如何添加接近交互性 - MRTK2

近距交互采用触摸和抓取形式。 触摸和抓取事件分别由 PokePointerSpherePointer 作为指针事件引发。

要侦听特定 GameObject 上的触摸和/或抓取输入事件,需要执行三个关键步骤。

  1. 确保相关指针已在主 MRTK 配置文件中注册。
  2. 确保所需的 GameObject 具有适当的抓取触摸脚本组件和 Unity Collider
  3. 在所需 GameObject 的附加脚本上实现输入处理程序接口,以侦听抓取触摸事件。

添加抓取交互

  1. 确保在 MRTK 指针配置文件中注册了 SpherePointer

    默认 MRTK 配置文件和默认 HoloLens 2 配置文件已包含 SpherePointer。 可以通过选择 MRTK 配置文件并导航到“输入”>“指针”>“指针选项”来确认将创建 SpherePointer。 应将默认 GrabPointer prefab (Assets/MRTK/SDK/Features/UX/Prefabs/Pointers) 与控制器类型起列出。 只要自定义预制件实现 SpherePointer 类,就可以使用该预制件。

    Grab Pointer Profile Example

    默认抓取指针会在抓取点周围的锥形区域内查询附近的对象,以匹配默认的 Hololens 2 接口。

    Conical Grab Pointer

  2. 在应该可抓取的 GameObject 上,添加一个 NearInteractionGrabbable 以及一个碰撞体。

    确保 GameObject 的层位于可抓取的层上。 默认情况下,除“空间感知”和“忽略光线投射”之外的所有层都是可抓取的。 通过检查 GrabPointer 预制件中的抓取层蒙板来查看哪些层是可抓取的。

  3. 在 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) prefab 列在控制器类型的“明确手”中。 只要自定义预制件实现 PokePointer 类,就可以使用该预制件。

Poke Pointer Profile Example

3D GameObject

可以通过两种不同的方式向 3D GameObject 添加触摸交互,具体取决于你的 3D 对象是否应该只有一个可触摸平面,或者它是否应该基于整个碰撞体可触摸。 第一种方法通常用于具有 BoxCollider 的对象,在这种情况下,你希望碰撞体只有单个面对触摸事件做出反应。 另一种方法适用的对象需要是从任何方向都可触摸的对象,具体取决于其碰撞体的情况。

单面触摸

这对于只有单面需要可触摸的情况很有用。 此选项假设游戏对象具有 BoxCollider。 可以将其与非 BoxCollider 对象一起使用,在这种情况下,需要手动设置“边界”和“本地中心”属性以配置可触摸平面(即边界应设置为非零值)。

  1. 在应该可触摸的 GameObject 上,添加一个 BoxCollider 和一个 [NearInteractionTouchable] (xref:Microsoft.MixedReality.Toolkit.Input.NearInteractionTouchable) 组件。

    1. 如果在下面的组件脚本中使用 [IMixedRealityTouchHandler] (xref:Microsoft.MixedReality.Toolkit.Input.IMixedRealityTouchHandler) 接口,请将“要接收的事件”设置为“触摸”。

    2. 单击“修复边界”和“修复中心”

    NearInteractionTouchable Setup

  2. 在该对象或其任一上级上,添加一个脚本组件,用于实现IMixedRealityTouchHandler 接口。 具有 [NearInteractionTouchable] (xref:Microsoft.MixedReality.Toolkit.Input.NearInteractionTouchable) 的对象的任一上级也将能够接收指针事件。

注意

在选择了 NearInteractionTouchable GameObject 的编辑器场景视图中,请注意白色边框正方形和箭头。 箭头指向可触摸的“前面”。 碰撞体只能从该方向触摸。 要使碰撞体从各个方向均可触摸,请参阅有关任意碰撞体触摸的部分。 NearInteractionTouchable Gizmos

任意碰撞体触摸

这适用于游戏对象需要整个碰撞体面都可触摸的情况。 例如,这可用于具有 SphereCollider 的对象的触摸交互,在这种情况下,整个碰撞体都需要可触摸。

  1. 在应该可触摸的 GameObject 上,添加一个碰撞体和一个 [NearInteractionTouchableVolume] (xref:Microsoft.MixedReality.Toolkit.Input.NearInteractionTouchableVolume) 组件。

    1. 如果在下面的组件脚本中使用 [IMixedRealityTouchHandler] (xref:Microsoft.MixedReality.Toolkit.Input.IMixedRealityTouchHandler) 接口,请将“要接收的事件”设置为“触摸”。
  2. 在该对象或其任一上级上,添加一个脚本组件,用于实现IMixedRealityTouchHandler 接口。 具有 [NearInteractionTouchable] (xref:Microsoft.MixedReality.Toolkit.Input.NearInteractionTouchable) 的对象的任一上级也将能够接收指针事件。

Unity UI

  1. 在场景中添加 UnityUI 画布/确保场景中有该画布。

  2. 在应可触摸的 GameObject 上,添加一个 NearInteractionTouchableUnityUI 组件。

    1. 如果在下面的组件脚本中使用 IMixedRealityTouchHandler 接口,请将“要接收的事件”设置为“触摸”。
  3. 在该对象或其任一上级上,添加一个脚本组件,用于实现 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

请参阅