手部追蹤 — MRTK2

手部追蹤設定檔

[手部追蹤] 設定檔位於[輸入系統] 設定檔下。 其中包含自訂手部標記法的設定。

Hand Tracking Profile

聯合預製專案

使用簡單預製專案將聯合預製專案視覺化。 「手掌」和「索引指」聯結具有特殊重要性,而且擁有自己的預製專案,而所有其他聯合則共用相同的預製專案。

根據預設,手部接合預製專案是簡單的幾何基本類型。 如有需要,可以取代這些專案。 如果未指定預製專案,則會改為建立空 的 GameObjects

警告

請避免在聯合預製專案中使用複雜的腳本或昂貴的轉譯,因為聯結物件會在每一個畫面上轉換,而且可能會有顯著的效能成本!

預設手部聯合標記法 聯合標籤
Articulated hand joints Input Hand joints

手部網格預製專案

如果手部追蹤裝置提供完整定義的網格資料,則會使用手部網格。 預製物件中可轉譯的網格會由來自裝置的資料取代,因此立方體之類的虛擬網格就已足夠。 預製專案材質用於手部網格。

Input Hand Mesh

手部網格顯示器可能會有明顯的效能影響,因此可以取消核取 [啟用手部Mesh視覺效果] 選項來完全停用。

手部視覺效果設定

可以分別透過 [手部Mesh視覺效果模式] 設定和 [手部聯合視覺效果模式] 設定來關閉或開啟手部網格和手部聯合視覺效果。 這些設定是應用程式模式特定的設定,這表示在編輯器 (中開啟某些功能,以查看與編輯器內模擬的聯結,例如,在部署至播放機組建中的裝置 (時,) 同時關閉相同的功能) 。

請注意,通常建議在編輯器 (中開啟手部聯合視覺效果,讓編輯器內模擬顯示手部接合) 的位置,以及讓手部聯合視覺效果和手部網格視覺效果在玩家 (關閉,因為它們會產生效能點擊) 。

指令碼

每個個別手部接合都可以從輸入系統要求位置和旋轉。 MixedRealityPose

或者,系統允許存取接合之後的 GameObject 。 如果另一個 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))
            {
                // ...
            }
        }
    }
}

Mesh事件

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 後端的主要組建有已知問題。 在.NET Native中, IInspectable 指標無法使用 從原生封送處理到 Managed 程式碼 Marshal.GetObjectForIUnknown 。 MRTK 會使用此來取得 SpatialCoordinateSystem ,以便從平臺接收手部和眼睛資料。

我們已在原生Mixed Reality工具組存放庫中,提供 DLL 來源作為此問題的因應措施。 請遵循讀我檔案中的指示,並將產生的二進位檔複製到 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;
    }
}