MRTK3在PICO4上的使用小结

说明

        本文档是针对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相关包体。

扫描二维码关注公众号,回复: 16508328 查看本文章

        注意,由于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页

        地址:MixedRealityToolkit-Unity

(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、还存在的问题

        经过以上配置后,手部模型已经可以正常显示,交互没问题。

        但是左手射线还是反着的,必须左手手掌朝上才能显示射线,不影响近距离交互。这一块有小伙伴找到问题所在后请评论区留言,不胜感激。

猜你喜欢

转载自blog.csdn.net/qq_40364278/article/details/131943651
今日推荐