本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。
MRTKv2のGuidesドキュメント
以下のドキュメントを読み進めていきます。
microsoft.github.io
以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io
本記事では以下のページを読み進めます。
microsoft.github.io
ハンドトラッキング
スクリプティング
手の位置と回転は MixedRealityPose として、個々の手の関節の入力システムから要求できます。
あるいはジョイントに従う GameObject へのアクセスを許可します。
これは別の GameObject がジョイントを継続的に追跡する必要がある場合に役立ちます。
使用可能なジョイントは TrackedHandJoint 列挙型にリストされています。
microsoft.github.io
所定のハンドコントローラーへのアクセス
入力イベントを処理する場合などに、特定のハンドコントローラーが利用できることがあります。
この場合、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 のセットを保持します。
IMixedRealityHandJointService handJointService = null; if (CoreServices.InputSystem != null) { var dataProviderAccess = CoreServices.InputSystem as IMixedRealityDataProviderAccess; if (dataProviderAccess != null) { handJointService = dataProviderAccess.GetDataProvider<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ネイティブ
現在、.NETバックエンドを使用したマスタービルドには既知の問題があります。
.NET Nativeでは、Marshal.GetObjectForIUnknown を使用して IInspectable ポインターをネイティブコードからマネージコードにマーシャリングできません。
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; }
[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; } }