共用方式為


手部追蹤 — MRTK2

手部追蹤設定檔

手部追蹤設定檔位於輸入系統設定檔下。 它包含自訂手部表現的設定。

手部追蹤檔案

關節預製件

接頭預製件是用簡單的預製件來視覺化的。 狀接頭和食指接頭特別重要,擁有各自的預製件,而其他接頭則共用相同的預製件。

預設情況下,手動接頭預製件是簡單的幾何基元。 這些都可以如願更換。 若完全未指定預製件,則會建立空的 GameObject

警告

避免在 joint 預製件中使用複雜腳本或昂貴的渲染,因為 joint 物件會在每一幀都被轉換,且可能帶來顯著的效能負擔!

預設手部關節表示 聯合唱片公司
關節式手關節 輸入手關節

手工網狀預製件

若手部追蹤裝置提供完整定義的網格資料,則使用手部網格。 預製件中可渲染的網格會被裝置資料取代,因此像立方體這樣的虛擬網格就足夠了。 預製件的材料用於手工網格。

輸入手部網格

手部網格顯示可能會明顯影響效能,因此只要取消勾選 啟用手部網格視覺化 選項,就可以完全關閉。

手部視覺化設定

手部網格與手部關節視覺化可分別透過 手部網格視覺化模式手部關節視覺化模式 來關閉或開啟。 這些設定是針對應用程式模式的,意即在編輯器 (中開啟部分功能,透過編輯器內模擬看到關節,例如) ,但在玩家建構) 部署到裝置 (時則關閉相同功能。

請注意,通常建議在編輯器 (開啟手部關節視覺化功能,這樣在編輯器內模擬時會顯示手部關節的) 位置;同時在播放器 (中關閉手部關節視覺化和手部網格視覺化,因為這會造成效能) 影響。

腳本編寫

每個手關節 MixedRealityPose的輸入系統可請求位置與旋轉。

或者系統允許存取跟隨關節的 遊戲物件 。 如果其他 GameObject 需要持續追蹤一個接點,這會很有用。

可用接頭列於列舉中 TrackedHandJoint

注意事項

當手部追蹤中斷時,關節物件會被摧毀! 確保使用聯合物件的腳本能優雅地處理此 null 情況,以避免錯誤!

存取特定的手型控制器

通常會使用特定的手型控制器,例如在處理輸入事件時。 此時可直接透過介面向裝置 IMixedRealityHand 請求聯合資料。

控制器的輪詢聯合姿勢

如果請求的接點因某些原因無法使用,函式會 TryGetJoint 回傳 false 。 此時所得姿態為 MixedRealityPose.ZeroIdentity

public void OnSourceDetected(SourceStateEventData eventData)
{
  var hand = eventData.Controller as IMixedRealityHand;
  if (hand != null)
  {
    if (hand.TryGetJoint(TrackedHandJoint.IndexTip, out MixedRealityPose jointPose)
    {
      // ...
    }
  }
}

手部視覺化器的關節轉換

可向 控制器視覺化器請求聯合物件。

public void OnSourceDetected(SourceStateEventData eventData)
{
  var handVisualizer = eventData.Controller.Visualizer as IMixedRealityHandVisualizer;
  if (handVisualizer != null)
  {
    if (handVisualizer.TryGetJointTransform(TrackedHandJoint.IndexTip, out Transform jointTransform)
    {
      // ...
    }
  }
}

簡化的聯合資料存取

若未提供特定控制器,則提供工具類別以便方便存取手關節資料。 這些功能會要求目前追蹤的第一個可用手持裝置進行聯合資料。

來自 HandJointUtils 的輪詢聯合姿勢

HandJointUtils 是一個靜態類別,查詢第一個主動的手持裝置。

if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
{
    // ...
}

從手部聯合服務的關節轉換

IMixedRealityHandJointService 保留一組持續存在的 GameObjects 來追蹤關節。

var handJointService = CoreServices.GetInputSystemDataProvider<IMixedRealityHandJointService>();
if (handJointService != null)
{
    Transform jointTransform = handJointService.RequestJointTransform(TrackedHandJoint.IndexTip, Handedness.Right);
    // ...
}

手部追蹤事件

如果不希望直接從控制器查詢資料,輸入系統也會提供事件。

聯合活動

IMixedRealityHandJointHandler 負責關節位置的更新。

public class MyHandJointEventHandler : IMixedRealityHandJointHandler
{
    public Handedness myHandedness;

    void IMixedRealityHandJointHandler.OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData)
    {
        if (eventData.Handedness == myHandedness)
        {
            if (eventData.InputData.TryGetValue(TrackedHandJoint.IndexTip, out MixedRealityPose pose))
            {
                // ...
            }
        }
    }
}

網狀事件

IMixedRealityHandMeshHandler 處理關節式手網的變更。

請注意,手部網格預設並非啟用。

public class MyHandMeshEventHandler : IMixedRealityHandMeshHandler
{
    public Handedness myHandedness;
    public Mesh myMesh;

    public void OnHandMeshUpdated(InputEventData<HandMeshInfo> eventData)
    {
        if (eventData.Handedness == myHandedness)
        {
            myMesh.vertices = eventData.InputData.vertices;
            myMesh.normals = eventData.InputData.normals;
            myMesh.triangles = eventData.InputData.triangles;

            if (eventData.InputData.uvs != null && eventData.InputData.uvs.Length > 0)
            {
                myMesh.uv = eventData.InputData.uvs;
            }

            // ...
        }
    }
}

已知問題

.NET Native

目前已知使用 .NET 後端的 Master 建置有問題。 在 .NET Native 中,IInspectable指標無法使用 Marshal.GetObjectForIUnknown. MRTK 利用此技術取得 SpatialCoordinateSystem 以接收平台的手部與眼睛資料。

我們已在原生的 Mixed Reality Toolkit 倉庫中提供了 DLL 原始碼作為解決方法。 請依照 README 中的指示,將產生的二進位檔複製到 Unity 資產中的 Plugins 資料夾。 之後,MRTK 提供的 WindowsMixedRealityUtilities 腳本會幫你解決這個變通方法。

如果你想建立自己的 DLL 或將此變通方法納入現有 DLL,該變通核心如下:

extern "C" __declspec(dllexport) void __stdcall MarshalIInspectable(IUnknown* nativePtr, IUnknown** inspectable)
{
    *inspectable = nativePtr;
}

以及它在你的 C# Unity 程式碼中的使用:

[DllImport("DotNetNativeWorkaround.dll", EntryPoint = "MarshalIInspectable")]
private static extern void GetSpatialCoordinateSystem(IntPtr nativePtr, out SpatialCoordinateSystem coordinateSystem);

private static SpatialCoordinateSystem GetSpatialCoordinateSystem(IntPtr nativePtr)
{
    try
    {
        GetSpatialCoordinateSystem(nativePtr, out SpatialCoordinateSystem coordinateSystem);
        return coordinateSystem;
    }
    catch
    {
        UnityEngine.Debug.LogError("Call to the DotNetNativeWorkaround plug-in failed. The plug-in is required for correct behavior when using .NET Native compilation");
        return Marshal.GetObjectForIUnknown(nativePtr) as SpatialCoordinateSystem;
    }
}