交互器体系结构 - MRTK3
MRTK 建立在 Unity 的 XR 交互工具包提供的交互器集的基础之上。 与 XRI 默认提供的集相比,关节手跟踪、凝视和捏合等混合现实功能需要更精细的交互器。 MRTK 定义了新的交互器接口(通常按输入模态分类)以及相应的实现。
摘要和回顾
对于不熟悉 XRI 的开发人员而言,建议先查看 Unity 的 XRI 体系结构文档。 MRTK 交互器是现有 XRI 交互器的子类,或 XRI 交互器接口的实现。 请参阅有关 Unity 交互器体系结构的文档,它同样适用于 MRTK。
XRI 的好公民
自定义 MRTK 交互器相对于默认 XRI 交互器接口而言行为良好;从 XRI 系统的角度看,它们与“普通”交互器没有差别。 反之亦然,在 MRTK 中生成高级可交互对象时,默认的 XRI 交互器仍可正常处理基本的悬停和选择动作。 与现有 XRI 项目完全兼容是 MRTK 所做努力的一部分。 如果你有一个 XRI 应用程序,MRTK 可交互对象和 UI 控件将与现有的“普通”XRI 设置配合工作。
输入模态的抽象
输入设备、执行交互的交互器及其生成的交互事件在 XRI 中全都保持体系结构隔离性。 这种隔离性对于 MRTK3 中的输入抽象策略至关重要,使我们能够编写出在所有上下文中均可正常运行的跨平台和跨设备交互。
从 MRTK v2 开始,为特定于输入类型或设备的交互编码有了一种共同的本能。 许多开发人员习惯于编写专门针对近距抓取、远距投射或某种其他特定输入类型做出反应的交互。
虽然 MRTK3 仍然允许对单个输入模式进行消歧和检测,但对特定单个输入类型的交互进行硬编码会人为地限制并降低交互的灵活性。 有关详细信息,请参阅可交互对象体系结构文档,但交互器的关键在于它们通常不必与输入设备进行 1:1 映射。
AttachTransform 和反转控制
MRTK v2 在“移动逻辑”中作为 ObjectManipulator
、Slider
等的一部分发挥的大部分作用现在由交互器本身负责。 交互器现在会控制其 attachTransform,以定义特定操控类型的行为方式。 用户不再需要针对因输入模态而异的可交互对象编写复杂的交互逻辑;取而代之的是,统一的操控逻辑可以侦听 attachTransform
的姿势,而不管输入模态或驱动它的设备是什么。
例如,GrabInteractor
的 attachTransform
定位在手部/控制器上的抓取点处。 XRRayInteractor
的 attachTransform
定位在光线一端的点击点处。 CanvasProxyInteractor
的 attachTransform
定位在单击鼠标的任何位置。 对于所有这些不同的交互器,可交互对象无需考虑交互器的类型即可正确地响应操控。
可交互对象查询 attachTransform
并可以将每个 attachTransform
视为相同,无论交互器类型是什么。
此方法对于与现有 XRI 交互器保持兼容,以及将来证明尚未开发的输入模态的交互至关重要。 如果引入了新的输入方法,而新的交互器能够生成有效且行为正常的 attachTransform
,则无需更改现有的可交互对象。
因此,从哲学上说,attachTransform
这是交互逻辑。 对于任何自定义交互,请始终优先使用新的 attachTransform
逻辑编写新的交互器,而不是重新编写或扩展可交互对象,以针对新交互进行自定义。 这样,所有现有的可交互对象(而不仅仅是重新编写或扩展的那些可交互对象)都可以享受新交互的好处。
XRControllers 和输入绑定
大多数交互器不会直接绑定到输入操作。 大多数交互器派生自 XRBaseControllerInteractor
,这需要在层次结构中的交互器上面提供一个 XRController
。 XRController
绑定到输入操作,然后将相关操作(选择等)向下传播到所有附加的交互器。
尽管如此,某些交互器仍可能需要特殊的输入绑定,或 XRController
不提供的其他输入。 在这种情况下,交互器可以选择直接绑定到其自身的独特输入操作,甚至为交互逻辑使用其他非输入系统源。 XRI 基类优先侦听 XRController
的绑定,但可以重写这些行为以使用外部或替代的输入源。
接口
XRI 定义基本的 IXRInteractor
、IXRHoverInteractor
、IXRSelectInteractor
和 IXRActivateInteractor
。 MRTK 为交互器定义其他接口。 其中一些接口公开有关 MRTK 特定交互的附加信息,还有一些则仅用于分类和标识。 这些接口全都位于“核心”包中,而实现则位于其他包中(包括“输入”)。
重要
虽然这些接口在你需要筛选特定类型的交互时很有帮助,但建议不要对交互进行硬编码来专门侦听这些接口。 在任何情况下,请始终优先使用泛型 XRI isSelected 和 isHovered,而不是任何特定于交互的接口。
除非绝对必要,否则不要在可交互对象中引用这些接口的具体 MRTK 实现。 在所有情况下,最好引用接口。 显式引用具体类型会将可交互对象限制为仅处理当前的现有类型。 如果仅引用接口,可以确保与将来的、将现有实现子类化的实现保持兼容。
IVariableSelectInteractor
实现此接口的交互器可以向可交互对象发出变量(即模拟)选择。 可以使用 SelectProgress
属性查询变量选择量。 实现此接口的 MRTK 交互器包括 MRTKRayInteractor
和 GazePinchInteractor
。 基础可交互对象(默认的 XRI 可交互对象,以及 MRTKBaseInteractable
)不受变量选择量的影响;但是,StatefulInteractable
会侦听此值,并根据所有参与变量和非变量交互器的 max()
计算其 Selectedness
。
IGazeInteractor
实现此接口的交互器代表用户的被动视线,与任何操控或意图分离。 MRTK 实现是 FuzzyGazeInteractor
,它继承自 XRI XRRayInteractor
,并添加了模糊锥体投射逻辑。 当 IGazeInteractor
处于悬停状态时,XRBaseInteractable
将标记 IsGazeHovered
。
IGrabInteractor
实现此接口的交互器代表物理近场抓取交互。 attachTransform
定义为抓取点。 MRTK 实现是 GrabInteractor
,它子类化 XRI 的 XRDirectInteractor
。
IPokeInteractor
实现此接口的交互器代表戳击交互。 请注意,这不一定表示手指戳击! 任意交互器可以实现此接口并提供来自非手指源的戳击交互。 在非常适合检查交互器接口的少数场合之一中,PressableButton
之类的可交互对象会专门侦听 IPokeInteractor
以驱动立体按压。 任何实现 IPokeInteractor
的交互器都会在按钮上产生 3D 按压。
IPokeInteractor
公开 PokeRadius
属性,该属性定义戳击对象的特征。 戳击的中心被认为在 attachTransform
上,并由 PokeRadius
从 attachTransform
向外延伸。 PressableButton
之类的可交互对象按此半径偏移其 3D 推按距离,在基于手指进行按压的情况下,这可以由用户的物理手指粗细度驱动。
此接口的 MRTK 实现是 PokeInteractor
。 在模板项目中,我们还提供了非手指驱动的 IPokeInteractor
的另一个示例;PenInteractor
提供基于虚拟 3D 触笔笔尖的戳击交互。
IRayInteractor
实现此接口的交互器代表基于光线的指向交互。 attachTransform
代表选择期间光线在目标对象表面上的点击位置。
此接口的 MRTK 实现是直接从 XRI XRRayInteractor
继承的 MRTKRayInteractor
。
注意
XRI XRRayInteractor
不实现此 MRTK 接口。
ISpeechInteractor
实现此接口的交互器代表语音驱动的交互。 MRTK 实现是 SpeechInteractor
。
MRTK SpeechInteractor
在内部使用 PhraseRecognitionSubsystem
并订阅来自 XRI XRInteractionManager
的可交互对象注册事件。 然而,可交互对象不需要关心哪个子系统正在执行语音处理;ISpeechInteractor
生成与任何其他交互器相同的 XRI 事件(选择等)。
IGazePinchInteractor
此接口只是 IVariableSelectInteractor
接口的专门化。 在隐含的意义上讲,实现此接口的交互器是变量选择交互器。 IGazePinchInteractor
明确代表间接针对的远程操控。 单独的基于视线的交互器将驱动交互目标,而操控通过手部或控制器进行。 attachTransform
的行为方式与 IRayInteractor
的 attachTransform
相同;启动选择时,它会贴靠至目标上的点击点。
当多个 IGazePinchInteractor
参与单个交互时,它们的 attachTransform
将会位移,位移长度为所有参与捏合点之间的中点与它们相隔的距离。 因此,可交互对象可以像对任何其他多手交互一样解释这些 attachTransform
,例如抓取交互或光线交互的 attachTransforms
。
MRTK 实现是 GazePinchInteractor
。
IHandedInteractor
某些交互器可以选择实现 IHandedInteractor
接口来显式指定它们与用户的特定手部相关联。 某些交互器与惯用手不关联,因此不实现此接口。 最典型的示例是 SpeechInteractor
或 FuzzyGazeInteractor
。
实现此接口的 MRTK 交互器是 HandJointInteractor
(由任意手关节驱动的泛型抽象 XRDirectInteractor
)、GazePinchInteractor
和 MRTKRayInteractor
。
可交互对象当前使用此接口来触发选择的特定特效,这些特效必须区分左手或右手。 最典型的示例是 UX 组件库中的脉冲特效。