LeapMotion直接提取手坐标并转换至Unity坐标系,解决坐标不对应问题

项目场景:

最近在做LeapMotion+VR的实验项目,需要通过LeapMotion识别手势。为此首先我希望能够提取出LeapHand的坐标,但是由于LeapMotion有自己的坐标系,与unity的世界坐标系是不同的,所以需要对得到的坐标进行转换。


问题描述:

LeapMotion直接提取手坐标与在Unity Space中显示的手模型坐标不对应问题。转换LeapMotion坐标至Unity坐标系。比如hand.PalmPosition


原因分析:

意外很艰难的解决过程

  1. 网上找到的内容都是直接调用Vector.ToVector3(),转换坐标到unity坐标,但是看源码这个函数,只是把xyz原样赋值给新的UnityEngine.Vector3,没有做任何变换。所以坐标显示在unity中是对不上的。hand.PalmPosition.ToVector3()
  2. 收集到的leap坐标系设置,但是帮助不大。github上很多都是对position直接乘除个数字,不知道怎么来的。而且对应的都是leapmotion老版本,新版本好像没有LeapProvider这个类?而官网API明显不全。
    LeapMotion直接提取手坐标并转换至Unity坐标系,解决坐标不对应问题
  3. 一筹莫展时,发现unity中有个DebugHand脚本,功能是Debug.DrawLines画出手线条,这个脚本拖拽到HandModelManager中手模型上,发现和手模型位置显示一致,进去看源码,然而也没有特殊操作,直接复制还是不行。
protected void DrawDebugLines() {
      Hand hand = GetLeapHand();
      Debug.DrawLine(hand.Arm.ElbowPosition.ToVector3(), hand.Arm.WristPosition.ToVector3(), Color.red); //Arm
      Debug.DrawLine(hand.WristPosition.ToVector3(), hand.PalmPosition.ToVector3(), Color.white); //Wrist to palm line
      Debug.Log(hand.PalmPosition.ToVector3());
      Debug.DrawLine(hand.PalmPosition.ToVector3(), (hand.PalmPosition + hand.PalmNormal * hand.PalmWidth / 2).ToVector3(), Color.black); //Hand Normal

      if (VisualizeBasis) {
        DrawBasis(hand.PalmPosition, hand.Basis, hand.PalmWidth / 4); //Hand basis
        DrawBasis(hand.Arm.ElbowPosition, hand.Arm.Basis, .01f); //Arm basis
      }

      for (int f = 0; f < 5; f++) { //Fingers
        Finger finger = hand.Fingers[f];
        for (int i = 0; i < 4; ++i) {
          Bone bone = finger.Bone((Bone.BoneType)i);
          Debug.DrawLine(bone.PrevJoint.ToVector3(), bone.PrevJoint.ToVector3() + bone.Direction.ToVector3() * bone.Length, colors[i]);
          if (VisualizeBasis)
            DrawBasis(bone.PrevJoint, bone.Basis, .01f);
        }
      }
    }
  1. 按手的绘制顺序向上层类和函数去找源码看。发现是在LeapServiceProvider中对controller.Frame做了变换。使用它的变换代码dest.CopyFrom(source).Transform(transform.GetLeapMatrix());
    GetLeapMatrix()函数和Transform()函数都在LeapUnityExtensions脚本文件中。(之前看过,但不会用),这样就解决了。
  protected virtual void transformFrame(Frame source, Frame dest) {
    dest.CopyFrom(source).Transform(transform.GetLeapMatrix());
  }

解决方案:

Frame source = controller.Frame();
Frame dest = new Frame();
dest.CopyFrom(source).Transform(transform.GetLeapMatrix());
dest.Hands[0].PalmPosition.ToVector3();

挂载在手模型上(或者任意位置?),功能是对Frame做变换(用LeapMotion自带API做变换),这样在获取的就是leap在unity中的坐标了。(不知道是不是这么回事,感觉理论说不清楚。。)

上一篇:Hands Off for Mac如何卸载?完全卸载Hands Off的方法


下一篇:《Hands-On Machine Learning with Scikit_Learn &TensorFlow》chapter1_GDP案例代码