MRが楽しい

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

MRTK v2のドキュメントを少しずつ読み解く入力システムのコントローラー/ポインター/フォーカス

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

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

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200203084817j:plain

コントローラー、ポインター、フォーカス

コントローラー、ポインター、およびフォーカスは入力システム上に構築される高レベルの仕組みです。
これらはシーン内のオブジェクトと対話するためのメカニズムの大部分を提供します。

コントローラー

コントローラーは物理的なコントローラーの表現を行います。(6DoFコントローラーや関節のある手など)
これらはデバイスマネージャーによって作成され、対応する基盤システムと通信し、そのデータを MRTK のデータとイベントに変換する役割を果たします。

例えば、Windows Mixed Reality プラットフォームでは、WindowsMixedRealityArticulatedHand が Windows ハンドトラッキングAPIとのインターフェイスを担当します。
手の関節、ポーズ、およびその他のプロパティに関する情報を取得するコントローラーです。

このデータを関連する MRTK イベントに変換し、TryGetJointPose が正しいデータを返すように独自の内部状態を更新します。
(例えば、RaisePoseInputChanged または RaiseHandJointsUpdated を呼び出します)

一般的に、コントローラーのライフサイクルには以下が含まれます。

1.コントローラは新しいソースの検出時にデバイスマネージャによって作成されます。(例えば、手の検出と追跡の開始)
2.コントローラーのUpdate()ループで、基盤システムの API を呼び出します。
3.その Update() ループで入力システム自体を直接呼び出すことにより、入力イベントの変更を発生させます。(例えば、HandMeshUpdatedまたはHandJointsUpdatedを発生させます)

ポインターとフォーカス

ポインターはゲームオブジェクトと対話するために使用されます。
このセクションではポインターの作成方法、更新方法、フォーカスされているオブジェクトの判別方法について説明します。
また、存在する様々な種類のポインターと、それらがアクティブになっているシナリオについても説明します。

ポインターのカテゴリー

通常、ポインターは次のいずれかのカテゴリに分類されます。

Far Pointers

Far pointers はユーザーから遠く離れたオブジェクトと対話するために使用されます。
これらのタイプのポインターは通常、遠くまで届くラインをキャストし、ユーザーがそれら遠くのオブジェクトを操作できるようにします。

Near Pointers

Near pointers はユーザーに近いオブジェクトを掴む/触れる/操作するために使用されます。
これらのタイプのポインターは近くにあるオブジェクトを以下の方法で探すことでオブジェクトとやり取りします。
・近距離でのレイキャストを行う
・近くにあるオブジェクトを探すための球状のキャストを行う
・掴む/触れることができると考えられるオブジェクトのリストを列挙する。

Teleport Pointers

Teleport pointers はテレポーテーションシステムにプラグインして、ユーザーをポインターがターゲットとする場所に移動することを処理します。

ポインターメディエーション

単一のコントローラーに複数のポインターを持たせることができるため、どのポインターをアクティブにするかを仲介するコンポーネントが存在します。
(例えば、関節のある手は「Near Pointer」と「Far Pointer」の両方の相互作用ポインターを持つことができます)

これは DefaultPointerMediator によって処理され、全てのポインターの状態に基づいて、どのポインターがアクティブであるかを決定します。
この機能の役割の1つは「Near Pointer」がオブジェクトの近くにあるとき、「Far Pointer」を無効にすることです。

「Pointer Profile」の PointerMediator プロパティを変更することにより、ポインターメディエーターの代替実装を提供することができます。

ポインターを無効にする方法

ポインターメディエーターは全てのフレームで実行するため、全てのポインターのアクティブ/非アクティブ状態を制御します。
従って、コードでポインターの IsInteractionEnabled プロパティを設定しても、ポインターのメディエーターによってフレームごとに上書きされます。

代わりに、PointerBehavior を指定することで、ポインタを自分でオンにするかオフにするかを制御できます。
これは、デフォルトの FocusProvider および DefaultPointerMediator を使用している場合にのみ機能することに注意してください。

例:MRTKでハンドレイを無効化する

次のコードは MRTK でのハンドレイをオフにします。

// Turn off all hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

// Turn off hand rays for the right hand only
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);

f:id:bluebirdofoz:20200203084926j:plain

次のコードはハンドレイを MRTK のデフォルトの動作に戻します。

PointerUtils.SetHandRayPointerBehavior(PointerBehavior.Default);

f:id:bluebirdofoz:20200203084936j:plain

次のコードは掴むことができるかどうかに関係なく、強制的にハンドレイをオンにします。

// Turn off all hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOn);

f:id:bluebirdofoz:20200203084951j:plain

PointerUtils/TurnPointersOnOff を参照するとより多くの例があります。
microsoft.github.io
microsoft.github.io

FocusProvider

FocusProvider は全てのポインターのリストを反復処理し、各ポインターに対してフォーカスされたオブジェクトが何であるかを把握します。

Update() 呼び出し毎に以下のことを行います。

1.レイキャストによって全てのポインターを更新し、ポインターのヒット検出を実行します。
(例えば、球体ポインターは SphereOverlap raycastMode を指定できるため、FocusProvider は球体ベースのコリジョンを実行します)
2.ポインタごとにフォーカスされたオブジェクトを更新します。
(オブジェクトがフォーカスを取得した場合、それらのオブジェクトに対するイベントもトリガーします。例えば、オブジェクトがフォーカスを失った場合、Focus Lost のイベントなど)

ポインターの構成とライフサイクル

ポインターは「Input System Profile」の Pointer セクションで構成できます。

ポインターのライフサイクルは一般に以下のとおりです。

1.デバイスマネージャーはコントローラーの存在を検出します。
そして、RequestPointers への呼び出しを介して、コントローラに関連付けられたポインタのセットを作成します。
2.FocusProvider は Update() で全ての有効なポインターを反復処理し、関連するレイキャストまたはヒット検出ロジックを実行します。
これは、特定の各ポインターによってフォーカスされるオブジェクトを判別するために使用されます。
複数の入力ソースを同時にアクティブにすることができるため、同時にフォーカスを持つ複数のオブジェクトを持つこともできます。(例えば、両手がアクティブになるなど)
3.デバイスマネージャーはコントローラーソースが失われたことを検出すると、失われたコントローラーに関連付けられたポインターを破棄します。