Unity之LeapMotion开发

一:LeapMotion简介










二:LeapMotion for Unity开发

一.  安装

1.      打开官网:https://developer.leapmotion.com/get-started

2.      先要下载和安装LeapMotion的驱动程序

         

注:我买的是二代Leap Motion,所以在Win10下 不支持V2 Desktop的开发驱动,选择左面的。(注意是开发驱动,而非App应用)

                 

我下载的最新版本是3.1.2,解压后如下图。


运行EXE文件,根据提示安装驱动,实际上这将安装了一个驻留程序在系统托盘中,并且生成一个自动启动的系统服务Leap Service,在控制面板中可查看它,当遇到Leap Motion不工作,或者托盘中图标显示黑色时,可检查一下这个服务是否正常。

如果系统托盘出的 Leap Motion 体感控制器图标为黑色,说明 Leap Service 服务并未运行,我们还需要手动启动服务,以支持 Leap Motion 体感控制器的使用。
步骤:
1.单击开始菜单,在“搜索程序和文件”输入框中键入“services.msc”,回车。
2.在服务控制台中,点选“Leap Service”服务,点击“启动”按钮,启动该服务。
3.系统托盘处的 Leap Motion 体感控制器图标变为绿色,说明服务启动成功。

驱动程序与LeapService通讯,读取硬件层面3D摄像头跟踪的手势数据,上层类的应用(如Unity,虚幻4,Java等)则与驱动程序(C++写成)通讯。

安装成功后,能看到LeapMotion两个摄像头和中间LED灯都正常亮起,表明处于工作状态,这时可用自动安装的Leap App Home应用来测试一下,通过它还可下载一些官方的例子。

3.      下载准备好各类Unity包

https://developer.leapmotion.com/unity下载所需的包。


其中CoreAssert是核心包,其他都是封装好的各类功能包,在实战篇中会介绍。

二.  基本概念

1.   坐标系统

Unity使用左手坐标,LeapMotion使用右手坐标(所以,Z轴是相反的)。

Unity以米为单位,LeapMotion使用毫米。LeapMotion配备的Plugin脚本内部对坐标系统进行了转化,即将单位和坐标转化为Unity的标准。

 

注意:在Unity中,一定要从LeapServiceProvider中获得Frame对象,否则在帧中的数据(TrackingData)将还使用Leap的坐标系统。LeapServiceProvider解析了Scaling,Rotation,Translation的变换.

2.   手势跟踪

LeapMotion使用了光学传感器和红外光组件。传感器的FOV为150度。顶部0.03~0.06米为有效的跟踪范围。


最佳的工作环境是可产生清晰的、高对比度对象轮廓的光照环境。

 

HMD模式下(头盔绑定的模式 ),跟踪算法被优化成对不同的视角下识别手势(大概的意思可能是,你头盔多动动,识别得更好一些),比放在桌面固定不动要更好一些。

 

3.   手(Hand Assert)

(1)表示方法

在预制件目录下,分成图形(图元)和物理两组脚本和预制件,可以用其中各一来组合表示手。这一处一定要理解,官方的Unity包里给了一些场景例子,可以研习一下。

从概念上手被区分成Graphic和Physic两种组件构成,前一即是图元,主要是呈现手的外观,后一主要表现手的物理特性(如刚体、碰撞)。

也可以没有物理组件,这样就不能产生物理特征了。

(2)创建手的方法

有几种创建手的方法:

  •  单独创建手的不同部位,比如手掌、胳膊、手指;
  •  创建绑骨骼的Mesh,驱动关节和骨骼来表示手的动作;
  •  用脚本编写来表示手的图形(即完全用脚本来绘制)。

(3)一个例子

下图是一个典型的手的例子,一个HandController下挂4个子对象,分别是图元左右手,物理左右手。


三.  创建你自己的手Prefab

注:跟着官方例子创建一个手,可能并不是很实用,但有助于理解手的预制件和原理组成。

你可以创建类似于已提供的Unity包里的手预制件,用你自己的图形来表示手,同时定制自己的手的行为(基于已提供好的代码)。

我们要创建的这种手称为“离散手预制件Discrete Hand Prefabs”,意思是手上每个部位都是单独的Game Object,都有其单独的位置和方向信息。在Core assert 包里,机器人的手即是这样的“离散预制件”。下面介绍了通过使用Unity自带的几何体(圆柱、圆)来创建Prefab。


  • 每一个图形元素都放在一个空对象下。手和手指的脚本负责更新空对象的Transform。每个图元的Local Transform的位置和方位依从于父对象。
  • 移除图形手上的所有碰撞体,否则将引起RigidHand的碰撞反弹。
  •  通常你不需要同时拥有关节和骨头。他们不是相互独立的。本教程中我们同时将关节和骨头加进模型中只是为了演示他们是如何工作的。
  • 类似的,你的模型也不必同时具有掌骨和手掌。掌骨是被手掌包围的,并且不能单独地动作。本教程同时具有二者(为了演示)。
  •  对手模型使用真实世界的尺寸。手和手指的脚本不能独立识别相关部位。整体的Scale被赋值成LeapHandController对象的scale(因为是必须挂在HandController下)
  • 由于采用了非常抽象和对称的设计,所以像在本教程中,能使用同样的Prefab表示左手和右手。但大多数的模型还是应使用不同的prefab表示左右手,这样能更好地调整Local Transform。


首先,我们需要创建一个手指的Prefab,并且使用它来创建手Prefab。

创建手指Prefab

1.     创建一个场景.

2.     新建一个空对象,命名KnobbyFinger

3.     创建骨头

1)     新建一个空对象到KnobbyFinger下,命名Metacarpal  (掌骨)

2)     新建一个CylinderMetacarpal,命名Tube.在创建你自己的手时,将此Cylinder替换为你自己的图形对象(或Obejct

3)     移除碰撞体组件,否则RigidHand碰撞体将会与它反弹。

4)     设置X Rotation90

(最好设置成Top视野来观察)

5)     Tube XZScale设置成0.0033毫米)。之所以这样设置,是因为要使用带皮肤的骨头,真实的手指要更胖一些。

6)     设置Tube YScale0.03434毫米)。这个决定了手指的长度。

尺寸必须使用真实世界的,转化为米。Y的长度应为68mm的一半,这是因为Cylinder2个单位高。所以我们要Scale缩减50%.

7)     复制Metacarpal,命名ProximalTube Y-Scale设置为0.02

8)     再复制Metacarpal,命名IntermediateTubeY-Scale设置为0.01

9)     再次复制Metacarpal,命名DistalTubeY-Scale0.007

4.     创建关节

记住:你不必都需要骨头和关节

1)     新建空对象到KnobbyFinger,取名MetacarpophalangealJoint(掌指关节)

2)     新建一个圆到关节,取名Knob.

3)     移除碰撞体。

4)     Knob所有的Scale设置成0.011厘米).

5)     复制MetacarpophalangealJoint更名为ProximalinterphalangealJoint.

6)     复制MetacarpophalangealJoint更名为DistalinterphalangealJoint.

6.     增加SkeletalFinger 脚本组件到KnobbyFinger

7.     拖动每个关节和骨头到脚本中的相应变量处。

具体如下:

Bones:

o  0 -Metacarpal

o  1 - Proximal

o  2 -Intermediate

o  3 - Distal

Joints:

o  0 - MetacarpohalangealJoint

o  1 -ProximalinterphalangealJoint

o  2 -DistalphalangealJoint

8.     将KonbbyFinger做成预制件。

创建手Prefab

(创建好手指Prefab后)

1.     创建空对象,取名KnobbyHand.

2.     增加SkeletalHand 脚本到 KnobbyHand.

3.     脚本变量Handedness设置成“Either.” (如果你的手是不对称的,设置成 “Right” or “Left”.)

4.     拖动5个KnobbyFinger Prefab到手中,命名为:Thumb, Index, Middle, Ring, and Pinky.

5.     对于每个手指,设置Finger类型为相对应的类型(SkelatalFinger脚本组件中)。

6.     拖动手指到KnobbyHand 的SkeletalHand 脚本中相应的Fingers变量上.

Finger element order:

o  0 - Thumb

o  1 - Index

o  2 - Middle

o  3 - Ring

o  4 - Pinky

7.     拇指是特殊的,没有Metacarpal. 因此,编辑Thumb,在bone数组中移除bone( element 0 ) . 删除Metacarpal子对象.

8.     增加手掌Add the palm:

如果没有图形元素,你可以在KnobbyHand的SkeletalHand脚本变量Palm,wrist,forearm先留为空白。手掌也可通过RigidHand来表示,如果你不使用palm,你可以修改RigidHand的副本,但要移除rigid body和collider。

1)    增加一个空对象到KnobbyHand.取名Palm.

2)    增加一个Cylinder Palm.取名 Disc.

3)    移除Collider.

4)    设置Disc scale (.085, .0015, .085)..

5)    拖动PalmSkeletalHand脚本的Palm变量中

9.     增加手腕:

1)    增加一个空对象到KnobbyHand,取名Wrist.

2)    增加一个圆到Wrist.取名 Ball.

3)    移除Collider.

4)    设置Ball scale(.03, .03, .03).

5)    拖动WristSkeletalHand脚本WristJoint变量中.

10.  增加胳膊

1)    增加一个空对象Arm.

2)    增加一个CylinderRod.

3)    移除Collider.

4)    设置Rodx rotation为: 90.

5)    设置Rodscale(.02, .12, .02).

6)    拖动 ArmSkeletalHand脚本的Forearm

12. KnobbyHand创建为prefab.

KnobbyHand的结构应为下图所示:


测试你的手

1.     新建一个LeapHandController prefab到场景中,以便交互区域是在摄影机的FOV内。

2.     设置如下层次结构


3.     LeapHandControllerHandPool中设置:

.

4.     运行关卡,观察你的手

如果RigidHand组件在Scene窗口中可见,但抖动或反弹,确保你移除图元手部位的所有碰撞体。

如果手指重叠或者移动在一个手指的控制下,检查手指SkeletalFinger 脚本的手指类型设置。

如果你的手混杂成一大团的乱糟糟样子,那是每个子元的Scale设置的太大了,记得Unity的单位是1米,一个典型的手宽度是8.5厘米(或者表示成Unity transform的Scale是0.085)。如果想使手更大一些(在游戏里看),增大LeapHandController的Scale.

三.Unity 主要类介绍

1.      Leap.Unity 命名空间下的类

此命名空间下的类负责与Unity的GameObject或组件交互,获取跟踪数据。

·        LeapServiceProvider –

访问跟踪(手势轨迹)数据和图形,并与LeapController对象通信,转换轨迹数据为Unity的制式;同时将右手坐标转化为左手坐标。

·        IHandModel,HandModel,或继承于它们的 类(如CapsuleHand)–

所有的手都基于这些接口和类,如果你创建自己的手,你必须实现IHandModel 或继承HandModel.

·        LeapHandController –

负责与手的图元以及物理对象进行交互。

2.      Leap命名空间leap     Leap 

Leap空间中的类定义了LeapMotion所跟踪的具体内容。

·        Frame

帧是某个时间点的数据集合,一个帧包含了Hand对象。

·        Hand

一个Hand手对象表示了一个跟踪的手,一个手总是包含5个手指以及相关属性如:Direction,PalmPosition,和Basis(orientation).

·        Finger

一个Finger手指对象表示了追踪的手指。一个手指包含四个骨头。

·        Bone

Bone骨头对象表示手指的一段,并包含位置、大小和方位数据。

·        Arm

Arm胳膊对象是特殊的Bone,其实是跟踪了前臂。.


Leap命名空间下的脚本不是仅专属于Unity的,也可被任何C#程序调用。但在Unity中使用这些类有一些重要的区别:你必须从LeapProvider中获得Frame对象,而不是从Controller对象。LeapProvider将Leap Motion的坐标空间转为Unity的。如果你直接从Controller中获得帧,那么你必须自己处理这些转化。

LeapMotion和UnityAPI为向量和空间变换定义了各自的类,你可以从Leap Motion的类转为Unity等价的类,如下例所示。


Vector3 unityVector = leapVector.ToVector3();
Quaternion unityRotation = leapMatrix.Rotation();
Vector3 unityTranslation = leapMatrix.origin.ToVector3();
Vector3 unityScale = new Vector3(leapMatrix.xBasis.Magnitude,leapMatrix.yBasis.Magnitude,leapMatrix.zBasis.Magnitude);



猜你喜欢

转载自blog.csdn.net/qq563129582/article/details/77071042