Leap Motion 之 准备工作

【仅用于个人复习使用,顺序较乱】
一、环境搭建
1、unity(5.0以上版本)
2、LeapMotion SDK(https://developer.leapmotion.com/get-started/)
压缩包(几百MB)下载下来解压安装就okay~
3、Core Asset For Unity(https://developer.leapmotion.com/unity/)
这个只有1.9MB,一个很小的unityPackage~

二、连接测试
1、基本连接
http://jingyan.baidu.com/article/c843ea0bb19a3d77931e4af7.html
右键leap motion控制器可以打开visualizer,按v键可以切换模式。显示橙色则需要清除leap motion上的污迹。(启动会一直闪绿色,只需稍等片刻即可)
如果提示leap service未启动,点击电脑-管理-服务-leap service,右键选择启动即可。
2、Visualizer的使用
http://blog.csdn.net/guoming0000/article/details/9566563
不知道为什么很多命令按了并没有用O>o

三、LeapMotion&Unity
(PS:如果Unity中无法new新的工程,重新登录账号即可,不要问我是怎么知道的O.O)
Core Asset中只有Capsule Hand和Debug Hand,可以从官网下载Hand Module来获得其他的Hand Model,例如Rigged Hand。

四、Core Asset
1、Plugins文件夹
插件?不是很清楚。。。
2、Leap Motion文件夹
这个文件夹是CoreAsset的核心内容。
Gizmos:传感器的贴图
Materials:材质
Models:手的模型
Resources:自定义的Shander,用于Materials中的材质
Textures:一些贴图。。。

OK,以上这些都不重要,属于花里胡哨,下面才是重点。

Editor:一些Editor脚本。
Prefab:预制件,比如HandController。拖入Hierarchy中即可直接使用。
Scripts:一些脚本,例如LeapHandController,后面会具体分析。
Scenes:提供的demo场景,有AR、VR、Desktop。我们这里以Desktop为例。双击进入该场景。

该场景的层次结构如图所示:
Leap Motion 之 准备工作_第1张图片

HandModels就是双手的模型在hierarchy中生成的对象,LeapHandController就是双手的控制器。需要将HandModels中的Graphics Hands(用来渲染的mesh)和Physics Hands(碰撞器和刚体)传入LeapHandController中,LeapHandController才可以正常work。
Leap Motion 之 准备工作_第2张图片

LeapHandController对象包含三个脚本:LeapHandController.cs、LeapServiceProvider.cs、HandPool.cs。以下是对这些脚本的解释,当然这对正常使用影响不大,你也可以选择直接跳过这部分。

(1)LeapHandController.cs
直接看注释就好,比较详细~

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Leap;

//名字空间
namespace Leap.Unity {
  /**
   * LeapHandController uses a Factory to create and update HandRepresentations based on Frame's received from a Provider  */
  public class LeapHandController : MonoBehaviour {
    protected LeapProvider provider;
    protected HandFactory factory;

    protected Dictionary graphicsReps = new Dictionary();
    protected Dictionary physicsReps = new Dictionary();

    // Reference distance from thumb base to pinky base in mm.
    // 也就是拇指到小指在unity中代表的距离
    protected const float GIZMO_SCALE = 5.0f;

	// 这个是内部变量,为了封装的考虑,在下面使用C#中的get和set方法。由于是protected,所以在Inspector面板中不会显示,添加[SerilizeField]将其序列化,可以强制显示在面板上。
    protected bool graphicsEnabled = true;
    protected bool physicsEnabled = true;
	// get和set方法,主要是权限控制,以及在赋值或读值的时候加入代码检验。带有get/set方法的变量不会显示在Inspector面板中。主要是用在脚本中,暴露给其他类调用来修改相应的变量。如果在Inspector面板修改,则需要Editor去手动关联。当然unity5.0之后的版本可以通过SetProperty来自动实现这一功能。
	//关于get/set以及Editor,可以参考这个链接:http://www.cnblogs.com/lixiang-share/p/4658132.html。
    public bool GraphicsEnabled {
      get {
        return graphicsEnabled;
      }
      set {
        graphicsEnabled = value;
      }
    }

    public bool PhysicsEnabled {
      get {
        return physicsEnabled;
      }
      set {
        physicsEnabled = value;
      }
    }

    /** Draws the Leap Motion gizmo when in the Unity editor. */
    //所谓的Gizmos,也就是在Scene窗口中显示的小玩意儿,在Scene窗口顶栏可以设置显示的Gizmos种类。而在Game窗口中就不在显示了。
    void OnDrawGizmos() {
      Gizmos.matrix = Matrix4x4.Scale(GIZMO_SCALE * Vector3.one);
      //这就是Gizmos文件夹的那张贴图
      Gizmos.DrawIcon(transform.position, "leap_motion.png");
    }

    protected virtual void OnEnable() {
	  //LeapProvider和HandFactory是Scripts文件夹下两个抽象类,requireComponent是这个脚本中自定义的一个函数,相当于GetComponent,只不过如果没有Component的话会写log。
	  //其实拿到的就是LeapServiceProvider和HandPool。这两个对象就是那两个抽象类的实现类。
      provider = requireComponent();
      factory = requireComponent();

      provider.OnUpdateFrame += OnUpdateFrame;
      provider.OnFixedFrame += OnFixedFrame;
    }

    protected virtual void OnDisable() {
      provider.OnUpdateFrame -= OnUpdateFrame;
      provider.OnFixedFrame -= OnFixedFrame;
    }

    /** Updates the graphics HandRepresentations. */
    protected virtual void OnUpdateFrame(Frame frame) {
      if (frame != null && graphicsEnabled) {
        UpdateHandRepresentations(graphicsReps, ModelType.Graphics, frame);
      }
    }

    /** Updates the physics HandRepresentations. */
    protected virtual void OnFixedFrame(Frame frame) {
      if (frame != null && physicsEnabled) {
        UpdateHandRepresentations(physicsReps, ModelType.Physics, frame);
      }
    }

    /** 
    * Updates HandRepresentations based in the specified HandRepresentation Dictionary.
    * Active HandRepresentation instances are updated if the hand they represent is still
    * present in the Provider's CurrentFrame; otherwise, the HandRepresentation is removed. If new
    * Leap Hand objects are present in the Leap HandRepresentation Dictionary, new HandRepresentations are 
    * created and added to the dictionary. 
    * @param all_hand_reps = A dictionary of Leap Hand ID's with a paired HandRepresentation
    * @param modelType Filters for a type of hand model, for example, physics or graphics hands.
    * @param frame The Leap Frame containing Leap Hand data for each currently tracked hand
    */
    protected virtual void UpdateHandRepresentations(Dictionary all_hand_reps, ModelType modelType, Frame frame) {
      //Frame应该是LeapMotion自己定义的类,猜测可能是将LeapMotion捕捉到的一帧画面进行解析之后,用来保存信息的类。比如这里的frame.Hands.Count就是指这帧画面中的手的数量。
      for (int i = 0; i < frame.Hands.Count; i++) {
        var curHand = frame.Hands[i];
        HandRepresentation rep;
        //如果有就直接get value,如果没有则add一个新的pair
        if (!all_hand_reps.TryGetValue(curHand.Id, out rep)) {
          rep = factory.MakeHandRepresentation(curHand, modelType);
          if (rep != null) {
            all_hand_reps.Add(curHand.Id, rep);
          }
        }
        //这里会将HandRepresentation的IsMarked置为true,也就是说每一帧画面中active的rep都会被标记。
        if (rep != null) {
          rep.IsMarked = true;
          rep.UpdateRepresentation(curHand);
          rep.LastUpdatedTime = (int)frame.Timestamp;
        }
      }

      /** Mark-and-sweep to finish unused HandRepresentations */
      //遍历Dictionary,如果发现未被标记的rep,则他一定不是active的,则直接remove掉。
      HandRepresentation toBeDeleted = null;
      for (var it = all_hand_reps.GetEnumerator(); it.MoveNext();) {
        var r = it.Current;
        if (r.Value != null) {
          if (r.Value.IsMarked) {
            r.Value.IsMarked = false;
          } else {
            /** Initialize toBeDeleted with a value to be deleted */
            //Debug.Log("Finishing");
            toBeDeleted = r.Value;
          }
        }
      }
      /**Inform the representation that we will no longer be giving it any hand updates 
       * because the corresponding hand has gone away */
      if (toBeDeleted != null) {
        all_hand_reps.Remove(toBeDeleted.HandID);
        toBeDeleted.Finish();
      }
    }

    private T requireComponent() where T : Component {
      T component = GetComponent();
      if (component == null) {
        string componentName = typeof(T).Name;
        Debug.LogError("LeapHandController could not find a " + componentName + " and has been disabled.  Make sure there is a " + componentName + " on the same gameObject.");
        enabled = false;
      }
      return component;
    }
  }
}

总的来说,就是LeapMotion实时的捕捉每帧的画面。拿到某帧画面后,通过解析将信息保存在Frame当中。
Leap Motion 之 准备工作_第3张图片
Frame当中的Hands实际上就是Hand类型的List。
Leap Motion 之 准备工作_第4张图片
当前手部信息(例如finger的位置啊)保存在Hand中,通过Factory产生HandRepresentation并保存在Dictionary中。
每次Update()时,对Dictionary中的active的HandRepresentation调用UpdateRepresentation()函数,其实就是更新HandRepresentation中的Hand属性,也就是更新了场景中的HandModel。
(由于更细节或者更底层的东西还没有看过,所以目前提及的并不一定全都正确,先note一下~)

(2)LeapServiceProvider和HandPool
(代码较长,暂时没看~大致上前者是负责提供frame,而后者是负责将frame的Hand给封装成HandRepresentation)

你可能感兴趣的:(本科时的小白文)