控制器、指针和焦点 - MRTK2
控制器、指针和焦点是较高级别的概念,它们构建在核心输入系统所建立的基础之上。 它们共同提供了与场景中对象交互的大部分机制。
Controllers
控制器是物理控制器(6 自由度、关节手等)的表示形式。 它们由设备管理器创建,负责与相应的底层系统通信,并将该数据转换为 MRTK 造型的数据和事件。
例如,在 Windows Mixed Reality 平台上,WindowsMixedRealityArticulatedHand
是一个控制器,它负责与底层 Windows 手部跟踪 API 交互以获取有关手部关节、姿势和其他属性的信息。 它负责将此数据转换为相关的 MRTK 事件(例如,通过调用 RaisePoseInputChanged 或 RaiseHandJointsUpdated 来这样做),并更新自身的内部状态,以便对 TryGetJointPose
的查询返回正确的数据。
一般情况下,控制器的生命周期包括:
在检测到新源时(例如,设备管理器检测到手部并开始对其进行跟踪),设备管理器会创建控制器。
在控制器的 Update() 循环中,它将调用其底层 API 系统。
在同一更新循环中,它通过直接调用核心输入系统本身来引发输入事件更改(例如,引发 HandMeshUpdated 或 HandJointsUpdated)。
指针和焦点
指针用于与游戏对象交互。 本部分介绍如何创建和更新指针,以及它们如何确定聚焦的对象。 此外还会介绍存在的不同类型的指针,以及在哪些情况下它们处于活动状态。
指针类别
指针通常属于以下类别之一:
远指针
这些类型的指针用于与远离用户的对象进行交互(“远离”简单地定义为“不近”)。 这些类型的指针通常会投射出可以深入世界的线条,使用户能够对不在他们身边的对象进行交互和操作。
近指针
这些类型的指针用于与距离用户足够近的对象进行交互,以便可以抓取、触摸和操作对象。 一般情况下,这些类型的指针通过查找附近区域中的对象来与对象交互(在短距离处进行光线投射、进行球体投射、查找附近的对象,或枚举被视为可抓取/可触摸对象的对象列表)。
瞬移指针
这些类型的指针插入到瞬移系统,以处理将用户移到指针所指位置的操作。
指针调解
由于单个控制器可以有多个指针(例如,关节手可以同时具有近距和远距交互指针),因此有一个组件负责调解哪个指针应处于活动状态。
例如,当用户的手部接近某个可按按钮时,ShellHandRayPointer
应停止显示,而 PokePointer
应该参与进来。
这由 DefaultPointerMediator
处理,它负责根据所有指针的状态确定哪些指针处于活动状态。 此措施的关键之处在于,当近指针靠近对象时禁用远指针(请参阅 DefaultPointerMediator
)。
通过更改指针配置文件中的 PointerMediator
属性,可以提供指针调解器的替代实现。
如何禁用指针
由于指针调解器每帧都会运行,因此它最终会控制所有指针的活动/非活动状态。 因此,如果在代码中设置指针的 IsInteractionEnabled 属性,每帧的指针调解器会覆盖此属性值。 你可以改为自行指定 PointerBehavior
来控制指针的打开和关闭。 请注意,仅在 MRTK 中使用默认的 FocusProvider
和 DefaultPointerMediator
时才能执行此操作。
示例:在 MRTK 中禁用手部射线
以下代码将关闭 MRTK 中的手部射线:
// Turn off all hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);
// Turn off hand rays for the right hand only
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);
以下代码将手部射线恢复为它们在 MRTK 中的默认行为:
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.Default);
以下代码将强制打开手部射线,无论是否靠近可抓取对象:
// Turn off all hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOn);
有关更多示例,请参阅 PointerUtils
和 TurnPointersOnOff
。
FocusProvider
FocusProvider
是负责迭代所有指针的列表并找出每个指针的聚焦对象的主类。
在每个 Update()
调用中,此类将:
更新所有的指针,更新方式是投射光线,并按照指针本身的配置执行命中检测(例如,球体指针可能指定 SphereOverlap raycastMode,因此 FocusProvider 将执行基于球体的碰撞)
基于指针更新聚焦对象(即,如果某个对象获得焦点,则也会触发该对象的事件;如果某个对象失去焦点,则会触发失去焦点的操作,等等)。
指针配置和生命周期
可以在输入系统配置文件的 Pointers 节中配置指针。
指针的生命周期通常如下:
设备管理器检测某个控制器是否存在。 然后,此设备管理器通过调用
RequestPointers
来创建与该控制器关联的指针集。FocusProvider 会在其 Update() 循环中迭代所有有效指针,并执行关联的光线投射或命中检测逻辑。 这用于确定每个特定指针聚焦的对象。
- 由于可以同时激活多个输入源(例如,两只手都处于活动状态),因此也有可能多个对象同时具有焦点。
设备管理器在发现控制器源丢失时,会摧毁与丢失的控制器关联的指针。