说明
本文档是针对GitHub开源项目PicoMRTK3的学习总结。
一、MRTK3使用
MRTK3目前为公共预览版,功能还不稳定,不过基本的使用没有问题。详见MRTK3。
1、添加包体至Unity工程
(1)混合现实功能工具使用
使用混合现实功能工具导入MRTK3包体至Unity工程,工具下载地址:混合现实功能工具
1)工具首页
工具为免安装EXE,下载完成将其置于合适的路径下,创建快捷方式至桌面即可。打开以后,点击首页的Start。
2)选择Unity工程路径
所选路径即包含Assets的Unity工程路径。选择完路径后,点击Discover Features。
3)选择MRTK3包体
在MRTK3菜单右侧点击Select All全选MRTK3相关包体。
注意,由于OpenXR Plugin导入后,工程打包报错,可以暂时先不用导入OpenXR Plugin。OpenXR Plugin在Platform Support菜单下。
选择完MRTK3包体后,点击Get Features。
4)导入
点击Import便可。导入后退出工具。
2、添加示例至Unity工程
MRTK3是由一些松散耦合的单个Unity Package Manager包集合组成,内部不在包含示例场景。而是将 UnityProjects 文件夹维护在 Git 存储库的顶层,其中包含要交付的任何 Unity 项目。 目前,此文件夹包含 MRTKDevTemplate 项目,其中包含所有示例场景,并配置为与建议的最佳设置保持一致。
(1)进入微软混合现实Github页
(2)选择mrtk3分支
直连入口:mrtk3
(3)克隆或者下载压缩包
用git克隆项目或者直接下载压缩包。
(4)复制资源至Unity工程
将下载的压缩包解压后,打开UnityProjects-->MRTKDevTemplate-->Assets,将内部的Analyzers、Audio、BuildAssets、Editor、Example Assets、Prefabs、Profiles、Scenes和Scripts文件夹复制到Unity工程的Assets路径下。当然,也可以在Assets路径下创建一个名为MRTKSamples的文件夹,将以上文件夹复制于MRTKSamples文件夹下,便于管理。
二、适配PICO平台
1、PICO SDK设置
详见PICO 文档中心。
(1)导入PICO Unity Integration SDK
1)SDK下载
前往PICO SDK下载中心下载最新版本的SDK。
2)解压下载的SDK压缩包
在Unity工程Assets同级路径下,创建名为PICOUnityIntegrationSDK的文件夹,将下载的压缩包复制到此文件夹内并解压缩。之所以要放在Unity工程里,是因为后续从Unity Package Manager里导入SDK时会绑定SDK路径,为了版本管理时不遗失SDK,将SDK置于Unity工程内最为稳妥。
解压后,会得到一个包含 package.json 文件的文件夹, package.json 文件用于后续导入使用。
3)在Unity Package Manager里导入SDK
如图,点击“+”号,再次点击Add package from disk...。
4)选择 package.json 文件并导入
5)输入系统设置及升级XR Interaction Toolkit
本工程采用的Unity版本为2021.3.20f1c1,所以导入SDK后会自动弹窗提示设置输入系统及升级XR Interaction Toolkit。低版本Unity(比如2019.4.x)需要自己去Package Manager升级XR Interaction Toolkit,然后按照弹窗提示设置便可。
这里,点击Yes,然后在后续弹窗中点击I Made a Backup,Go Ahead!。之后Unity会重启,重启完成后继续进行后续设置。
6)点击Apply
点击Apply后,待Unity编译完成后,再次点击Close关闭窗口。
(2)项目配置
1)启用 PICO XR 插件
在 Project Settings 窗口中,点击 XR Plug-in Management --> 安卓设置图标,勾选PICO。
2)安卓平台其他设置
包括Company Name、Product Name 、 Version以及Other Settings里的诸项。
2、MRTK3适配PICO
(1)克隆或者下载开源项目
项目地址:PicoMRTK3。
(2)复制资源
将下载的项目解压缩后,打开其Assets,将Scripts路径下的PicoMRTK3Support文件夹复制到Unity工程的Scripts路径下。
(3)Scripting Define Symbols设置
在Project Settings-->Player-->Other Settings-->Script Compilation里进行设置,添加PICO_INSTALL和MRTK3_INSTALL。
添加完成,点击Apply,待Unity编译完成后,进行后续配置。
(4)MRTK3设置
在Project Settings-->MRTK3里进行设置。
1)配置文件设置
选择默认配置文件便可。
2)MRTK子系统设置
① AccessibilitySubsystem设置
勾选MRTK Accessibility Subsystem并配置设置资产。默认是勾选并配置好的,若没有设置,自己手动设置好,设置资产选择默认的便可。
② HandsAggregatorSubsystem设置
勾选Pico MRTK Hands Aggregator Subsystem并配置设置资产。设置资产选择默认的便可。
③ HandsSubsystem设置
勾选Subsystem for Pico Hands API。
(5)场景设置
可以复制MRTK示例中的“HandInteractionExamples”场景,在其基础上进行配置。注意,在复制出的场景里,将报错的预制件删掉。
1)添加PXR_Manager组件
在MRTK XR Rig物体上添加PXR_Manager组件,并勾选Hand Tracking。
2)配置左右手
① 手模型预制件创建
打开Packages-->PICO Integration-->Assets-->Resources-->Prefabs,将其中的HandLeft和HandRight拖至场景的Hierarchy内,并解除预制件绑定。
以左手为例,给HandLeft物体添加PicoMRTKHandVisualizer脚本组件,并配置相关参数。
以上参数中,多数为物体本身子节点,将五个手指的节点依次拖入便可。
选中物体下的l_handMesh节点,替换其材质为Packages-->MRTK Input-->Visualizers-->RiggedHandVisualizer路径下的三个材质,如下图所示。
设置完后,将HandLeft物体拖至Assets下自定义路径里创建的Prefabs文件夹下,制作成预制件。
同理,创建HandRight预制件。
② 配置左右手
选中MRTK XR Rig下的MRTK LeftHand Controller,将创建的左手预制件拖至Model Prefab处,将MRTK XR Rig下的Camera Offset物体拖至Model Parent处。
同理,配置右手。
3)修改MRTK3中的脚本
① 修改ArticulatedHandController
此脚本挂载于MRTK XR Rig下的MRTK LeftHand Controller和MRTK RightHand Controller物体上。主要是修改其中的UpdateInput方法,添加条件编译指令,修改后的方法代码如下。
/// <inheritdoc />
protected override void UpdateInput(XRControllerState controllerState)
{
base.UpdateInput(controllerState);
using (UpdateTrackingInputPerfMarker.Auto())
{
if (controllerState == null)
return;
// Cast to expose hand state.
ArticulatedHandControllerState handControllerState = controllerState as ArticulatedHandControllerState;
// If we still don't have an aggregator, then don't update selects.
if (XRSubsystemHelpers.HandsAggregator == null) { return; }
bool gotPinchData = XRSubsystemHelpers.HandsAggregator.TryGetPinchProgress(
handNode,
out bool isPinchReady,
out bool isPinching,
out float pinchAmount
);
// If we got pinch data, write it into our select interaction state.
if (gotPinchData)
{
// Workaround for missing select actions on devices without interaction profiles
// for hands, such as Varjo and Quest. Should be removed once we have universal
// hand interaction profile(s) across vendors.
// Debounce the polyfill pinch action value.
bool isPinched = pinchAmount >= (pinchedLastFrame ? 0.9f : 1.0f);
#if !PICO_INSTALL
// Inject our own polyfilled state into the Select state if no other control is bound.
if (!selectAction.action.HasAnyControls())
{
controllerState.selectInteractionState.active = isPinched;
controllerState.selectInteractionState.activatedThisFrame = isPinched && !pinchedLastFrame;
controllerState.selectInteractionState.deactivatedThisFrame = !isPinched && pinchedLastFrame;
}
if (!selectActionValue.action.HasAnyControls())
{
controllerState.selectInteractionState.value = pinchAmount;
}
// Also make sure we update the UI press state.
if (!uiPressAction.action.HasAnyControls())
{
controllerState.uiPressInteractionState.active = isPinched;
controllerState.uiPressInteractionState.activatedThisFrame = isPinched && !pinchedLastFrame;
controllerState.uiPressInteractionState.deactivatedThisFrame = !isPinched && pinchedLastFrame;
}
if (!uiPressActionValue.action.HasAnyControls())
{
controllerState.uiPressInteractionState.value = pinchAmount;
}
pinchedLastFrame = isPinched;
#else
// Debounced.
controllerState.selectInteractionState.active = isPinched;
controllerState.selectInteractionState.activatedThisFrame = isPinched && !pinchedLastFrame;
controllerState.selectInteractionState.deactivatedThisFrame = !isPinched && pinchedLastFrame;
controllerState.selectInteractionState.value = pinchAmount;
controllerState.uiPressInteractionState.active = isPinched;
controllerState.uiPressInteractionState.activatedThisFrame = isPinched && !pinchedLastFrame;
controllerState.uiPressInteractionState.deactivatedThisFrame = !isPinched && pinchedLastFrame;
controllerState.uiPressInteractionState.value = pinchAmount;
pinchedLastFrame = isPinched;
#endif
}
handControllerState.PinchSelectReady = isPinchReady;
}
}
② 修改HandConstraintPalmUp
此脚本挂载于HandMenu物体上。由于在PICO SDK里,左右手是反着的,所以需要修改脚本里的局部变量dotProduct的值,如下所示。
float dotProduct = Vector3.Dot(hand == XRNode.LeftHand ? -palmPose.Up : palmPose.Up, Camera.main.transform.forward);
三、关于升级PICO4系统手部模型异常问题解决
升级PICO4系统至5.7.1后,手部模型位置翻转,关节点扭曲,这可能是由PICO针对手势识别手部模型标准化导致的。解决方案是升级SDK至PICO最新版SDK,本文采用的是最新的2.3.0版本。
1、重新配置左右手
打开Packages-->PICO Integration-->Assets-->Resources-->Prefabs,将其中的HandLeft和HandRight拖至场景的Hierarchy内,并解除预制件绑定。
以左手为例,给HandLeft物体添加PicoMRTKHandVisualizer脚本组件,并配置相关参数。 注意别忘记删除原来的PXR_Hand脚本组件,并将子物体RayPose隐藏。
由上图可以看出,PICO对手部模型关节点名字进行了标准化命名,所以只需要对应拖入相应位置便可。
其他配置同上文中二-2-(5)-2)对应设置。
同理,创建HandRight预制件。
2、修改PicoMRTKHandVisualizer
主要修改Update中更新手部关节点部分代码,如下:
if (i == (int) HandJoint.JointWrist)
{
riggedVisualJointsArray[i].localPosition =
handJointLocations.jointLocations[i].pose.Position.ToVector3();
riggedVisualJointsArray[i].localRotation =
handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
}
else
{
//riggedVisualJointsArray[i].localRotation =
// handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
UnityEngine.Pose parentPose = UnityEngine.Pose.identity;
if (i == (int)HandJoint.JointPalm ||
i == (int)HandJoint.JointThumbMetacarpal ||
i == (int)HandJoint.JointIndexMetacarpal ||
i == (int)HandJoint.JointMiddleMetacarpal ||
i == (int)HandJoint.JointRingMetacarpal ||
i == (int)HandJoint.JointLittleMetacarpal)
{
parentPose = new UnityEngine.Pose(handJointLocations.jointLocations[1].pose.Position.ToVector3(), handJointLocations.jointLocations[1].pose.Orientation.ToQuat());
}
else
{
parentPose = new UnityEngine.Pose(handJointLocations.jointLocations[i - 1].pose.Position.ToVector3(), handJointLocations.jointLocations[i - 1].pose.Orientation.ToQuat());
}
var inverseParentRotation = Quaternion.Inverse(parentPose.rotation);
riggedVisualJointsArray[i].localRotation = inverseParentRotation * handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
}
3、恢复HandConstraintPalmUp
此脚本挂载于HandMenu物体上。由于在新版PICO SDK里,左右手被优化正常,所以需要恢复脚本里的局部变量dotProduct的值,如下所示。
float dotProduct = Vector3.Dot(palmPose.Up, Camera.main.transform.forward);
4、还存在的问题
经过以上配置后,手部模型已经可以正常显示,交互没问题。
但是左手射线还是反着的,必须左手手掌朝上才能显示射线,不影响近距离交互。这一块有小伙伴找到问题所在后请评论区留言,不胜感激。