Unity 交互SDK

1. SDK版本发布记录

初次阅读文档者请先仔细阅读此链接处并了解V1.0发布版内容。

版本号
更新内容

V2.0

  1. 增加远距离交互

  2. 增加交互物体轮廓线提示及交互触发音效

  3. 增加静态手势识别

  4. 优化多处交互逻辑,修正bug,增加处理工具

  5. (重要) 更新适配Pico SDK 3.3版本(仅在Pico集合版)

  6. 提供新的Swift定位方案参数(仅在Pico集合版)

V1.5

  1. 蓝牙Pico集合版已迭代为Pico集合版(增加设备连接方式)

  2. 增加控制器应用实例

  3. 数据接收及回传插件更新

  4. 增加标定数据记录

  5. 更改交互核心脚本图标

  6. UI界面语言更改为英文

V1.4.3

  1. 优化大拇指活动表现(仅在蓝牙Pico集合版)

V1.4.2

  1. 修正手部模型在VR中可能会出现的穿模问题(仅在蓝牙Pico集合版)

V1.4.1

  1. 修正物理手在各种Objectfollowtype下的表现,修正原始非物理手在natural交互方式的表现

  2. 修正实例体中HandInteractor脚本上Active Range的数值错误

  3. 示例UI增加检测双手连接才能继续流程的限制,增加手势动作标定后的摇杆范围标定(仅在蓝牙Pico集合版)

  4. 优化蓝牙版手套的表现(仅在蓝牙Pico集合版)

  5. (重要) 更新适配Pico SDK 3.1版本(仅在蓝牙Pico集合版)

V1.4

  1. 增加物理手与物理性质交互

  2. 增加可交互物体的物理属性应用选项及参数调整

  3. 修复了RegularShapeFit功能触发不正确的问题

  4. VR Base UI增加高度调节选项(仅在蓝牙Pico集合版)

V1.3.3

  1. 修复了InteractableObject脚本上Unity Event监听无效的问题。

V1.3.2

  1. 修复了程序在正常运行时会短时间后崩溃闪退的BUG。(仅在蓝牙Pico集合版)

V1.3.1

  1. 修正了V1.3中的一个交互无法触发BUG。

V1.3

  1. 替换SDK内左右手模型为新标准姿态,虚拟手的食指及小指所有关节增加偏航调整。

  2. InteractObject脚本迭代:增加物体交互与交互完成时的UnityEvent监听、增加组合交互方案切换功能与接口、增加交互锁接口、更改手势检测按钮逻辑。

  3. Hand Interactor脚本迭代:增加强制更改当前交互手势方法

  4. RegularShapeFit脚本增加SpecialCube选项,可自适应适配立方体上的任意角度交互。

  5. HandController插件已迭代为适配HandDriver2.1.2版本。

  6. VR Base UI 增加手套连接选择页面。

  7. 修正若干交互Bug

V1.2

  1. 调整SDK内左右手模型初始姿态。

V1.1

  1. 增加蓝牙手套算法适配。

V1.0

  1. 发布版,说明内容请见下文

1.1. 更新详细说明

V2.0

提醒:由于SDK该版本变动较多较大,如果需要在现有项目中更新请保留源工程备份以防开发损失。

在新的示例场景[9. Distant Interact]中,增加了远距离交互的范例。

远距离交互的射线可视化组件(LineRenderer)位于手部内的DetectArea物体上,在启用Toggle Visibility后,选中左、右手跟关节可以看到可视化的射线方向,为了便于显示仅展示部分射线长度,实际运行时长度是无限的。

以左手为例,手心朝外为正方向,手部所含的射线检测为:深蓝色(沿着拇指以外的四指,朝上)、红色(垂直于手心向外的正方向)、粉色(红色与深蓝色的夹角中间,45°)、绿色(红色朝下45°),青色(红色朝右45°),黄色(红色朝左45°)。

右手上的射线布局一致。为了缓解运行时检测压力,暂时只规划这六条射线,后续可能视情况迭代。

InteractableObject脚本上,选择Object Follow Type为Distance即为远距离交互。此时物体上会自动增加一个较大的球形触发检测箱,便于让射线捕获,该碰撞箱可以自行调整或删除。

Tracking Max Distance为手部检测与该物体能交互的最大距离,Tracking Time是物体移至手上所需的交互时间。

当手部的射线检测到物体时,会在手部和物体中间出现一道浅蓝色的连接线,代表此时手部与该物体已经处于交互预备状态,此时手部抓握即可触发交互。

交互手势,物体选择,优先级等功能都依旧适用。远距离交互物体在和其他交互方式的物件处于共同场景时,触发选择的判断依旧基于距离和优先级。

当远距离交互物体在离手部很近的位置时(处于手部常规的交互范围判定内),不会再出现中间的引导连接线,此时也能正常触发交互。

在新的示例场景[10. Interact Hint]中,增加了交互提示的范例。

Interactable Object脚本上增加了两个按键,分别为增加轮廓线组件和增加交互音效。

增加轮廓线组件后,物体根节点同级会增加一个InteractableObjectOutline脚本。

可以自定义轮廓线颜色及宽度,默认为红色6像素宽。

当物体处于可交互范围或状态下,轮廓线会显示。包括新增的远距离交互,也能适用。

增加交互触发音效后,物体根节点同级会增加一个Audio Source组件。InteractSound是一个简单的触发音效例子,以按钮形式增加的该组件会自动绑定在InteractableObject脚本内的WhenObjInteract监听内,交互触发时播放音效。可以随意更换音效,或是自定义增加AudioSource并进行关联绑定。

在新的示例场景[11. Distant Interact]中,增加了对静态手势判断的范例。

判断组件为Hand预制体下除了左右手外的新节点上的StaticPoseDetector脚本。该节点下存有若干代表静态手势的物体,挂载HandStaticPose脚本。该脚本的作用逻辑与交互中所用的HandInteraction极为类似,本身蕴含一个固定手势,在非运行状态下选中该节点会在场景内生成对应的蓝色手势。

Handedness控制左右手,Freedom控制手部关节是否可以活动(该类沿用了HandInteraction的,在手势判断中没有额外作用),Consider Wrist代表是否考虑手腕(默认不启用),也就是判断手势时需不需要考虑整个手部在场景中的处于的姿态,参考的是世界坐标系,可以在运行时动态变更。Create Visual Pose Model会在子物体目录创建一个固定的白色网格模型手,作为该手势的可视化,对手势判断没有实际影响。该示例场景内的手模型均为这样创建。

需要注意,Consider Wrist点选后,最好在确定虚拟手势根关节姿态后再创建手模型,维持姿态的一致性。另外在创建模型后更改静态手势模型不会跟随更改,需要重新创建。同时单独更改模型内关节姿态,对原本的手势判断也没有影响,点选HandStaticPose脚本所在物体时生成的蓝色虚拟手为最高层级判断依据。

StaticPoseDetector脚本为所有静态手势的管理组件。在非运行点按下Detect Poses按钮能够罗列全部在判断状态的手势,一般所有手势都应该处于StaticPoseDetector物体下一层的子节点上。不过就算不在非运行时按下按钮,在运行时也会自动执行。因此该列表在非运行时的状态未必是运行时的状态,需要自行检查。

PoseMsg是场景内对手势判断的信息输出,在消息监听方法内部控制。如果需要更改监听方式或是判断,需要自行更改处于StaticPoseDetector.cs脚本内的方法:

void PoseDetectAnnouncement(object sender, StaticPoseDetectEventArgs e)

以上为以左手为例的静态手势识别效果。

该方法仍旧有不稳定或不准确的情况,后续将持续迭代优化。

新建静态手势可以通过更改已有手势或是新建手势的方法。在HandInteractor脚本上新增了创建静态手势的按钮,使用逻辑与上方的录制实时手势交互相同。点击时会生成相应的左手或右手静态手势,动作与运行时手部模型的姿势一致,同时在SDK目录下的VirtualTemp文件夹内会储存录制的静态手势预制体。

现在可以支持录制保存多个预制体,命名会以数字尾缀逐渐叠加。该功能现在对手势交互录制也同样生效。

在场景内复制含有HandInteraction或是HandStaticPose脚本的物体时,会在场景内遗留一份额外的虚拟手物体,该物体是由于复制粘贴产生的多余组件。

通过点选上方任务栏中UDE Interaction选项下的Clear All Redundant Virtual Hand,可以一次性清除场景内这些多余的虚拟手物体。

此外,在Pico集合版中,SDK内有关Swift定位的脚本已更新适配最新的Pico SDK V3.3.0,请在官网获取更新。

https://developer-cn.picoxr.com/resources/arrow-up-right

在两个VR Base场景内,应用swift定位的MotionTracker脚本有些许变动。

Use Old Calibration Version为使用旧版的定位方案。目前最新版的手套定位方案是Swift贴点位置在拇指根部往下更靠近手腕朝身体内侧的位置,需要搭配全新的手套来使用。除此以外的旧版手套均为靠近手背的虎口下方贴点位置,需要勾选此选项来正常使用。

MotionTrackerNum是Pico SDK内检测追踪器使用数目的方案,一般情况选TWO即可。

纯交互版中,原先的9.Controller Sample示例场景更名为Controller Sample,仅去除了数字序号。

V1.5 示例场景-控制器范例

从1.5版本开始,原先SDK的蓝牙Pico集合版更名为Pico集合版,在保留了蓝牙连接功能(后续功能迭代将以2.4G为主)的同时增加了2.4G Android Service连接,关于Android Service的文档请见:VR头显安卓服务Glove Service用户手册

Pico集合版中移除了VR Base,增加了示例场景VR Base(BLE)——供原蓝牙连接场景以及VR Base(Android Service)——供Android Service连接场景使用。

在示例场景[VR Base(BLE)]中,增加了移动时参照的地面。

完成手套标定后,新增的VRControllerSample脚本提供了一套VR中的移动实例。左手摇杆直接控制角色(摄像机及手模型)移动,右手摇杆朝前推动能够启用传送,抛物线方向角度由右手姿态控制,松开摇杆后角色将瞬移到蓝色脚印图标的位置。按下右手控制器上的A按键可以移回到最后一次瞬移前的位置。

左手控制器B按键按下后可以开启额外操作面板,由上至下功能分别为:标定评价,重新标定,退出游戏。再次按下同一B按键后可以折叠关闭该面板。

在示例场景[VR Base(Android Service)]中,同样增加了移动时参照的地面,与蓝牙连接版不同之处是,应用内不再有标定和查看标定评价的功能,这部分已经全部移至安卓服务应用中。在主面板UI上按下Start开始游戏后面板就会关闭。其余控制器操作与BLE场景内一致,额外操作面板上仅有退出游戏的按钮。

纯交互版中增加了示例场景[9. Controller Sample],在Hand根节点上增加了示例脚本ControllerSample,通过左手摇杆可以控制场景内的小车移动,右手摇杆控制小车旋转。

该脚本上八个UnityEvent可以绑定控制器上对应按键触发时执行的事件。其中Menu按键为A、B同时按下时触发,此时不会触发A或B按键。Interact Interval为触发响应间隔,为了避免重复或重叠触发设置。某一个控制器按键按下并作用后,在该相应间隔内任何按键都不会触发,详细逻辑可以参考脚本代码。Control Obj为示例的玩具车。下方的Joystick Value可以实时显示摇杆的数值。

在SDK两版(纯交互及Pico集合)内的LeftHand与RightHand下的Hand上的HandDriver是接收数据的脚本,该脚本已经更新为Unity插件的最新版。使用参考文档:HandDriver Unity 插件使用手册

Pico集合版的Android Service场景中的HandDriver和纯交互中的HandDriver作用略有些不同。前者用于VR应用运行时接收安卓服务数据,后者为PC开发中接收HandDriver软件的串流数据,并回传震动反馈指令。HandDriver脚本上的应用开关设置部分,第一项需要默认勾选,第二项勾选对应PC应用场景接收数据,第三项为在VR设备上接收Android Service时勾选。请注意二、三不可同时勾选,需要区分应用场景。

在Pico集合版的蓝牙连接与安卓服务场景中,该项为主要的应用设置差别。蓝牙连接只需勾选第一项,接收安卓服务需要勾选一、三项。

另外原先蓝牙连接中的振动反馈是通过调用蓝牙SDK内的接口方法实现的,在安卓服务场景该方法挪动到了HandDriver脚本中。勾选UsingAndroidService后,调用ServiceVibrationControl()方法即可。

void ServiceVibrationControl(int VirbatorIndex = 1, int DurationSecond = 20, int Strength = 10)

接口功能向安卓服务发送振动反馈指令

参数说明该接口的参数说明如下:

参数名称
是否必选
示例值
说明

VirbatorIndex

int

1

硬件振子位置,1对应按键下方,2对应摇杆下方,3代表同时启用两处

DurationSecond

int

20

振动持续毫秒数(10ms),示例值代表200ms

Strength

int

10

振动幅度等级,可选范围为4~10级

在Pico集合版的蓝牙连接中增加了标定数据记录的功能,该功能改动在SDK核心内自动启用,具体实现及效果可以参考VR Base(BLE)。在同一应用内,会永久保留最后一次标定数据(包括手部动作标定与摇杆标定),重复打开应用并连接上手套后能直接应用记录的标定数据。

在已经有记录的标定数据时,在手套连接状态的UI面板右下角会出现Skip跳过按钮,点击后可以直接关闭UI面板跳过最初的标定步骤。如果需要在应用期间重复标定,在额外面板上选择重复标定即可。

在SDK双版本内,不建议内部改动的交互核心脚本已经全部更换为UDEXREAL的Logo图标,方便区分。

为了更广泛的适用性,所有示例场景内UI上的描述已全部更换为英文。

V1.4.3

在上一更新版本基础上优化了大拇指的表现,更符合实际动捕效果。

V1.4.2

更新了蓝牙中旋转角应用在关节点上的方法,消除了VR中手部动作可能会出现的穿模问题。

V1.4.1

在1.4更新的物理手及原本的非物理手条件下,对可交互物体InteractableObject脚本上的各种Objectfollowtype选项均可以正常交互。包括物理手适配Instant, Slow Move, Chasing, No Pose,以及非物理手适配Natural。

V1.4中非物理手Hand预制体内,HandInteractor脚本上的Active Range数值变为0,会导致示例场景内交互无法进行,现已更正为初始默认数值。

在示例场景VR Base中的UI范例上,现在进行到连接设备信息界面时,需要等到左右手讯息栏皆为高亮状态才能点击下方的继续按钮进行标定流程。

另外在结束原先的五指分开标定动作后,会进入新增的摇杆范围标定页面。将左右手的摇杆(分别操作或同时操作均可)在最大可交互范围内绕上两到三周后,点击完成标定按钮。

另外在V1.4及以前版本中,实际开发使用的Pico SDK版本为2.3.0版,从V1.4.1版本开始将适配最新的Pico Unity SDK 3.1.0及更高版本。官方新SDK获取链接:

具体更改为移除了适配旧版中的SpatialLocationSetting_L.cs 和 SpatialLocationSetting_R.cs,作用为读取PICO 体感追踪器的位置姿态信息并与手部定位关联。现在该功能的脚本已经替换为MotionTracker.cs,仍旧位于XR Origin内的TrackedLeftHand与TrackedRightHand上。

该脚本上有控制左右手的枚举项,Target为实际追踪需要关联的手部根节点。在非物理手时为Hand预制体上的手部根节点LeftHand与RightHand,在物理手预制体内时为左右手导航点LeftHandNavigator与RightHandNavigator。

至此旧版的Pico SDK 2.3.0(左右)已不再适配,请开发时留意迭代为新版。

V1.4 示例场景-物理自然模拟 [8. Natural Interact]

在新的示例场景[8. Natural Interact]中引入了符合现实物理模拟的自然交互。

场景内的手部模型采用了新的预制体PhysicalHands

相较于先前版本的Hands预制体,物理手其中LeftHand与RightHand是手模型本体,LeftHandNavigator和RightHandNavigator是两个空物体,仅作为左右手模型的定位。

在HandInteractor同层级上,现在左右手都增加了控制实现物理属性的PhysicalHand.cs脚本。

Navigator是左/右手的导航定位,TraceToloranceDist是手可以与导航相隔的最大距离。Velocity Limitationn是模型跟随导航的速度限制。

LeftHandNavigator与RightHandNavigator是现实定位点。在示例中可以看到,正常情况下物理手不可以沿着某一方向穿过带有碰撞体的桌面,但如果定位点与手模型距离大于TraceToloranceDist,就会将模型强制移动到定位点上。

在实际应用中,只需要控制左右手对应的导航点即可。

同时手掌及手指上也都增加了适配的碰撞体,两只手之间与手和环境之间都可以实现物理效果。

场景内的可交互物体SampleStick是其它场景中同样的预制体,在与物理手交互时也有真实碰撞效果。

该物体上没有刚体,由此没有重力效果。场景内的胶囊体SamplePhysicalCapsule适配了刚体重力和新的物理适配。

在InteractableObject.cs上有新的EnablePhysicalProperties参数,适用于有刚体适配的可交互物体。注意:点选该选项时将会自动关闭物体刚体的IsKinematic选项,因为运动学会影响交互正常表现

启用选项时还会多出是否应用物体运动轨迹的选项EnableObjectMotionTrace,点选后会给物体自动挂载LineRenderer,在物体结束交互后会以橘色勾勒运动轨迹。TraceVisibleSecond控制轨迹留存的时间,单位为秒。当物体再次交互完毕或时间结束后轨迹将消失。

取消点选EnableObjectMotionTrace或EnablePhysicalProperties会去除物体上的LineRenderer组件。

原先的Active Interaction Plans更名为Enable Interaction Plans,功能不变。

在ObjectFollowType中增加了Natural,效果为手部移动到物体上,达成交互状态后手部回到真实追踪点。在SamplePhysicalCapsule物体上均适配了这个效果。

RegularShapeFit的效果得到了改善,没有增加新的配置选项。在物理模拟交互中,规则形状物体总需要在手部最合适的位置上进行交互(单一固定手势可能存在手势在地表下或其它物体的碰撞体内的情况),但偶尔也会存在交互时的穿模,该问题在后续迭代中会尽可能优化。

交互效果如下:

按下红色按钮可以重置所有胶囊体。

circle-exclamation

在VR Base场景的UI初始面板上左下角增加了坐姿或站姿调节的按钮。功能为在实际坐姿或站姿进入游戏场景中,可以让UI,视角和手处于场景内较为适当的高度。

V1.3.3

修正了V1.3中,InteractableObject脚本上的WhenObjInteract和WhenObjDisable的Event无效的问题。

V1.3.2

修正了V1.3中,手套标定后正常运行两分钟左右会出现程序崩溃闪退的问题。

V1.3.1

修正了V1.3中的“物体内组件交互”无法触发的BUG。

V1.3 示例场景-动态交互方案 [7. Dynamic Interactions]

SDK内的手模型已替换为新标准模型,左右手的轴向配置相同,相同手部表现时旋转角正负统一(例如两只手的食指朝外扩张的偏航角均为负值)。现在从HandInteraction脚本上切换左右手手势时左右手姿态将保持一致。同时虚拟手的食指和小指二三关节也增加了偏航角调整,这个配置主要是为了在设定固定手势,譬如握拳时有更好的手部表现,对正常手部活动没有影响。

Interactable Object上增加了交互触发与交互结束时的Unity Event监听。

在新的示例场景[7. Dynamic Interactions]中采用了新的交互组合方案功能。

左侧的哑铃片物体SampleBell上含有两种Interaction Plan交互方案,启用该功能需要勾选Active Interaction Plans。

在常规运行时,会在已经设定好的Hand Interactions内选择交互手势。如果出现需要变换,更改手势的情况,可以调用InteractableObject.cs内的重载接口方法SwitchHandInteractioinPlan来切换方案,以目标方案序列号或是名称作为传参。InteractionPlan的单个组件为方案名称与方案的交互手势集合,切换方案时将自动更改Hand Interactions为方案内的Hand Interactions,达到动态更改交互手势的效果。需要注意的是ObjectFllowType是无法动态切换的。

public void SwitchHandInteractioinPlan(int index) {...}

public void SwitchHandInteractioinPlan(string name) {...}

右边的哑铃物体SampleDumbbell上也含有两个交互方案。在初始时Hand Interactions为空,则无法进行任何交互,对应逻辑为——哑铃需要在组装且配重平衡后才能使用。

请注意,AutoCheckPose按钮的功能仍旧是将物体内的所有手势添加到HandInteractions内,但不会在游戏运行时自动调用或产生作用,最初的交互列表选择Hand Interactions和交互方案Interaction Plan配置都需要自行在脚本内设定完毕。

在该实例场景中,哑铃在装上哑铃片后才能正常交互,同时拿着哑铃片的手将强制切换为哑铃片SampleBell交互方案二中的Operation Inside Object类型手势。

此处强制执行手势的接口在HandInteractor.cs脚本内。需要注意,强制更改的手势需要跟先前的手势对同一可交互物体有相同的相对位置,仅有手指表现或是手指触发逻辑(例如交互使用物体)可以不同。

public void ForceActive(InteractableObject newObj, HandInteraction newInteraction){...} 同时原先的哑铃片上也会继续保有两个可交互的Operation Inside Object手势,但需要先进行哑铃主体上的交互。

哑铃片SampleBell上的BellSample.cs脚本包含该动态操作的示例,可以阅读代码研究。

另外在InteractableObject脚本内还增加了交互锁接口,可以用来控制物体是否可以进行交互。

public void SetActiveLock(bool value) {...}

在原示例场景[2. Multiple Interaction]中增加了骰子物体SampleDice。

该物体上适配了更新的RegularShapeFit设置。

类似于Special Sphere的效果,该立方体内只需要给出一个标准的左右手交互手势,运行时可以自动适配立方体当前角度最匹配的交互位置。以每个面上有4种可能性,立方体有6个面,所以单只手的交互状态共有24种。

需要注意的是,除了正方体以外的手势无法保持每个面的交互手势相同,因此无法适用。

左右手模型根关节下的Hand上所挂载的HandDriver脚本已经修改为在电脑端Editor内适配HandDriver2.1.2的版本。为了方便在电脑端上进行测试开发,推荐更新此V1.3版本。如果暂时需要维持老版本,可以在HandDriver的串流设置页面上勾选“旧插件”选项,仍旧可以驱动旧插件让手模型正常活动。

VR Base场景内的UI中增加了适配多副手套环境的设置。如果程序在VR设备中实际运行时检测到多副手套,可以点选高亮需要连接的手套(以左右手及名称区分),两只手都选择完毕后,在左下角会出现继续按钮,由此可以进入连接检测及标定页面。

修正了物体可能在交互范围外却触发交互的bug等。

V1.2

V1.0中左右手模型的初始姿态之间存在些许差异(指关节角度),相同关节角度在左右手上的表现不同,会导致相同手势动作左右手需要分别调节。 V1.3中已解决。

V1.1

蓝牙手套新版型适配算法更新,详情请咨询公司相关业务管理。

2. 前置配置流程

Unity适用版本为2021LTS及以上。SDK目前尚为长期迭代版本,推荐在新建空项目或是已有备份的项目中进行开发,避免因某些未知错误造成难以逆转的开发损失。(以下部分为V1.0发布版)

首先请将 UDE_PicoBased_Interaction&BluetoothSDK_Vx.x UDE_InteractionSDK_Vx.x 的unitypackage文件全部导入工程中。

circle-exclamation

2.1. 蓝牙Pico集合版

2.2. 纯交互版

2.3. 报错解决

随后或许会出现若干报错,请跟随以下步骤逐步解决。

  1. 在Package Manager中安装XR InteractionToolkit。

  1. (纯交互版本请跳过此步骤)取得Pico SDK的文件夹,导入Package。

circle-exclamation
  1. 在Player Settings中,将Player->configuration->Api Compatibility Level设置为.Net Framework,随后可能会自动重启工程。若没有自动重启,请手动重启工程。

  1. (纯交互版本请跳过此步骤)最后在实际开发使用前,请将Unity平台切换为Android。

如无意外,所有报错信息至此已经处理完毕。

3. 交互分类详解

在SDK完成导入且无报错,从路径Assets->SDK->Interaction SDK->Sample Scenes内,可以找到若干示例场景,分别对应了主要几种交互类型的示例物体以及接入VR的应用场景。以下将根据通用基础部分,以及细分的示例场景来逐步介绍SDK所含的交互功能。

circle-exclamation

3.1. 可交互物体 Interactable Object

可交互物体上需要挂载InteractableObject脚本。

Hand Interactions内包含了该物体所有预先设置好的固定交互手势,每一项对应左手或右手的一个手势。下方的Auto Check Hand按钮会读取物体下的所有固定手势(Hand Interaction脚本),运行开始时也会执行自动读取。Add Virtual Hand可以在非运行时给该物体增加一个默认的手势。

Interact Priority参数为物体交互的优先级,类型为int,范围是自然数。当可交互范围内存在多个物体时,将会只能与优先级数字最小的物体产生交互,如果优先级相同,则会与最先在范围内读取到的物体交互。

Object Follow Type设置的是物体的交互表现,Instant是物体直接瞬移至手上准确的交互位置,且交互结束前不会偏移;Slow Move是物体平滑移动到交互位置;Chasing是物体会一直滞后性地朝着设定的手部交互位置移动,不会固定在手上;No Pose是无交互手势,在物体下不包含可用手势时会默认选中该选项,处于交互时物体与手部相对静止运动。

选择Slow Move及Chasing时可以进一步设置Tracking Time,指代从交互触发到物体达到手势固定位置的时间,推荐默认值为0.3秒。

最下方折叠的可选设置项是物体内可单独交互的子物体Inside Operation Part位置,默认为空,可以达成一些特殊交互。

在该选项不为空时可以设置移动时间,对应手到特殊组件上的手势所需的时间,推荐默认值为0.3秒。

3.2. 虚拟手势 Hand Interaction

上文提到在Interactable Object中点击Add Virtual Hand按钮后会在目前可交互物体的子物体下生成一个虚拟手。在Hierarchy中双击点选该虚拟手物体即可在场景中看到蓝色的虚拟手实体,可以自由移动虚拟手相对于物体的位置和旋转。交互时的手部的实际表现与虚拟手的形态一致,物体的实际位置与在虚拟手抓握交互时相同。虚拟手上的主要脚本为HandInteraction。

最上方的Relative To指代的是手势所属可交互物体的位置,会默认自动获取。Handedness是左右手选择。

Fingers Freedom设置自上而下为五指交互时手指的表现。其中Fixed为固定手势,处于交互状态下手指只能保持固定手势的姿态;Free为无手势可自由活动手指;Flexible为灵活可触发手势,在触发判断范围外可以自由活动,到了范围内则变成设定好的固定手势;Operation为交互后可使用特殊功能,指定手指的活动可以与物体上的按钮,扳机等可活动结构交互。

设置了非Free的手指在点击场景编辑器右上角的Visibility设置后,可以在场景内调节虚拟手指关节处的圆圈来给虚拟手的手指设置交互手势的弯曲姿态。同时也可以设置虚拟手的位置和旋转来达到想要的交互表现。

固定手势交互时,虚拟手上还有HandInteractionSetting脚本,来设置手势触发的判断条件。

Interact Type有AnyFinger 和 All Fingers两种,默认状态下指代五根手指中的任意手指及全部手指。Active Intense代表所选手指需要的触发强度(弯曲度),0为自然伸直,1为弯曲握紧。

如果点击了最下方的Separate Finger勾选框,能够对五根手指分别进行具体调节。Active勾选则代表采用,触发逻辑将结合Interact Type与所选手指及其分别的Active Intense进行整体判断。

Operation Inside Object的勾选需要对应Interactable Object内的Inside Operation Part使用,具体表现为交互时组件位置不动,手部将移动到指定组件上并采用该虚拟手势,在下文中将具体讲解。

3.3. 手部交互基础 Hand Interactor

该挂载于左右手根节点的HandInteractor脚本可以获取手部在开始交互与终止交互时的UnityEvent,对应为WhenHandInteract以及WhenHandDisable。

开始交互时,控制台还会输出交互信息的Log,为触发交互的手,交互物体名称及交互手势的名称。

手部默认的交互触发范围是半径为0.08的碰撞球,可以通过ActiveRange这一参数进行调节。

Shortcut Key Code为快捷键设置,在运行时按下设定的快捷键可触发最下方的Create Realtime Hand Interaction按钮。该按钮也可以直接鼠标点击触发,作用效果为在运行时,且手部处于跟可交互物体的有效范围内时,生成一个有效的固定手势预制体,储存的默认文件夹为SDK内的TempVirtual文件夹。

运行中生成的虚拟手与按钮触发时的手部动作和位置完全一致,但只会以预制体的形式保存在本地文件夹中。如果不更改已生成虚拟手预制体的名字,新生成的虚拟手预制体将会覆盖掉旧的。

使用该预制体,需要将其拖入刚才所选择的物体(如果是完全同样的物体可以共用)的根节点下作为子物体,然后为了避免预制体覆盖影响该手势,需要右键该预制体选择Perfab->Unpack Completely,然后在Hand Interaction脚本内将该虚拟手父物体挂载到Relative To中,选择所需要固定的手指关节,进行调整后,即可使用该手势。

3.4. 示例场景-基础交互 [0. Basic Interaction]

在该示例场景中提供了四种Object Follow Type的示例物体。从左到右进行分析。

SampleCube方块物体上的示例左手手势如下图所示。

实际交互表现如下,方块的Object Follow Type为Instant,所以会瞬移至正确交互位置。右手交互逻辑类似。

SampleCylinder圆柱体上左右手的固定姿势不同。

Object Follow Type为Slow Move,Tracking Time设置为0.3s,交互效果如下:

circle-exclamation

SampleChasedObject不规则物体上也各有左右手固定手势,由于设定为持续跟随手部移动的物体,所以交互手势不是固定在物体表面的姿态。

Object Follow Type为Chasing,Tracking Time设置为0.3s,交互效果如下:

SampleSphere球物体没有任何固定手势,运行时会自动将Object Follow Type设置为No Pose,只要满足交互触发设定,球物体就会跟随手部一起移动。交互效果如下:

3.5. 示例场景-交互优先级 [1. Interact Priority]

在该示例场景中提供了三种交互优先级不同的示例物体。

其中SampleStick的交互优先级参数Interact Priority设置为0,代表最高级别。所有SampleCube立方体的 Interact Priority设置为1,然后是SampleCylinder圆柱体的Interact Priority设置为2。交互表现为,当若干物体均处于可交互范围内时,只能先与交互等级最高的(0级)物体进行交互。根据不同优先级依次顺延。当拿出SampleStick后,范围内的SampleCylinder圆柱体因为优先级低于所有SampleCube立方体,因此无法进行交互。

效果演示如下:

3.6. 示例场景-多手势交互 [2. Multiple Interactions]

在该示例场景中提供了四种含有多手势或多规律交互的物体。

当一个可交互物体上左右手固定手势分别只有一个的时候,左右手与其交互的表现会选取对应手姿势。如果固定手势数量有多个,则会计算当前手的食指指尖位置与虚拟手的食指指尖的距离,然后以距离由近至远的次序遍历所有虚拟手,选择最先满足触发交互条件的虚拟手姿势作为交互手势。

居中左侧的SampleMultiShape物体上有若干个交互手势,分别在四个末端物体上,左右手各一个。当手部与物体满足交互条件时,会先从物体上位置最近的虚拟手开始做交互判断。

交互效果如下:

居中右侧的SampleStick是交互旋转判断的例子。

当物体上有若干个虚拟手,且有两个虚拟手的位置十分接近时,交互时就会判断先选择物体需要旋转的角度更小的一个。(对距离上的容忍度暂时没有明确计算)

例如在SampleStick上每只手有四个手势。以左手为例。

在长条的两个端点,都分别有虎口朝向内部和外部的两个手势。同一端点上的虚拟手位置已经十分接近了,交互就会更多判断物体需要旋转的角度更小(更便利)的手势。

交互效果如下:

最左侧的SampleComlexStick物体是一个规则形状交互的例子。

该物体的所有虚拟手上需要增加一个额外脚本RegularShapeFit

挂载此脚本后,同样点击场景编辑器右上角的Visibility设置后,可以在场景内调节规则物体的可交互范围。

以该物体的PoseLeft为例,圆柱体中心的竖直红线代表物体上可交互的范围,通过调整两端的Tramsform坐标箭头可以调整该区域的方向与大小。

脚本上挂载的TargetObject为适配的规则形状物体,此处为细圆柱体的主干部分。

StartPoint和EndPoint是该物体上代表范围起始点和结束点的本地坐标,调整坐标箭头时会自动变化,也可以手动输入坐标来配置。

Draw Radius控制场景内所画红色圆柱的半径,只起到视觉变化效果,对功能没有影响。

该设置的效果为:在圆柱体红色长实线上的任意位置可以360度适配虚拟手,实际表现为在任意位置和角度上与该圆柱体交互,交互位置均为最佳适配位置,物体不会出现额外的移动或旋转。在最初设置时虚拟手只要在放置在物体上有效交互范围内的且表现正确的任意一处即可。

同一个物体上可以根据物体形状设置多个自适应交互,判断时如果两个自适应范围覆盖且所属手相同,会先从InteractableObject的HandInteractions列表中的先后顺序选取判断。

交互效果如下:

居右的RegularSphere地球模型,在虚拟手的RegularShapeFit脚本上要勾选Special Sphere。

SpecialSphere的设置用于球形物体,在任何角度上与球形交互都能自适应交互位置。

同时还需要将Start Point和End Point都设置为(0, 0, 0),然后给虚拟手适配一个任意角度上的常规交互手势即可。

交互效果如下:

3.7. 示例场景-交互使用 [3. Interact Use]

在该示例场景中提供了三种交互时还含有额外使用功能的物体。

左侧的SampleGun枪模型,以右手为例,右手交互有两个虚拟手PoseRight和UsePoseRight,分别对应交互的起始动作和最大交互动作。需要注意的是,两个手势需要有完全一样的位置和旋转,同时除了参与交互使用的手指以外均需要有一样的姿态,避免交互时出现手势跳转或是交互表现产生偏差。

此处上下图的右手动作就对应了扣扳机的最初动作以及扳机触发时扳至底部位置时的手指动作。可以看到两个虚拟手仅只有食指表现有差别。

起始动作所属的PoseRight虚拟手上需要增加一个FingerUseInteraction脚本。

Prepose Interaction需要选择为该虚拟手的交互动作。

Trigger的选择是交互使用时物体的可活动部分。

Axis是物体活动的本地坐标方向。

Release Thresold和Active Thresold分别指的是在交互中判断释放与交互触发的阈值。以该物体为例,此处当交互程度大于等于0.7时将会判断为一次开枪,随后需要将交互程度回到小于等于0.5后,才会继续开始判断下一次的开枪。也就是保持扣下扳机并不会一直触发开枪指令。

Trigger Process Length为触发物体的可活动距离,需要在场景内自行调整物体位置,记录数值后适配。同样UsePose对应的交互动作最好也在触发物体移动到极值时进行指关节表现调整。

When Use Active是物体交互触发时运行的Unity Event。此处调用的的开枪脚本Sample Gun仅为一个简单范例,实际开发中需要根据不同物体的交互逻辑根据想要的表现自行编写。

另外虚拟手上对应需要交互的手指要设置为Operation,UsePose对应的虚拟手上可以不需要HandInteractionSetting脚本,触发判断是由Pose的虚拟手上的HandInteractionSetting配置决定的。HandInteractions中也会自动过滤掉关联的UsePose。

交互效果如下:

居中的SampleGripper物体提供了一个多手指交互的示例。此物体上可以凭借除拇指外四指中的任意一根或多根手指触发交互使用,扳机的交互值判断将由其中弯曲度最高的手指决定。

设置固定手势时仍旧要以所有手指的初始和最深交互状态为准,实际使用中四指的弯曲及交互程度可以是各有差别的。

交互效果如下:

右侧的SampleCounter交互物体与SampleGun逻辑类似,仅有一根手指参与交互使用。此物体上可以通过拇指的弯曲程度按压按钮,每次按压会让显示的数字加一。

交互表现如下:

3.8. 示例场景-物体内组件交互 [4. Interact Inside Object]

场景内提供了示例弓与箭和门物体。

SampleBow弓物体设计参照了左手弓,因此交互逻辑设定为只能左手握持右手拉弦。在物体根节点的InteractableObject脚本上,最下方的Optional选项中的Inside Operation Part赋值为弓箭内部中的拉弦固定部分Handle,Moving Time设置为默认的0.3s。

弓的左手固定手势的虚拟手为常规交互。

物体内的Inside Operation Part是可单独活动的,并且在交互时和虚拟手之间的位置需要相对静止。例如此处,拉弦时弓的主要位置不动,但弦触发的位置会变动,所以虚拟手的位置需要放在可活动组件内。由此Handle被拉动时,也能获取到正确的交互位置。

这个内部可活动组件上的虚拟手挂载的HandInteractionSetting脚本需要勾选Operation Inside Part。

最明确的表现是,物体整体不会移动,而是手移动到物体上,或是将内部组件移到可交互范围内的位置。这一条的表现如下,Moving Time代表了手移动到指定位置和返回实际位置所用的时间:

SampleBow上的BowActiveSample脚本与SampleArrow上的ArrowTipSample是两个专门为弓箭交互而写的交互控制脚本,仅作为示例参考,不建议直接拿过来复用,可以参考其内部的逻辑来开发编写相似交互,这里不多介绍。

示例弓箭的使用方法为,左手持弓,右手将箭放置在弓箭触发位置附近,箭会自动装载到弓上。随后右手触发交互并拉弓,松手后即可完成射箭过程。

完整的弓箭演示如下,箭靶仅为演示效果,没有添加到示例场景中:

file-download
12MB

SampleDoor上有四个组件内交互手势,分别是两侧门把手上的左右手。

这里将门把手做成了一个完整的整体,因此四个虚拟手都放在了这个门把手物体内。

同样地,四个虚拟手上的HandInteractionSetting的Operation Inside Object都需要勾选。Interactable Object上的Inside Operation Part设置为门把手位置。

DoorActiveSample为专门为门交互而写的交互控制脚本,仅作为示例参考。

门的交互方式为,将门把手压到底后可以将门推开,推开一点距离后就可以不需要压住门把手。关门时也需要将门把手压到底后才能完全关闭。

交互效果如下:

3.9. 示例场景-接触面交互物体 [5. Finger Press]

3.9.1. 手部交互补充 FingerPressSelector

实现此功能依靠手部根节点(与HandInteractor同级)上的FingerPressSelector脚本。被勾选的手指末端点可以参与接触面交互,未勾选的则不能交互。

位于左右手子节点中的Tip物体上的FingerPress脚本上有对应五指末端点的配置。

以左手食物指为例,在FingerPressInteractor脚本上可设置每一帧的判断次数,触发点的参考坐标以及触发球体的半径。在场景中开启Toggle Visibility后可以看到检测球体的大小和位置。

在Finger Press场景中提供了手指按压触发的几个例子。

最左侧的SampleButton物体有一个圆形的可交互平面,在物体根节点开启Toggle Visibility后可以看到触发面交互方案是从按钮表面往下。

物体根节点上挂载了FingerPressInteractable脚本

参数从上往下依次是手指悬停检测距离(Hover Detect Distance),手指悬停忽略距离(Hover Ignore Distance,忽略距离需要大于等于检测距离),接触表面悬停额外扩展检测距离(Surface Ext Hover Detect),接触表面悬停额外扩展忽略距离(Surface Ext Hover Ignore),交互终止距离(Interact Disable Distance,顺延交互表面向后),接触表面额外扩展终止交互距离(Surface Ext Interact Disable)。实际效果可以在使用中通过调试来感受。

示例按钮物体上的ButtonPos为按钮的实际触发部件。需要挂载FingerPressController脚本。

Button Base Transform为Surface组件的位置(下文会介绍)。

Quad的显示类型有两种,Pure Color(纯色)或者Sprite(精灵图)。选择Pure Color时,下方的四个颜色分别对应常规颜色(Normal Color),悬停颜色(Hover Color),触发颜色(select Color),失效颜色(Disabled Color)。相对应的,选择Sprite时,下方四张图片引用对应常规图片,悬停图片,触发图片,失效图片。

Renderer是该物体的Mesh Renderer。

另外还可以通过OnHover和OnSelect的Unity Event来监听触发。

按钮物体内与实际触发部件同一层级的Surface为触发面底部的面,开启Toggle Visibility后可以看到触发底部位置的绿色网格面。由于该触发面为圆形,所以可视化网格也为大小相同的圆形。

Surface物体上需要挂载InteractableSurface脚本。

Facing代表接触面接收触发的法线方向。从上图绿色网格所示的Local Position可以看出,Backward为Z轴的反方向,也就是按钮接受按压的一侧。如果选择Forward则为指向Z轴的正方向。

Double Sided控制面的两侧是否皆可触发。

Surface Type有三种,方形面,圆形面与无形状无限面。

选择方形面时可以设定面的大小。

圆形面可以设定圆形半径。

无限广面在场景中会根据视角位置生成面的可视化格栅。

需要注意:以按钮物体为例,挂载FingerPressController的ButtonPos把实际Button模型放在了子物体内,因为需要以该物体Pivot的世界坐标作为触发的起点位置,面物体的世界坐标为接触面可活动的末端位置。对于比较大的按钮物体,坐标会以几何中心为准,这样会造成按压只有一半距离,所以需要多一层父节点作为坐标参考。

交互表现如下:

SamplePad物体为面板型接触面,场景内展示了三种。SamplePad为纯色面板,SamplePadWithSprite为使用精灵图的面板,还有一个在UI组件中的SamplePadUI为在UI上使用的面板。

纯色面板的设置如下图,在该设置下不需要理会Quad子物体中的Sprite。

使用精灵图的面板设置如下。需要注意的是,精灵图不需要原先的Mesh Render,因此为了在非运行时不被纯色面板挡住影响视觉外观,可以点掉下方Mesh Renderer的勾。这一设置不是必须的,在运行时会自动取消勾选。

与接下来要提到的UI上的面板不同的是,SamplePadWithSprite中的Sprite子物体上运用的是常规三维坐标轴Transform,挂载精灵图的组件为Sprite Render。组件内引用的Sprite仅作为非运行时的视觉展示,运行时的图片以FingerPressController中的设置为准。

SamplePadUI放置在UI层级下,同时UI Canvas的Render Mode必须为World Space。含义为在世界空间内的UI面板上控制接触面交互物体。

SamplePadUI的Sprite子物体上运用的是Rect Transform,渲染图片的组件是UI上的Image。如果在UI面板上采用Sprite Render或是在常规物体中采用Image都会出现图片无法加载的情况,所以要根据实际运用场景来使用这两种可交互面板。

这三种Pad类型的交互表现类似,在Pure Color或是Sprite上的设置让表现不同:

3.10. 示例场景-射线UI交互 [6. Ray UI Interaction]

Ray UI Interaction场景中提供了射线使用的样例,经由XR Interaction Toolkit扩展包更改而成。

请注意,进行射线交互的一个重要前提条件是场景内需要有Tag设置为MainCamera的Camera。

3.10.1. 手部交互补充 Ray Controller

挂载于左右手根部的RayController脚本控制手指模拟手柄Trigger使用逻辑触发射线点击。

Active Ray控制是否开启射线。

Ray Active Type选项有Any Finger和All Fingers。此处的配置逻辑与抓握交互的一致,可以控制读取任意手指是否弯曲到一定程度来触发,或是某几根手指的组合来触发。默认为仅需要食指来触发。

射线开启后,仅有路径上检测到UI界面时才会显现,其余时候不显示,也不会影响其它任何交互的正常使用。

请注意,在Editor中运行示例场景测试时需要让Game窗口处于显示状态,仅通过Scene窗口射线将无法正常加载。可以如下图所示排布窗口。

以左手为例,LeftHand RayController物体下包含射线的各种配置及射线十字锚点物体,可以自行根据自己的需要更改。

射线功能由XR Interaction Toolkit提供的方案修改而成,更详细的解读可以自行查找相关资料。

SampleUI为示例的UI物体,与正常的UI区别为Canvas中的Render Mode需要设置为World Space,代表UI是放置在场景中而不是直接在摄像机上渲染。另外UI上的Graphic Raycaster脚本需要更换为Tracked Device Graphic Raycaster脚本,该脚本由XR Interaction Toolkit提供。

UI面板上的所有组件均不需要特别设置,像寻常GUI一样创建即可。示例UI上有按钮,切换键与滑动条三个示例组件。

交互效果如下:

file-download
3MB

3.11. 总结

3.11.1. LeftHandRightHand的基本结构:

手部根节点,挂载了三个关键脚本:HandInteractor(控制基本交互),FingerPressSelector(控制接触面交互启用的手指),RayController(控制射线交互)。手部的移动务必要在该根节点上进行。

  1. 关节根节点,含有控制关节活动的Hand Driver(非PC平台运行不需要理会)

  2. Mesh Renderer组件

  3. DetectArea检测交互范围(在HandInteractor脚本上控制)

  4. FingerPress指尖配置 (手指是否触发在FingerPressSelector脚本上控制)

  5. LeftHand/RightHand RayController控制射线交互(RayController脚本上控制)

3.11.2. 可交互物体的基本结构:

物体根节点,需要挂载InteractableObject脚本,Scale需要为默认的(1,1,1),可以包含自定义的碰撞体结构,以及自行编写的交互逻辑脚本。

  1. VisualPart物体实际模型部分,一般包含碰撞体,Mesh Filter,Mesh Renderer或是其它多层结构,对Scale没有要求,但位置和旋转需要为默认(0,0,0),如果根节点没有完备的碰撞体,在该部分需要设置齐全。

    • (物体内组件交互时)有单独活动逻辑的内部组件

      • 若干固定挂载HandInteraction与HandInteractionSetting脚本的虚拟手物体,且勾选了Operation Inside Object。

  2. (有手势交互时)固定挂载HandInteraction与HandInteractionSetting脚本的虚拟手物体,数量没有限制,Scale需要为默认的(1,1,1) 。如果是交互使用的需要挂载FingerUseInteraction脚本,如果是规则物体自适应的需要挂载RegularShapeFit脚本。

    • 运行时生成的代表虚拟手食指指尖位置的空物体。(不需要理会)

  3. (交互使用时)额外挂载HandInteraction脚本的虚拟手,为交互完全触发时的动作,不需要HandInteractionSetting脚本。需要被对应的FingerUseInteraction上的Prepose Interaction引用。

  4. (无手势交互时)仅需HandInteractionSetting脚本控制交互触发判断的游戏物体。

  5. 运行时生成的空物体CalculateGameobj,用于计算交互位置。(不需要理会)

3.11.3. 接触面可交互物体的结构规范:

物体根节点,需要挂载FingerPressInteractable脚本。

  • 可活动物体父节点,原始坐标为触发的初始位置,需要挂载FingerPressController脚本,脚本上的Button Base Transform要设置为面物体的Transform。物体的实际模型(Mesh Renderer)可以不在该物体上。

    • 如果父节点上没有Mesh Renderer,则该子物体上必须设置,同时需要设为FingerPressController的Renderer。

    • 如果为Quad面板型,需要有Sprite组件,非UI内时为Sprite Render,在UI内为Image。

  • Surface物体,需要挂载InteractableSurface脚本,物体的位置为可活动物体能够到达的末端位置。平面的形状与尺寸将影响触发判定和表现。

射线UI交互的结构标准规范如上述第10节中所述。

4. 交互全流程方案

4.1. Pico Swift + UDE Interaction SDK + UDE BleSDK

目前已经完全打通的流程为Pico一体机方案。用Pico的Swift为手部提供空间定位,通过蓝牙连接的方式将手套数据传入Pico设备。需要接入Pico的SDK和UDE的蓝牙SDK(蓝牙SDK已包括在unitypackage中)在交互SDK的Sample Scene文件夹中有一个示例场景VR Base该场景包含了与Pico SDK适配的XR Origin,以及对应Swift手部定位的脚本。将这个示例场景打包在Pico中后,可以通过在面板UI上用手点击按钮完成手套的信息读取和标定过程。(以下演示为PC Editor录制,仅展示操作流程)

连接所用的蓝牙SDK文档:Unity Android SDK

Last updated