ハンド トラッキング — MRTK2

ハンド トラッキング プロファイル

"ハンド トラッキング プロファイル" は、"入力システム プロファイル" の下にあります。 これには、手による表現をカスタマイズするための設定が含まれています。

ハンド トラッキング プロファイル

関節プレハブ

関節プレハブは、単純なプレハブを使用して視覚化されます。 "手のひら" と "人差し指" の関節は特に重要であり、独自のプレハブを持っていますが、他のすべての関節は同じプレハブを共有しています。

既定では、手関節プレハブは単純な幾何プリミティブです。 これらは、必要に応じて置き換えることができます。 プレハブがまったく指定されていない場合は、代わりに空の GameObjects が作成されます。

警告

関節オブジェクトはすべてのフレームで変換され、パフォーマンス コストが大きくなる可能性があるため、関節プレハブでは複雑なスクリプトや高負荷のレンダリングは使用しないようにしてください。

既定の手関節表現 関節ラベル
多関節ハンドジョイント 入力ハンド ジョイント

ハンド メッシュ プレハブ

ハンド メッシュは、完全に定義されたメッシュ データがハンド トラッキング デバイスによって提供される場合に使用されます。 プレハブでレンダリング可能なメッシュは、デバイスからのデータによって置き換えられるため、キューブなどのダミー メッシュで十分です。 プレハブの素材は、ハンド メッシュに使用されます。

入力ハンド メッシュ

ハンド メッシュ表示は、パフォーマンスに大きな影響を与える可能性があります。そのため、[Enable Hand Mesh Visualization](ハンド メッシュの視覚化を有効にする) オプションをオフにして、完全に無効にすることができます。

手の視覚化の設定

ハンド メッシュと手関節の視覚化は、それぞれ "ハンド メッシュの視覚化モード" 設定と "手関節の視覚化モード" 設定によって無効または有効にすることができます。 これらの設定は、アプリケーションモードに固有です。つまり、エディター使用中はいくつかの機能を有効にし (たとえば、エディター内シミュレーションで関節を見るため)、デバイスへのデプロイ時には同じ機能を無効にすることができます (プレーヤー ビルドで)。

一般に、エディターでは手関節の視覚化を有効にすることをお勧めします (エディター内シミュレーションで、手関節の位置が表示されるように)。また、プレーヤーでは手関節の視覚化もハンド メッシュの視覚化も無効にすることをお勧めします (パフォーマンスへの影響が生じるため)。

スクリプト

位置と回転は、個別の手関節の入力システムから MixedRealityPose として要求できます。

または、関節に追従する GameObjects にアクセスできます。 これは、別の GameObject が関節を継続して追跡する必要がある場合に便利であることがあります。

使用可能な関節の一覧は、TrackedHandJoint 列挙型にあります。

Note

ハンド トラッキングが失われると、関節オブジェクトは破棄されます。 エラーを回避するために、関節オブジェクトを使用しているすべてのスクリプトが 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 バックエンドを使用するマスター ビルドには既知の問題があります。 .NET Native では、Marshal.GetObjectForIUnknown を使用して、IInspectable ポインターをネイティブ コードからマネージド コードにマーシャリングすることはできません。 MRTK はこれを使用して を SpatialCoordinateSystem 取得し、プラットフォームから手と目のデータを受信します。

この問題の回避策として、ネイティブ Mixed Reality ツールキット リポジトリで 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;
    }
}