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