Godot に既存の XR プロジェクトがある場合は、新しい別のプロジェクトを開始しなくても Android XR のサポートを追加できます。一部の手順はすべてのプロジェクトで必須ですが、プロジェクトで使用する XR 機能によっては省略可能な手順もあります。手順全体を通して、Android XR のサポートを追加した複数のオープンソースの Godot XR プロジェクトへのリンクと、特定の機能を有効にするために必要な変更を示す関連するプルリクエストへのリンクを掲載しています。
すべてのプロジェクトに必要な手順
プロジェクトでサポートされている XR 機能の種類に関係なく、次のトピックの手順を完了してください。その後、省略可能な手順のリストに記載されている機能を確認して、プロジェクトに追加の作業が必要かどうかを判断します。
Godot と Godot OpenXR Vendors プラグインを更新する
プロジェクトを最新の必須バージョンに更新し、Android XR 用にプロジェクトの設定を構成する手順は次のとおりです。
- Godot のバージョンを 4.6.2 以降に更新します。プロジェクトで追加のサポートが必要な場合は、新しいバージョンへの移行に関するドキュメントをご覧ください。
アセットストア、アセット ライブラリ、または GitHub のリポジトリから、Godot OpenXR Vendors Plugin バージョン 5.1 以降をダウンロードします。
Android XR 用にプロジェクトの設定を構成します。
- Android XR 用のエクスポート プリセットを追加します。
- [Use Gradle Build] を有効にします。
- [XR Features] セクションで、[XR Mode] に [OpenXR] を選択し、[Enable AndroidXR Plugin] を選択します。
ハンド トラッキングのサポートを追加
コントローラを使用できる場合もありますが、Android XR ヘッドセットと XR グラスの主な入力方法はハンド トラッキングです。可能であれば、Godot プロジェクトにハンド トラッキングのサポートを追加する必要があります。
ハンド トラッキングのサポートを追加する: プロジェクト設定を行う
まず、次の手順に沿ってプロジェクト設定を行い、ハンド トラッキングとそれに関連する OpenXR 拡張機能を有効にします。
- プロジェクトの設定を開き、[General] > [XR] > [OpenXR] に移動します。
[拡張機能] セクションで、[ハンド トラッキング] と [ハンド インタラクション プロファイル] を選択します。
[Extensions] セクションで [Meta] サブセクションを見つけ、[Hand Tracking Mesh] と [Hand Tracking Aim] を選択します。
ハンド トラッキングのサポートを追加する: コントローラ ノードを追加して構成する
ハンド トラッキング用の既存の XRController3D ノードを動的に変更するのではなく、ハンドモデルのトラッキングと表示、およびハンド トラッキング エイム拡張機能からの入力の処理を行うコントローラ ノードを追加します。
XROrigin3Dノードに 3 つのXRController3Dノードを追加します。- 1 つは「HandTrackingLeft」という名前にし、トラッカー プロパティを
/user/hand_tracker/leftに設定します。 - もう 1 つの名前を「HandTrackingRight」にし、トラッカー プロパティを
/user/hand_tracker/rightに設定します。 - 最後の名前を「HandTrackingAimLeft」にし、トラッカー プロパティを
/user/fbhandaim/leftに設定します。
プロジェクトの元の
XRController3Dノードの名前が「XRController3D_left」と「XRController3D_right」の場合、シーンは次のようになります。
- 1 つは「HandTrackingLeft」という名前にし、トラッカー プロパティを
HandTrackingLeft と HandTrackingRight のシグナル
tracking_changedを、対応するコントローラ トラッカー(前の例では XRController3D_left と XRController3D_right)の可視性を更新する個々の関数に接続します。たとえば、HandTrackingLeft のシグナルに接続された関数は次のようになります。
func _on_hand_tracking_left_hand_tracking_changed(tracking): $XROrigin3D/XRController3D_left.visible = not trackingハンド トラッキング コントローラ ノードの [Show When Tracked] プロパティを有効にします。
これで、ユーザーがハンド トラッキングを使用しているかコントローラを使用しているかに応じて、コントローラ モデルとハンド トラッキング モデルを視覚的に切り替えることができます。
ハンド トラッキング コントローラ ノードの子として
OpenXRFbHandTrackingMeshノードを追加します。これらの
OpenXRFbHandTrackingMeshノードの子としてXRHandModifier3Dノードを追加し、正しい Hand Tracker プロパティが設定されていることを確認して、リアルタイムのハンド トラッキング データをモデルに適用します。
ハンド トラッキングのサポートを追加: OpenXR アクション マップでハンド インタラクション プロファイルを設定
次に、OpenXR アクション マップで手のインタラクション プロファイルを設定します。
- エディタの下部にある [OpenXR Action Map] メニューを開きます。
- Galaxy XR コントローラとの互換性の問題を回避するため、Simple Controller プロファイルを削除します。
- [プロファイルを追加] をクリックし、[手の操作] を選択して、[OK] をクリックします。
このプロファイルを 1 つ以上のアクション セットに自由にマッピングします。
アプリの要件によっては、ハンド トラッキングによるユーザー入力の処理方法も調整する必要があります。
ハンド トラッキングのサポートを追加する: Android XR のメニュー ジェスチャーを設定する
最後に、Android XR のメニュー ジェスチャーを実装できます。これにより、プレーヤーの左手がメニュー ジェスチャーを行うのに正しい位置にあるときにアイコンが表示され、ユーザーがジェスチャーを行うとメニューが表示または非表示になります。この処理には、先ほど追加した HandTrackingAimLeft ノードを使用します。
左手のハンド トラッキング ノードに、選択したアイコンを表示するビルボードの四角形を追加します(前の手順で追加したコントローラ ノードの次の画像の MenuIcon ノードを参照)。
HandTrackingAimLeft の
button_pressedシグナルとbutton_releasedシグナルを、次のような関数に接続します。@onready var menu_icon: MeshInstance3D = $XROrigin3D/HandTrackingLeft/MenuIcon func _on_hand_tracking_aim_left_button_pressed(p_name): if p_name == "menu_pressed": toggle_menu() elif p_name == "menu_gesture": if OS.has_feature("androidxr"): menu_icon.visible = true func _on_hand_tracking_aim_left_button_released(p_name): if p_name == "menu_gesture": menu_icon.visible = false
特定の機能の省略可能な手順
プロジェクトに必要な手順を完了したら、アプリの要件と機能に応じて、特定の機能に追加の作業が必要かどうかを判断します。これらのオプション機能の詳細については、以降のセクションをご覧ください。
ピンチ操作をボタンの押下として登録する
Android XR では、ピンチは多くの基本的なシステム アクションに使用されます。たとえば、アイテムの選択、スクロール、ウィンドウの移動やサイズ変更、2D および 3D 空間での UI 要素やオブジェクトの移動などです。これらのパターンに沿って一貫したユーザー エクスペリエンスを促進するため、ハンド トラッキングを使用する場合は、コントローラのボタンを押す場合と同様に、ピンチを登録する必要があります。
アプリをこのように構成するには、作成したハンド インタラクション プロファイルで提供される浮動小数点値を使用して、仮想アクションを作成します。
const PRESSED_THRESHOLD := 0.8
const RELEASED_THRESHOLD := 0.6
@onready var left_controller: XRController3D = $XROrigin/XRController3D_left
func _on_xr_controller_3d_left_input_float_changed(p_name: String, value: float):
if p_name == "pinch":
var xr_tracker = XRServer.get_tracker(left_controller.tracker)
if _left_hand_pinching:
if value < RELEASED_THRESHOLD:
_left_hand_pinching = false
xr_tracker.set_input("pinch_pressed", false)
else:
if value > PRESSED_THRESHOLD:
_left_hand_pinching = true
xr_tracker.set_input("pinch_pressed", true)
コードに関する主なポイント
XRController3Dinput_float_changedシグナルの特定のしきい値よりfloatの値が大きいか小さいかを確認します。pinch_pressedという仮想アクションを作成します。
XR Tools の関数とハンド トラッキングを併用する
このページでリンクされているオープンソース プロジェクトの一部を含め、多くの Godot XR プロジェクトで Godot XR Tools が利用されています。メニュー操作の FunctionPointer など、一部の XR Tools の関数を動作させるには、ユーザーがハンド トラッキングに切り替えたときに、検索対象のアクションを入れ替える追加のコードが必要です。
たとえば、メニュー操作に FunctionPointer を使用する場合は、XRController3D ノードの tracking_changed 信号に基づいて、active_button_action プロパティをハンド トラッキングのアクションに更新します(これらのノードは、前のハンド トラッキングの設定手順では HandTrackingLeft と HandTrackingRight でした)。
const TRIGGER_POINTER_ACTION = "trigger_click"
const PINCH_POINTER_ACTION = "pinch_pressed"
@onready var func_point_left: XRToolsFunctionPointer = %FunctionPointerLeft
func _on_hand_tracking_left_tracking_changed(tracking: bool) -> void:
if tracking:
func_point_left.active_button_action = PINCH_POINTER_ACTION
else:
func_point_left.active_button_action = TRIGGER_POINTER_ACTION
コードに関する主なポイント
ハンド トラッキングと人工移動を併用する
プロジェクトで人工的な移動を使用している場合でも、ハンド トラッキングのサポートは可能です。たとえば、プレーヤーがジェスチャーで移動経路を描画できる移動システムを構築したり、プレーヤーが手を上下に動かして加速し、ジャンプ、クライミング、グライド用のジェスチャーを追加したりできます。
The Museum of All Things では、コントローラのサムスティックを使用して人工的な移動を行います。ハンド トラッキングによる移動は、「仮想サムスティック」を追加することで実装されました。プレーヤーは空中で指を挟んでトリガーし、サムスティックを動かしたい方向に手を動かします。
このサポートを実装したプルリクエストから得られた主なポイントは次のとおりです。
- ピンチが検出されると、
XRVirtualThumbstickシーンがインスタンス化されます。 - ピンチが保持されている間、元のピンチ位置からの相対的な距離と方向が
Vector2に変換され、通常のサムスティック入力に仮想的にマッピングされます。 - この入力の視覚的なフィードバックは、サムスティックの位置を示す 2 つのビルボード化された四角形メッシュの形式でプレイヤーに提供されます。
同様のアプローチを試して、既存のサムスティック駆動の移動コードを最小限の変更で動作させることができます。ただし、プロジェクトでハンド トラッキング用のカスタム移動ソリューションが必要になる場合があります。
パススルーのサポートを追加
パススルー サポートをアプリに追加すると、ユーザーが現実世界の周囲の状況を確認できるようになります。
アプリでこれを実現するには、次のようにコードを変更します。
- OpenXR
XRInterfaceのenvironment_blend_modeをXR_ENV_BLEND_MODE_ALPHA_BLENDに設定します。 WorldEnvironmentノードのbackground_modeをBG_COLORに設定します。WorldEnvironmentノードのbackground_colorを完全に透明な任意の色に設定します。Viewport transparent_bgプロパティをtrueに設定します。
光推定拡張機能を使用する
パススルーを有効にする場合は、Android XR Light Estimation OpenXR 拡張機能の使用を検討してください。この拡張機能は、WorldEnvironment と DirectionalLight3D のプロパティを調整して、ユーザーの現実世界の環境の照明をより適切にエミュレートします。これにより、仮想オブジェクトが現実世界の照明条件にうまく溶け込みます。この拡張機能は、プロジェクトの設定で有効にできます。
- プロジェクトの設定を開き、[General] > [XR] > [OpenXR] に移動します。
[Androidxr] セクションで、[Light Estimation] を選択します。
OpenXRAndroidLightEstimationノードをシーンツリーに追加し、シーンのWorldEnvironmentとDirectionalLight3Dに接続します。
例: パススルーと照明推定を有効または無効にする
次のコードは、パススルーと光推定を有効または無効にします。
@onready var world_environment = $WorldEnvironment
@onready var directional_light = $DirectionalLight3D
@onready var directional_light_orig_transform: Transform3D = directional_light.transform
func set_passthrough_enabled(p_enabled: bool) -> void:
var xr_interface = XRServer.find_interface("OpenXR")
if xr_interface == null:
return
var supported_blend_modes = xr_interface.get_supported_environment_blend_modes()
if not supported_blend_modes.has(XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND):
return
# Passthrough
if p_enabled:
xr_interface.set_play_area_mode(XRInterface.XR_PLAY_AREA_STAGE)
xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND
world_environment.environment.background_mode = Environment.BG_COLOR
world_environment.environment.background_color = Color(0.0, 0.0, 0.0, 0.0)
get_viewport().transparent_bg = true
else:
xr_interface.set_play_area_mode(XRInterface.XR_PLAY_AREA_ROOMSCALE)
xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_OPAQUE
world_environment.environment.background_mode = Environment.BG_SKY
get_viewport().transparent_bg = false
# Light Estimation
if OS.has_feature("androidxr"):
var light_estimation = Engine.get_singleton("OpenXRAndroidLightEstimationExtension")
if p_enabled and light_estimation.is_light_estimation_supported():
light_estimation.start_light_estimation()
elif light_estimation.is_light_estimation_started():
light_estimation.stop_light_estimation()
directional_light.transform = directional_light_orig_transform
コードに関する主なポイント
- ライト推定を無効にする場合は、
DirectionalLight3Dの元の方向を手動で復元する必要があります。 - パススルーと光推定を使用するプロジェクトの完全な例については、GitLab の Expedition to Blobotopia をご覧ください。