Leap Motion 之 官方SDK代码分析

【仅用于个人复习使用,顺序较乱】
[Detection SDK]
Detection SDK
关于手势检测的官方SDK主要有这么几个脚本。
Detector是所有检测器的父类,主要保存的属性是IsActive。
DetectorLogicGate继承自Detector,主要提供多个Detector的逻辑操作,比如AND/OR/NAND/NOR。
PinchDetector是用来检测手是否握紧,继承自AbstractHoldDetector。而AbstractHoldDetector又继承自Detector。
FingerDirectionDetector用来检测某个手指是否沿某个指定的方向。
PalmDirectionDetector用来检测手掌是否沿某个指定的方向。
ExtendedFingerDetector用来检测手指是否展开。
ProximityDetector用来进行距离检测。

(LeapMotion脚本代码思路教程:http://blog.csdn.net/admintan/article/details/50319757)
(LeapMotion的名字空间:http://blog.csdn.net/eagle_pre21/article/details/51776830)
这两个链接还是值得一看的。
我们先对官方提供的一些demo和源码进行解析,从而了解LeapMotion提供了哪些主要的接口或者说我们应该怎么编写LeapMotion的代码。

五、SDK的使用 之 PinchDetector
我们这里将以LeapMotion Detection Module中的PinchDrawDemo场景为例。这是PinchDrawDemo的结构:
PinchDrawDemo
LMHeadMountedRig是CoreAsset中的一个预制件,应该对应的是HeadMounted模式。PinchDrawing是执行绘制功能的object。DirectionLight则是场景中的灯光。
我们对这个场景做简单的分析,来了解LM SDK的使用方法。

(1)PinchDraw.cs
这是PinchDrawing对象上的唯一的脚本,具体代码如下:

using UnityEngine;
using System.Collections.Generic;

namespace Leap.Unity.DetectionExamples {

  public class PinchDraw : MonoBehaviour {
	//使用Tooltip,当我们在Inspector面板中,把鼠标停留在PinchDetector变量上,就会显示这一句字符串。这里的PinchDetector是一个DetectionUtility文件夹中的自定义类,左右手模型上各有一个。
    [Tooltip("Each pinch detector can draw one line at a time.")]
    [SerializeField]
    //左右手的PinchDetector
    private PinchDetector[] _pinchDetectors;

    [SerializeField]
    //mesh的材质
    private Material _material;

    [SerializeField]
    //mesh的颜色
    private Color _drawColor = Color.white;

    [SerializeField]
    //SmoothedVector3的平滑系数
    private float _smoothingDelay = 0.01f;

    [SerializeField]
    //绘制的Ring的半径
    private float _drawRadius = 0.002f;

    [SerializeField]
    //绘制一个Ring所使用的顶点数
    private int _drawResolution = 8;

    [SerializeField]
    //判断是否需要添加Ring的最短距离
    private float _minSegmentLength = 0.005f;

    private DrawState[] _drawStates;

	//get/set,前面已经介绍了,这里不再多提
    public Color DrawColor {
      get {
        return _drawColor;
      }
      set {
        _drawColor = value;
      }
    }

    public float DrawRadius {
      get {
        return _drawRadius;
      }
      set {
        _drawRadius = value;
      }
    }

	//当Inspector面板中的值被修改时触发,用于保证值的合法性。类似的函数还有Reset(),当面板中脚本的值被reset时触发。
	//具体可参考:http://www.tuicool.com/articles/AfqY32
    void OnValidate() {
      _drawRadius = Mathf.Max(0, _drawRadius);
      _drawResolution = Mathf.Clamp(_drawResolution, 3, 24);
      _minSegmentLength = Mathf.Max(0, _minSegmentLength);
    }

    void Awake() {
      //至少要有一个PinchDetector被传入
      if (_pinchDetectors.Length == 0) {
        Debug.LogWarning("No pinch detectors were specified!  PinchDraw can not draw any lines without PinchDetectors.");
      }
    }

	//初始化DrawState数组,并加入新建DrawState对象。DrawState是这个脚本中定义的内部类,具体参见下方的注释。
    void Start() {
      _drawStates = new DrawState[_pinchDetectors.Length];
      for (int i = 0; i < _pinchDetectors.Length; i++) {
	    //把this作为参数传入DrawState,保存在parent变量中。
        _drawStates[i] = new DrawState(this);
      }
    }

    void Update() {
      for (int i = 0; i < _pinchDetectors.Length; i++) {
        var detector = _pinchDetectors[i];
        var drawState = _drawStates[i];

		//以下三个是PinchDetector类的方法,根据名字很容易猜到他们的功能。捏成拳头就开始画线,拳头松开就结束画线。画线调用的则是内部类DrawState封装的函数。
		//DidStartHold——手刚捏成拳头
        if (detector.DidStartHold) {
          drawState.BeginNewLine();
        }
		//DidRelease——手从拳头松开
        if (detector.DidRelease) {
          drawState.FinishLine();
        }
		//IsHolding——手保持拳头的姿势
        if (detector.IsHolding) {
          drawState.UpdateLine(detector.Position);
        }
      }
    }

	//期待已久的DrawState类~
    private class DrawState {
      private List<Vector3> _vertices = new List<Vector3>();
      private List<int> _tris = new List<int>();
      private List<Vector2> _uvs = new List<Vector2>();
      private List<Color> _colors = new List<Color>();

	  //外部类在初始化DrawState数组时(Start()函数),会将this(外部类对象的引用)传入新建的DrawState。
      private PinchDraw _parent;

      private int _rings = 0;

      private Vector3 _prevRing0 = Vector3.zero;
      private Vector3 _prevRing1 = Vector3.zero;

      private Vector3 _prevNormal0 = Vector3.zero;

      private Mesh _mesh;
      //SmoothedVector3是LM CoreAsset中Algorithm文件夹里的自定义类,大致就是让Vector3的值在改变时更平滑。
      private SmoothedVector3 _smoothedPosition;

      public DrawState(PinchDraw parent) {
        _parent = parent;
		//初始化SmoothedVector3对象
        _smoothedPosition = new SmoothedVector3();
        _smoothedPosition.delay = parent._smoothingDelay;
        _smoothedPosition.reset = true;
      }

	  //开始画线,为后面的Update做一些初始化的准备工作
      public GameObject BeginNewLine() {
        _rings = 0;
        _vertices.Clear();
        _tris.Clear();
        _uvs.Clear();
        _colors.Clear();

        _smoothedPosition.reset = true;

		//每次BeginNewLine会新建一个mesh
        _mesh = new Mesh();
        _mesh.name = "Line Mesh";
        _mesh.MarkDynamic();//标记为动态,这样mesh就会使用动态的buffer,在渲染时的性能更高。

		//用脚本动态添加GameObject
        GameObject lineObj = new GameObject("Line Object");
        //初始化transform
        lineObj.transform.position = Vector3.zero;
        lineObj.transform.rotation = Quaternion.identity;
        lineObj.transform.localScale = Vector3.one;
        //添加MeshFilter以及材质
        lineObj.AddComponent<MeshFilter>().mesh = _mesh;
        lineObj.AddComponent<MeshRenderer>().sharedMaterial = _parent._material;

        return lineObj;
      }

      public void UpdateLine(Vector3 position) {
        //更新SmoothedPosition,这里传入的position是PinchDetector.position。
        _smoothedPosition.Update(position, Time.deltaTime);

        bool shouldAdd = false;

		//当vertices为空 或者 position与prevRing0的距离超过minSegmentLength的时候,需要调用addRing()去添加ring。
        shouldAdd |= _vertices.Count == 0;
        shouldAdd |= Vector3.Distance(_prevRing0, _smoothedPosition.value) >= _parent._minSegmentLength;
		//addRing添加ring,updateMesh去更新mesh的数据。
        if (shouldAdd) {
          addRing(_smoothedPosition.value);
          updateMesh();
        }
      }

      public void FinishLine() {
        ;
	    //通过vertices、normals、triangles等可以通过脚本绘制mesh,mesh的data会被标记为modified,在下一次传给GraphicsAPI去渲染。而调用UploadMeshData可以强制将data立刻传给API渲染。
	    //而markNoLongerReadable参数则表示是否清空mesh data在内存中占用的空间。由于这里是FinishLine,所以设置为true。
        _mesh.UploadMeshData(true);
      }

	  //将顶点等数组的数据给刷新到mesh中去,从而更新场景中的mesh。
      private void updateMesh() {
        _mesh.SetVertices(_vertices);
        _mesh.SetColors(_colors);
        _mesh.SetUVs(0, _uvs);
	    //以Triangles的方式设置mesh的sub-mesh
        _mesh.SetIndices(_tris.ToArray(), MeshTopology.Triangles, 0);
        //重新计算边界和法向量
        _mesh.RecalculateBounds();
        _mesh.RecalculateNormals();
      }

	  //添加Ring&#x
  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Leap Motion SDK是一种用于与Leap Motion手势控制设备进行交互的软件开发工具包。它提供了一系列的类和函数,用于在Unity中实现与Leap Motion设备的交互。\[1\]Leap Motion SDK可以通过下载Leap Motion官方网站上的SDK来获取。\[1\]在Unity中使用Leap Motion SDK,可以使用LeapServiceProvider类来获取帧数据,该类将Leap Motion的坐标空间转换为Unity的坐标空间。\[3\]此外,LeapMotionUnityAPI为向量和空间变换定义了各自的类,可以通过一些转换函数将Leap Motion的向量和矩阵转换为Unity的向量和矩阵。\[2\]通过使用Leap Motion SDK,开发者可以在Unity中实现手势识别、手势控制等功能,从而为用户提供更加沉浸式的交互体验。 #### 引用[.reference_title] - *1* [Unity LeapMotion SDK 基础讲解](https://blog.csdn.net/weixin_43925843/article/details/117734184)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Leap MotionUnity 开发指南(二. 开发架构和SDK)L](https://blog.csdn.net/eagle_pre21/article/details/51776830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值