You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hololens 2 MRTK3手部交互:如何测量捏合点距离并可视化?

问题描述

我正在开发基于Unity、使用MRTK3的Hololens 2项目,需实现以下功能:

  • 在手部交互中测量两个捏合点的距离
  • 通过Line Renderer绘制两点连线
  • 使用TextMeshPro显示距离数值

尝试使用MRTK2的IMixedRealityHandJointHandler接口与MixedRealityPose类型时,出现“找不到类型或命名空间名称MixedRealityPose”的错误,尝试的代码如下:

using Microsoft.MixedReality.Toolkit.Input;
using UnityEngine;

public class MeasurePinchDistance : MonoBehaviour, IMixedRealityHandJointHandler
{
    private Vector3 pinchPoint1;
    private Vector3 pinchPoint2;
    private bool isPinching = false;

    public void OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData)
    {
        if (eventData.Handedness == Handedness.Right)
        {
            var handPose = eventData.InputData[TrackedHandJoint.IndexTip];
            if (handPose.Position.y > 0.5f && !isPinching)
            {
                isPinching = true;
                pinchPoint1 = handPose.Position;
            }
            else if (handPose.Position.y <= 0.5f && isPinching)
            {
                isPinching = false;
                pinchPoint2 = handPose.Position;
                Debug.Log("Distance between pinch points: " + Vector3.Distance(pinchPoint1, pinchPoint2));
            }
        }
    }
}
适配MRTK3的修改方案

MRTK3中移除了MixedRealityPose类型,改用HandJointPose,同时手部交互的API有部分调整。以下是适配后的完整实现,包含捏合检测、距离计算、连线绘制和数值显示:

核心修改点

  • 将MixedRealityPose替换为MRTK3的HandJointPose类型
  • 调整OnHandJointsUpdated方法的参数类型
  • 使用拇指尖与食指尖的距离判断捏合状态(更符合实际交互逻辑)
  • 集成Line Renderer和TextMeshPro实现可视化反馈

完整代码

using Microsoft.MixedReality.Toolkit.Input;
using UnityEngine;
using TMPro;
using System.Collections.Generic;

public class MeasurePinchDistance : MonoBehaviour, IMixedRealityHandJointHandler
{
    [Header("Visual Components")]
    public LineRenderer lineRenderer;
    public TextMeshPro distanceText;

    [Header("Pinch Settings")]
    [Tooltip("阈值:拇指与食指尖的距离小于此值时判定为捏合")]
    public float pinchThreshold = 0.02f;

    private Vector3 pinchStartPoint;
    private bool isMeasuring = false;
    private float currentDistance = 0f;

    void Start()
    {
        // 初始化Line Renderer
        if (lineRenderer != null)
        {
            lineRenderer.positionCount = 2;
            lineRenderer.enabled = false;
        }

        // 初始化Text
        if (distanceText != null)
        {
            distanceText.enabled = false;
        }
    }

    public void OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, HandJointPose>> eventData)
    {
        // 只处理右手
        if (eventData.Handedness != Handedness.Right) return;

        // 获取拇指尖和食指尖的关节数据
        if (eventData.InputData.TryGetValue(TrackedHandJoint.ThumbTip, out HandJointPose thumbPose) &&
            eventData.InputData.TryGetValue(TrackedHandJoint.IndexTip, out HandJointPose indexPose))
        {
            float tipDistance = Vector3.Distance(thumbPose.Position, indexPose.Position);
            bool isPinching = tipDistance < pinchThreshold;

            // 开始测量:第一次捏合时记录起点
            if (isPinching && !isMeasuring)
            {
                isMeasuring = true;
                pinchStartPoint = indexPose.Position;
                UpdateVisuals();
            }
            // 结束测量:松开捏合时记录终点并计算距离
            else if (!isPinching && isMeasuring)
            {
                isMeasuring = false;
                currentDistance = Vector3.Distance(pinchStartPoint, indexPose.Position);
                UpdateVisuals();
            }
            // 测量中:实时更新终点和距离
            else if (isMeasuring)
            {
                currentDistance = Vector3.Distance(pinchStartPoint, indexPose.Position);
                UpdateVisuals(indexPose.Position);
            }
        }
    }

    private void UpdateVisuals(Vector3 endPoint = default)
    {
        if (lineRenderer != null)
        {
            lineRenderer.enabled = isMeasuring;
            if (isMeasuring)
            {
                lineRenderer.SetPosition(0, pinchStartPoint);
                lineRenderer.SetPosition(1, endPoint != default ? endPoint : pinchStartPoint);
            }
        }

        if (distanceText != null)
        {
            distanceText.enabled = isMeasuring || currentDistance > 0;
            if (isMeasuring)
            {
                distanceText.text = $"距离: {currentDistance:F2}m";
                // 将文本跟随终点位置
                distanceText.transform.position = endPoint != default ? endPoint : pinchStartPoint;
            }
            else
            {
                distanceText.text = $"测量完成: {currentDistance:F2}m";
            }
        }
    }

    // 接口必需的空实现(兼容旧版签名)
    public void OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData) { }
}

使用说明

  1. 在Unity场景中创建一个空物体,挂载此脚本
  2. 给空物体添加Line Renderer组件,设置好材质和线宽
  3. 创建一个TextMeshPro对象(推荐使用World Space模式),拖入脚本的distanceText字段
  4. 在MRTK3的输入配置中确保手部跟踪已启用
  5. 调整pinchThreshold值适配你的交互需求(单位:米)

内容的提问来源于stack exchange,提问作者kprabhasreddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:13:19