Leap Motion 之 准备工作

来源:互联网 发布:腾讯代理吃鸡优化 编辑:程序博客网 时间:2024/06/10 14:32

【仅用于个人复习使用,顺序较乱】
一、环境搭建
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为例。双击进入该场景。

该场景的层次结构如图所示:
场景的层次结构

HandModels就是双手的模型在hierarchy中生成的对象,LeapHandController就是双手的控制器。需要将HandModels中的Graphics Hands(用来渲染的mesh)和Physics Hands(碰撞器和刚体)传入LeapHandController中,LeapHandController才可以正常work。
LeapHandController-HandPool

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<int, HandRepresentation> graphicsReps = new Dictionary<int, HandRepresentation>();    protected Dictionary<int, HandRepresentation> physicsReps = new Dictionary<int, HandRepresentation>();    // 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<T>是这个脚本中自定义的一个函数,相当于GetComponent,只不过如果没有Component的话会写log。      //其实拿到的就是LeapServiceProvider和HandPool。这两个对象就是那两个抽象类的实现类。      provider = requireComponent<LeapProvider>();      factory = requireComponent<HandFactory>();      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<int, HandRepresentation> 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<T>() where T : Component {      T component = GetComponent<T>();      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当中。
Frame
Frame当中的Hands实际上就是Hand类型的List。
Hand
当前手部信息(例如finger的位置啊)保存在Hand中,通过Factory产生HandRepresentation并保存在Dictionary中。
每次Update()时,对Dictionary中的active的HandRepresentation调用UpdateRepresentation()函数,其实就是更新HandRepresentation中的Hand属性,也就是更新了场景中的HandModel。
(由于更细节或者更底层的东西还没有看过,所以目前提及的并不一定全都正确,先note一下~)

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

0 0
原创粉丝点击