如何添加近距交互性 — MRTK2
近距交互采用触摸和抓取形式。 触摸和抓取事件分别由 PokePointer 和 SpherePointer 作为指针事件引发。
要侦听特定 GameObject 上的触摸和/或抓取输入事件,需要执行三个关键步骤。
- 确保相关指针已在主 MRTK 配置文件中注册。
- 确保所需的 GameObject 具有适当的抓取或触摸脚本组件和
Unity Collider
。 - 在所需 GameObject 的附加脚本上实现输入处理程序接口,以侦听抓取或触摸事件。
添加抓取交互
确保在 MRTK 指针配置文件中注册了 SpherePointer。
默认 MRTK 配置文件和默认 HoloLens 2 配置文件已包含 SpherePointer。 可以通过选择 MRTK 配置文件并导航到“输入”>“指针”>“指针选项”来确认将创建 SpherePointer。 默认的
GrabPointer
预制件 (Assets/MRTK/SDK/Features/UX/Prefabs/Pointers) 应与关节手的控制器类型一起列出。 只要自定义预制件实现SpherePointer
类,就可以使用该预制件。默认抓取指针会在抓取点周围的锥形区域内查询附近的对象,以匹配默认的 HoloLens 2 界面。
在应该可抓取的 GameObject 上,添加一个
NearInteractionGrabbable
以及一个碰撞体。确保 GameObject 的层位于可抓取的层上。 默认情况下,除“空间感知”和“忽略光线投射”之外的所有层都是可抓取的。 通过检查 GrabPointer 预制件中的抓取层蒙板来查看哪些层是可抓取的。
在 GameObject 或其任一上级上,添加一个脚本组件,用于实现
IMixedRealityPointerHandler
接口。 具有NearInteractionGrabbable
的对象的任一上级也将能够接收指针事件。
抓取代码示例
下面的脚本会输出事件是触摸还是抓取。 在相关的 IMixedRealityPointerHandler 接口函数中,可以通过 MixedRealityPointerEventData
查看触发该事件的指针类型。 如果指针是 SpherePointer,则交互为抓取。
public class PrintPointerEvents : MonoBehaviour, IMixedRealityPointerHandler
{
public void OnPointerDown(MixedRealityPointerEventData eventData)
{
if (eventData.Pointer is SpherePointer)
{
Debug.Log($"Grab start from {eventData.Pointer.PointerName}");
}
if (eventData.Pointer is PokePointer)
{
Debug.Log($"Touch start from {eventData.Pointer.PointerName}");
}
}
public void OnPointerClicked(MixedRealityPointerEventData eventData) {}
public void OnPointerDragged(MixedRealityPointerEventData eventData) {}
public void OnPointerUp(MixedRealityPointerEventData eventData) {}
}
添加触摸交互
在 UnityUI 元素上添加触摸交互的过程与 vanilla 3D GameObject 不同。 可以跳到以下部分 (Unity UI),启用 Unity UI 组件。
但是,对于这两种类型的 UX 元素,请确保在 MRTK 指针配置文件中注册了 PokePointer。
默认 MRTK 配置文件和默认 HoloLens 2 配置文件已包含 PokePointer。 可以通过选择 MRTK 配置文件并导航到“输入”>“指针”>“指针选项”来确认将创建 PokePointer。 默认的 PokePointer
预制件 (Assets/MRTK/SDK/Features/UX/Prefabs/Pointers) 应与关节手的控制器类型一起列出。 只要自定义预制件实现 PokePointer
类,就可以使用该预制件。
3D GameObject
可以通过两种不同的方式向 3D GameObject 添加触摸交互,具体取决于你的 3D 对象是否应该只有一个可触摸平面,或者它是否应该基于整个碰撞体可触摸。 第一种方法通常用于具有 BoxCollider 的对象,在这种情况下,你希望碰撞体只有单个面对触摸事件做出反应。 另一种方法适用的对象需要是从任何方向都可触摸的对象,具体取决于其碰撞体的情况。
单面触摸
这对于只有单面需要可触摸的情况很有用。 此选项假设游戏对象具有 BoxCollider。 可以将其与非 BoxCollider 对象一起使用,在这种情况下,需要手动设置“边界”和“本地中心”属性以配置可触摸平面(即边界应设置为非零值)。
在应可触摸的 GameObject 上,添加 BoxCollider 和
NearInteractionTouchable
组件。如果在下面的组件脚本中使用
IMixedRealityTouchHandler
接口,请将“要接收的事件”设置为“触摸”。单击“修复边界”和“修复中心”
在该对象或其任一上级上,添加一个脚本组件,用于实现
IMixedRealityTouchHandler
接口。 具有NearInteractionTouchable
的对象的任一上级也将能够接收指针事件。
注意
在选择了 NearInteractionTouchable GameObject 的编辑器场景视图中,请注意白色边框正方形和箭头。 箭头指向可触摸的“前面”。 碰撞体只能从该方向触摸。 要使碰撞体从各个方向均可触摸,请参阅有关任意碰撞体触摸的部分。
任意碰撞体触摸
这适用于游戏对象需要整个碰撞体面都可触摸的情况。 例如,这可用于具有 SphereCollider 的对象的触摸交互,在这种情况下,整个碰撞体都需要可触摸。
在应可触摸的 GameObject 上,添加一个碰撞体和
NearInteractionTouchableVolume
组件。- 如果在下面的组件脚本中使用
IMixedRealityTouchHandler
接口,请将“要接收的事件”设置为“触摸”。
- 如果在下面的组件脚本中使用
在该对象或其任一上级上,添加一个脚本组件,用于实现
IMixedRealityTouchHandler
接口。 具有NearInteractionTouchable
的对象的任一上级也将能够接收指针事件。
Unity UI
在场景中添加 UnityUI 画布/确保场景中有该画布。
在应可触摸的 GameObject 上,添加一个
NearInteractionTouchableUnityUI
组件。- 如果在下面的组件脚本中使用
IMixedRealityTouchHandler
接口,请将“要接收的事件”设置为“触摸”。
- 如果在下面的组件脚本中使用
在该对象或其任一上级上,添加一个脚本组件,用于实现
IMixedRealityTouchHandler
接口。 具有NearInteractionTouchableUnityUI
的对象的任何上级也将能够接收指针事件。
重要
如果对象位于重叠的画布对象上,则对象的行为可能会与预期不一致。 为确保行为一致,切勿在场景中重叠画布对象。
重要
在 NearInteractionTouchable
脚本组件上,对于“要接收的事件”属性,有两个选项:“指针”和“触摸”。 如果在响应/处理输入事件的组件脚本中使用 IMixedRealityPointerHandler
接口,则将“要接收的事件”设置为“指针”,如果使用 IMixedRealityTouchHandler
接口,则将其设置为“触摸”。
触摸代码示例
下面的代码演示了一个 MonoBehaviour,它可以附加到具有 NearInteractionTouchable
变体组件并响应触摸输入事件的 GameObject。
public class TouchEventsExample : MonoBehaviour, IMixedRealityTouchHandler
{
public void OnTouchStarted(HandTrackingInputEventData eventData)
{
string ptrName = eventData.Pointer.PointerName;
Debug.Log($"Touch started from {ptrName}");
}
public void OnTouchCompleted(HandTrackingInputEventData eventData) {}
public void OnTouchUpdated(HandTrackingInputEventData eventData) { }
}
近距交互脚本示例
触摸事件
此示例创建一个立方体,使其可触摸,并在被触摸后更改颜色。
public static void MakeChangeColorOnTouch(GameObject target)
{
// Add and configure the touchable
var touchable = target.AddComponent<NearInteractionTouchableVolume>();
touchable.EventsToReceive = TouchableEventType.Pointer;
var material = target.GetComponent<Renderer>().material;
// Change color on pointer down and up
var pointerHandler = target.AddComponent<PointerHandler>();
pointerHandler.OnPointerDown.AddListener((e) => material.color = Color.green);
pointerHandler.OnPointerUp.AddListener((e) => material.color = Color.magenta);
}
抓取事件
下面的示例展示了如何使 GameObject 可拖动。 假设游戏对象上有一个碰撞体。
public static void MakeNearDraggable(GameObject target)
{
// Instantiate and add grabbable
target.AddComponent<NearInteractionGrabbable>();
// Add ability to drag by re-parenting to pointer object on pointer down
var pointerHandler = target.AddComponent<PointerHandler>();
pointerHandler.OnPointerDown.AddListener((e) =>
{
if (e.Pointer is SpherePointer)
{
target.transform.parent = ((SpherePointer)(e.Pointer)).transform;
}
});
pointerHandler.OnPointerUp.AddListener((e) =>
{
if (e.Pointer is SpherePointer)
{
target.transform.parent = null;
}
});
}
有用的 API
NearInteractionGrabbable
NearInteractionTouchable
NearInteractionTouchableUnityUI
NearInteractionTouchableVolume
IMixedRealityTouchHandler
IMixedRealityPointerHandler