ハンド メニュー — MRTK3
手のメニューを使用すると、ユーザーは頻繁に使用される関数の手で接続された UI を表示できます。 これらは通常、クイック アクションを提供する小さな ボタン グループ です。 ただし、情報や設定を表示するためのより複雑なレイアウトが、手のメニューとしてユーザーに提供される場合があります。多くの場合、手からメニューを "引き裂く" オプションを使用して、世界に固定します。
[手] メニューには、[フラット ハンドが必要] オプションと [視線入力のアクティブ化を使用する] オプションが用意されており、他のオブジェクトとの対話中に誤ったアクティブ化を防ぐことができます。 これらのオプションを使用して、不要なアクティブ化を防ぐことをお勧めします。
シーンとプレハブの例
テンプレート プロジェクトを使用している場合は、HandConstraintPalmUp
スクリプトを使用して、ハンド メニューのいくつかの一般的な構成をHandMenuExamples.unity
に示します。
HandMenuLarge
このプレハブは、長い対話時間を必要とする大規模または複雑な UI の例を示しています。 この種類の UI では、使いやすさを向上させ、腕の疲労を回避するために、手動ドロップでメニューをワールド ロックすることをお勧めします。 この例では、メニューをワールド ロックする 'grab and pull' もサポートしています。
この例では、 OnFirstHandDetected() イベントで MenuContent オブジェクトをアクティブ化することで、メニューが表示され、非表示になります。 OnLastHandLost() イベントを使用すると、閉じるボタンがアクティブになり、配置アニメーションがトリガーされます。 アニメーションは単純なスケーリングの変動です。 OnLastHandLost() イベントで MenuContent を非表示にしていないため、手が表示されないと、メニューは自動的にワールド ロックされます。 [Palm Up] セクションの値は、手の下にドラッグしすぎずにメニューをワールド ロックするように最適化されています。

この例では、メニューの下部領域にグラブ可能なバーと自動ワールド ロック動作を提供します。 ユーザーは、手からメニューを明示的にデタッチし、これをつかんで世界に配置できます。 これを実現するために、ObjectManipulator の ManipulationStarted() イベントで SolverHandler.UpdateSolvers を無効にします。 それ以外の場合、HandConstraint ソルバーは手の位置の近くにメニューを配置しようとするため、メニューをデタッチできません。 また、HandConstraintPalmUp.StartWorldLockReattachCheckCoroutine を使用して、ユーザーが手を上げてメニューを手に再アタッチできるようにします。
最後に、閉じるボタンは、HandConstraint ソルバーの機能を復元するために SolverHandler.UpdateSolvers を再アクティブ化する必要があります。
スクリプト
HandConstraint
動作は、追跡対象のオブジェクトを手の制約付きコンテンツ (手の UI、メニューなど) に対して安全な領域に制限するソルバーを提供します。安全なリージョンは、手と交差しない領域と見なされます。
HandConstraintPalmUp
と呼ばれるHandConstraint
の派生クラスも含まれており、手のひらがユーザーに向いているときにソルバー追跡オブジェクトをアクティブ化する一般的な動作を示します。
その他のドキュメントについては、各 HandConstraint
プロパティで使用できるヒントを参照してください。 いくつかのプロパティについて、以下で詳しく説明します。
セーフ ゾーン: セーフ ゾーンは、コンテンツを制限するハンドの場所を指定します。 手との重複を避け、対話品質を向上させるために、コンテンツをウルナー側に配置することをお勧めします。 安全ゾーンは、カメラのビューに直交する平面に投影された手の向きと、手の周囲の境界ボックスに対するレイキャストによって計算されます。 セーフ ゾーンは、
XRNode
で動作するように定義されます。 各セーフ ゾーンが異なるコントローラーの種類で表す内容を調することをお勧めします。カメラに向くまで手をつながってください このアクティブな場合、カメラに向いているときにメニューが視線入力と十分に揃うまで、ソルバーは手の回転に従います。 この作業を行うには、ソルバーの
GazeAlignment
角度が異なるため、HandConstraintSolver
のSolverRotationBehavior
をLookAtTrackedObject
からLookAtMainCamera
に変更します。
アクティブ化イベント: 現在、
HandConstraint
は 4 つのアクティブ化イベントをトリガーします。 これらのイベントは、さまざまな組み合わせで使用して、一意のHandConstraint
動作を作成できます。- OnHandActivate: 手が IsHandActive メソッドを満たすとトリガーされます。
- OnHandDeactivate: IsHandActive メソッドが満たされなくなったときにトリガーされます。
- OnFirstHandDetected: 手の追跡状態がビュー内の手からビューの最初の手に変わるときに発生します。
- OnLastHandLost: 手の追跡状態が、少なくとも 1 つの手のビューからビュー内の手に変わるときに発生します。
ソルバーのアクティブ化/非アクティブ化ロジック: 現在、
HandConstraintPalmUp
ロジックをアクティブ化および非アクティブ化するための推奨事項は、オブジェクトを無効または有効にするのではなく、SolverHandler
のUpdateSolver
値を使用して行うことです。 これは、添付されたメニューの ManipulationHandler "OnManipulationStarted/Ended" イベントの後にトリガーされるエディター ベースのフックを使用して、サンプル シーンで確認できます。-
ハンド制約ロジックの停止: ハンド制約付きオブジェクトを停止するように設定する (アクティブ化/非アクティブ化ロジックを実行しない) 場合は、HandConstraintPalmUp を無効にするのではなく、UpdateSolver を False に設定します。
- 視線入力ベース (または非視線入力ベース) の再アタッチ ロジックを有効にする場合は、その後に
HandConstraintPalmUp.StartWorldLockReattachCheckCoroutine()
関数を呼び出します。 これにより、"IsValidController
" 条件が満たされた場合に引き続きチェックされるコルーチンがトリガーされ、UpdateSolver が True に設定されます (または、オブジェクトが無効になった場合)。
- 視線入力ベース (または非視線入力ベース) の再アタッチ ロジックを有効にする場合は、その後に
- 手制約ロジックの開始: 手の制約付きオブジェクトを設定して(アクティブ化条件を満たしているかどうかに基づいて) 手の後を再び開始しようとすると、SolverHandler の UpdateSolver を true に設定します。
-
ハンド制約ロジックの停止: ハンド制約付きオブジェクトを停止するように設定する (アクティブ化/非アクティブ化ロジックを実行しない) 場合は、HandConstraintPalmUp を無効にするのではなく、UpdateSolver を False に設定します。
-
ロジックの再アタッチ: 現在、
HandConstraintPalmUp
は、SolverHandler
のUpdateSolver
が True であるかどうかに関係なく、追跡対象のポイントにターゲット オブジェクトを自動的に再アタッチできます。 これは、HandConstraintPalmUp
のStartWorldLockReattachCheckCoroutine()
関数がワールド ロックされた後に呼び出すことによって行われます (この場合は、SolverHandler の UpdateSolver を実質的に False に設定します)。