MRが楽しい

MRやVRについて学習したことを書き残す

Mixed Reality Toolkit 3 パブリックプレビューのドキュメントを少しずつ読み解く MRTK3でのハンドトラッキング

本日は Mixed Reality Toolkit 3 の調査枠です。
Mixed Reality Toolkit 3 パブリックプレビューのドキュメントを少しずつ翻訳しつつ読み進めていきます。

Mixed Reality Toolkit 3 のドキュメント

以下のドキュメントを読み進めていきます。
docs.microsoft.com

今回は「MRTK3でのハンドトラッキング」のページを読み進めます。
docs.microsoft.com

概要

多関節のハンドジョイントデータは MRTK サブシステムによって処理されます。
これは Unity 入力システムによってネイティブに処理されていない入力データの 1 つです。

MRTK3 サブシステムと MRTK 2.x サービスとの違いについてよく知らない場合は、
MRTK3 サブシステムのアーキテクチャーに関するドキュメントを参照して、
MRTK の哲学と設計を深く掘り下げてください。
https://docs.microsoft.com/en-us/windows/mixed-reality/mrtk-unity/mrtk3-overview/architecture/subsystems

MRTK のサブシステムは複数のソースから手作業で共同データを取得し、それらをデバイスとシミュレーションコンテキスト間で機能する中央 API に集約します。
以下に HandsSubsystem サブシステムの実装を示します。

・OpenXRHandsSubsystem は OpenXR プラグインから直接ハンドデータを受け取ります。
・XRSDKHandsSubsystem は Unity の XR SDK の抽象化レイヤーからハンドデータを受け取ります
 (このレイヤーは OpenXR やその他のソースからデータをソースにしている可能性があります)。
・SyntheticHands サブシステムはシステムからの入力アクション(devicePosition、deviceRotationなど)に基づいてハンドジョイントを合成します。
 このサブシステムはエディタで入力シミュレーションを使用するときに表示されるジョイントを提供します。

これらの HandsSubsystem はハンドデータの全てのソースを中央 API に結合する HandsAggregatorSubsystem によって照会できます。

ハンドジョイントデータを直接クエリする場合は個々の HandsSubsystem からではなく HandsAggregatorSubsystem からクエリを実行することをお勧めします。
そうすることでコードはシミュレートされたデータを含む、ハンドジョイントデータの任意のソースに対して機能します。

HandsAggregatorSubsystem と HandsSubsystem は着信ハンドデータ要求を遅延評価で実行します。
ハンドデータは「クライアント」スクリプトが要求するまで照会されません。
アプリが個々のジョイントのみを要求する場合、ハンドサブシステムは遅延評価で実行され、基になる API から単一のジョイントのみを照会します。
「クライアント」がフルハンド相当のジョイントデータを要求する場合、同じフレーム内の後続の呼び出しで同じデータが再利用されます。このため、同じフレーム内の多くのジョイントを照会するコストが削減されます。
新しいフレームごとにキャッシュはフラッシュされ、後続の呼び出しはキャッシュの補充を開始します。

この仕組みにより、アプリケーションをプロファイリングしたとき、フレーム内の最初のジョイントクエリが後続のクエリよりも時間がかかることがあります。
これは最初のクエリに関連付けられたコストと、その後の「キャッシュヒット」の相対的なパフォーマンスによるものです。

摘み(Pinch)特性

HandsAggregatorSubsystem は各特定のハンドサブシステムから照会するジョイントデータに基づいて、摘み(Pinch)ジェスチャに関するいくつかの敷居値を計算します。
これらの敷居値は HandsAggregatorSubsystem 構成で構成されます。

[Pinch Open Threshold]と[Pinch Closed Threshold]は摘み(Pinch)ジェスチャの進行状況を判定する親指と人差し指の間のワールドの絶対距離を制御します。
距離が閉じた[Pinch Closed Threshold]と等しい場合、ピンチの進行状況は 1.0 になり、[Pinch Open Threshold]に等しい場合は 0.0 になります。
(これらの敷居値は現在ワールド単位ですが、まもなくユーザーの手のサイズに正規化されます)

[Hand Raise Camera FOV]は摘み(Pinch)ジェスチャを有効と見なすために、ハンドがユーザー視点の中心にどれだけ近い角度に含まれるかを判定します。
[Hand Facing Away Tolerance]はユーザーの手の回転を測定し、いつユーザーの手が反対側を向いているかを判断するための許容範囲を制御します。

コード例

// Get a reference to the aggregator.
// HandsAggregatorSubsystem への参照を取得します
var aggregator = XRSubsystemHelpers.GetFirstRunningSubsystem<HandsAggregatorSubsystem>();
// Wait until an aggregator is available.
// HandsAggregatorSubsystem が利用できるようになるまで待機します
IEnumerator EnableWhenSubsystemAvailable()
{
    yield return new WaitUntil(() => XRSubsystemHelpers.GetFirstRunningSubsystem<HandsAggregatorSubsystem>() != null);
    GoAhead();
}
// Get a single joint (Index tip, on left hand, for example)
// 単体のジョイントデータを取得する(例:左手の人差し指の指先)
bool jointIsValid = aggregator.TryGetJoint(TrackedHandJoint.IndexTip, XRNode.LeftHand, out HandJointPose jointPose);
// Get an entire hand's worth of joints from the left hand.
// 左手から手のひら全体のジョイントデータを取る。
bool allJointsAreValid = aggregator.TryGetEntireHand(XRNode.LeftHand, out IReadOnlyList<HandJointPose> joints);
// Check whether the user's left hand is facing away (commonly used to check "aim" intent)
// This is adjustable with the HandFacingAwayTolerance option in the aggregator configuration.
// handIsValid represents whether there was valid hand data in the first place!
// ユーザーの左手が反対側を向いているかどうかをチェックします(一般的に指さしの意図をチェックするために使用されます)。
// この判定敷居値は HandsAggregatorSubsystem の設定にある HandFacingAwayTolerance オプションで調整できます。
// handIsValid はそもそも有効な手のデータがあったかどうかを表します。
bool handIsValid = aggregator.TryGetPalmFacingAway(XRNode.LeftHand, out bool isLeftPalmFacingAway);
// Query pinch characteristics from the left hand.
// pinchAmount is [0,1], normalized to the open/closed thresholds specified in the aggregator configuration.
// isReadyToPinch is adjusted with the HandRaiseCameraFOV and HandFacingAwayTolerance settings in the configuration.
// 左手から掴み(Pinch)ジェスチャーの状態を問い合わせます。
// pinchAmount は 0 から 1 の値で HandsAggregatorSubsystem の構成で指定された敷居値を基に正規化されています。
// isReadyToPinch の判定は構成の HandRaiseCameraFOV と HandFacingAwayTolerance の設定で調整できます。
bool handIsValid = aggregator.TryGetPinchProgress(XRNode.LeftHand, out bool isReadyToPinch, out bool isPinching, out float pinchAmount);