手部菜单 - MRTK2

Hand Menu UX Example

通过手形菜单,用户可以快速为常用功能获取手形连接的 UI。 为防止在与其他对象交互时错误激活,手动菜单提供了“要求手平伸”和“使用凝视激活”等选项。 建议使用这些选项以防止意外激活。

手动菜单示例

HandMenuExamples.unity 场景位于 MRTK/Examples/Demos/HandTracking/Scenes 文件夹下。 在该场景运行时,场景只会激活当前选择的菜单类型。
HandMenu_ExampleScene

可以在 MRTK/Examples/Common/Prefabs 文件夹下找到这些手动菜单预制件。

HandMenu_Small_HideOnHandDrop 和 HandMenu_Medium_HideOnHandDrop

这两个示例简单地激活和停用 MenuContent 对象,以在 OnFirstHandDetected() 和 OnLastHandLost() 事件上显示和隐藏菜单。
HandMenu_ExampleScene 1
HandMenu_ExampleScene 2

HandMenu_Large_WorldLock_On_GrabAndPull

对于需要较长交互时间的更复杂菜单,建议对菜单进行世界锁定。 在此示例中,除了在发生 OnFirstHandDetected() 和 OnLastHandLost() 事件时激活和停用 MenuContent 之外,用户还可以抓取并拉动菜单以进行世界锁定
HandMenu_ExampleScene 3

背板的 ManipulationHandler 使其变得可抓取并且可移动。 “在操作已启动时”事件,停用 SolverHandler.UpdateSolvers 以在世界锁定菜单。 此外,它还显示关闭按钮,用户可以使用该按钮在任务完成时关闭菜单。 “在操作结束时”事件,该事件调用 HandConstraintPalmUp.StartWorldLockReattachCheckCoroutine,这样用户通过抬手并注视手掌便可在手掌中显示菜单。
HandMenu_ExampleScene 4

关闭按钮将重新激活 SolverHandler.UpdateSolvers 并隐藏 MenuContent。
HandMenu_ExampleScene 5

HandMenu_Large_AutoWorldLock_On_HandDrop

此示例类似于 HandMenu_Large_WorldLock_On_GrabAndPull。 唯一的区别是菜单会在手放下时自动世界锁定。 要处理此行为,请不要在发生 OnLastHandLost() 事件时隐藏 MenuContent。 抓取并拉动的行为与 HandMenu_Large_WorldLock_On_GrabAndPull 示例相同。

脚本

HandConstraint 行为提供了一个求解器,该求解器将跟踪对象约束在确保可显示手部约束内容(如手部 UI、菜单等)的区域内。 安全区域是指不会与手部相交的区域。 还包含了一个名为 HandConstraintPalmUpHandConstraint 派生类,用于演示手掌朝向用户时激活求解器的常见行为。

有关更多文档,请参阅每个 HandConstraint 属性可用的工具提示。 下面更详细地定义了一些属性。

HandMenu_ExampleScene Palm up
  • 安全区域:安全区域指定了手掌上限制内容的区域。 建议内容放在尺侧,避免与手重叠,提高交互质量。 安全区域的计算方法是将手部方向投影到与相机视野正交的平面中,并针对手部周围的边界框进行光线投射。 安全区域规定为与 IMixedRealityHand 一起使用,但也可与其他控制器类型一起使用。 建议探索每个安全区域在不同控制器类型上的含义。

  • 跟随手直到面对相机:激活此设置后,求解器将跟随手旋转,直到菜单与用户凝视目光充分对齐,此时手朝向相机。 通过将 HandConstraintSolver 中的 SolverRotationBehavior 从 LookAtTrackedObject 更改为 LookAtMainCamera 来实现此行为,因为求解器的 GazeAlignment 角度会发生变化。

HandMenu Safe Zones
  • 激活事件:目前 HandConstraint 触发四个激活事件。 这些事件可以在许多不同的组合中使用以创建独特的 HandConstraint 行为,请参阅 MRTK/Examples/Demos/HandTracking/Scenes/ 下面的 HandBasedMenuExample 场景以获取这些行为的示例。

    • OnHandActivate:当手形满足 IsHandActive 方法时触发
    • OnHandDeactivate:当不再满足 IsHandActive 时触发
    • OnFirstHandDetected:当手部跟踪状态从视野中没有手形变为视野中出现第一个手形时触发
    • OnLastHandLost:当手部跟踪状态从视野中至少出现一个手形变为视野中没有手形时触发
  • 求解器激活/停用逻辑:目前,建议使用 SolverHandler 的 UpdateSolver 值来激活和停用 HandConstraintPalmUp 逻辑,而不是通过禁用/启用对象来实现。 在示例场景中,通过在附加菜单的 ManipulationHandler“OnManipulationStarted/Ended”事件后触发的基于编辑器的挂钩即可看到此行为。

    • 停止手部约束逻辑:尝试将手部约束对象设置为停止(或不运行)激活/停用逻辑时,请将 UpdateSolver 设置为 False,而不是禁用 HandConstraintPalmUp。
      • 如果想启用基于凝视(甚至基于非凝视)的重新附加逻辑,随后调用 HandConstraintPalmUp.StartWorldLockReattachCheckCoroutine() 函数。 此调用将触发一个协同例程,然后继续检查“IsValidController”条件是否满足,一旦满足(或对象被禁用),就会将 UpdateSolver 设置为 True。
    • 启动手部约束逻辑:尝试将手部约束对象设置为再次开始跟随你的手部时(根据是否满足激活条件),将 SolverHandler 的 UpdateSolver 设置为 true
  • 重新附加逻辑:目前,HandConstraintPalmUp 能够自动将目标对象重新附加到跟踪点,无论 SolverHandler 的 UpdateSolver 是否为 True。 要处理此行为,请在目标对象经世界锁定后调用 HandConstraintPalmUp 的 StartWorldLockReattachCheckCoroutine() 函数(在这种情况下,实际上是将 SolverHandler 的 UpdateSolver 设置为 False)。

另请参阅