本节摘要:渲染、跟踪、空间重建解决了"看见可信的虚拟",但要"操作虚拟"还需要输入识别。本节讲 XR 三大输入模态:手势(21 节点骨骼模型)、眼动(注视点估计)、语音(前端信号处理)。每一模态讲原理+工程挑战+一段最小代码。最后给出一个"多模态融合"的设计框架——Vision Pro 的"看+捏"组合是该框架的标杆。
阅读完本节,你应当能够:
XR 交互和传统 GUI 交互最大的差异是"输入模态"——传统 GUI 用"鼠标+键盘"二维输入,XR 用"手势+眼动+语音+手柄"三维输入。每一模态都解决一种"原语":
把这三原语组合起来,可以覆盖几乎所有 XR 交互场景。
XR 手势识别的目标是"实时估计 21 个手部关节点的 6DoF 位置"。这 21 个节点是:手腕 1 个、手掌 4 个(每指根 1 个)、每根手指 4 个关节 × 5 根手指。
工程实现:
手势识别的 3 个工程难点:
上一章讲过,眼动追踪用红外照明+红外摄像头拍瞳孔+角膜反射斑,由 AI 模型估计注视点。
工程实现分三步:
精度与延迟:
眼动有两个关键应用:
XR 语音识别和手机/智能音箱的差异是"近场+强噪声"。XR 头显离嘴 5-15cm,距离近;周围又有头显电机噪声+环境噪声。前端处理要做:
识别引擎方面,Vision Pro 用设备内置 ASR(on-device);Quest 3 默认接 Meta AI 云端;HoloLens 2 接 Azure 认知服务。
下面这段代码在 Quest 3 上订阅"手势捏合 + 眼动注视 + 语音指令"三种输入,让一个虚拟按钮同时支持三种触发方式:
using UnityEngine.XR; public class MultiModalButton : MonoBehaviour { [SerializeField] private Transform gazeTarget; private float _gazeDuration = 0f; void Update() { // 1. 眼动注视检测 var eye = InputDevices.GetDeviceAtXRNode(XRNode.EyeGaze); if (eye.TryGetFeatureValue(EyeGazeUsages.gazePosition, out Vector3 gazePos)) { // 计算注视点在场景中 var ray = new Ray(Camera.main.transform.position, (gazePos - Camera.main.transform.position).normalized); if (Physics.Raycast(ray, out var hit, 10f) && hit.transform == transform) _gazeDuration += Time.deltaTime; else _gazeDuration = 0; } // 2. 手势捏合(Vision Pro / Quest 3 都有) var hand = InputDevices.GetDeviceAtXRNode(XRNode.RightHand); if (hand.TryGetFeatureValue(CommonUsages.gripButton, out bool grip) && grip && _gazeDuration > 0.5f) { Debug.Log("注视 + 捏合 → 触发按钮"); _gazeDuration = 0; } // 3. 语音指令(需要 ASR 服务,简化示例) // if (SpeechRecognizer.IsActive && SpeechRecognizer.Text == "click") // Trigger(); } }
跑起来后:用眼动注视虚拟按钮 0.5 秒 + 捏合手势 → 触发;或者注视 + 语音 "click" → 触发。这就是 Vision Pro 的"看+捏"组合的核心范式。
下一章我们从算法层进入工程层——Unity/Unreal/OpenXR/SDK 选型与一条 XR 项目的完整流水线。