既存の Godot XR プロジェクトに Android XR のサポートを追加する

対象の XR デバイス
このガイダンスは、次のようなタイプの XR デバイス向けのエクスペリエンスを構築する際に役立ちます。
XR ヘッドセット
有線 XR グラス

Godot に既存の XR プロジェクトがある場合は、新しい別のプロジェクトを開始しなくても Android XR のサポートを追加できます。一部の手順はすべてのプロジェクトで必須ですが、プロジェクトで使用する XR 機能によっては省略可能な手順もあります。手順全体を通して、Android XR のサポートを追加した複数のオープンソースの Godot XR プロジェクトへのリンクと、特定の機能を有効にするために必要な変更を示す関連するプルリクエストへのリンクを掲載しています。

すべてのプロジェクトに必要な手順

プロジェクトでサポートされている XR 機能の種類に関係なく、次のトピックの手順を完了してください。その後、省略可能な手順のリストに記載されている機能を確認して、プロジェクトに追加の作業が必要かどうかを判断します。

Godot と Godot OpenXR Vendors プラグインを更新する

プロジェクトを最新の必須バージョンに更新し、Android XR 用にプロジェクトの設定を構成する手順は次のとおりです。

  1. Godot のバージョンを 4.6.2 以降に更新します。プロジェクトで追加のサポートが必要な場合は、新しいバージョンへの移行に関するドキュメントをご覧ください。
  2. アセットストアアセット ライブラリ、または GitHub のリポジトリから、Godot OpenXR Vendors Plugin バージョン 5.1 以降をダウンロードします。

  3. Android XR 用にプロジェクトの設定を構成します。

    1. Android XR 用のエクスポート プリセットを追加します。
    2. [Use Gradle Build] を有効にします。

    を有効にします。

    1. [XR Features] セクションで、[XR Mode] に [OpenXR] を選択し、[Enable AndroidXR Plugin] を選択します。

    次のオプションを構成します。

ハンド トラッキングのサポートを追加

コントローラを使用できる場合もありますが、Android XR ヘッドセットと XR グラスの主な入力方法はハンド トラッキングです。可能であれば、Godot プロジェクトにハンド トラッキングのサポートを追加する必要があります。

ハンド トラッキングのサポートを追加する: プロジェクト設定を行う

まず、次の手順に沿ってプロジェクト設定を行い、ハンド トラッキングとそれに関連する OpenXR 拡張機能を有効にします。

  1. プロジェクトの設定を開き、[General] > [XR] > [OpenXR] に移動します。
  2. [拡張機能] セクションで、[ハンド トラッキング] と [ハンド インタラクション プロファイル] を選択します。

    次のオプションを構成します。

  3. [Extensions] セクションで [Meta] サブセクションを見つけ、[Hand Tracking Mesh] と [Hand Tracking Aim] を選択します。

    次のオプションを構成します。

ハンド トラッキングのサポートを追加する: コントローラ ノードを追加して構成する

ハンド トラッキング用の既存の XRController3D ノードを動的に変更するのではなく、ハンドモデルのトラッキングと表示、およびハンド トラッキング エイム拡張機能からの入力の処理を行うコントローラ ノードを追加します。

  1. XROrigin3D ノードに 3 つの XRController3D ノードを追加します。

    1. 1 つは「HandTrackingLeft」という名前にし、トラッカー プロパティを /user/hand_tracker/left に設定します。
    2. もう 1 つの名前を「HandTrackingRight」にし、トラッカー プロパティを /user/hand_tracker/right に設定します。
    3. 最後の名前を「HandTrackingAimLeft」にし、トラッカー プロパティを /user/fbhandaim/left に設定します。

    プロジェクトの元の XRController3D ノードの名前が「XRController3D_left」と「XRController3D_right」の場合、シーンは次のようになります。

    コントローラ ノードを追加した後のシーンの例。

  2. HandTrackingLeftHandTrackingRight のシグナル tracking_changed を、対応するコントローラ トラッカー(前の例では XRController3D_leftXRController3D_right)の可視性を更新する個々の関数に接続します。

    たとえば、HandTrackingLeft のシグナルに接続された関数は次のようになります。

    func _on_hand_tracking_left_hand_tracking_changed(tracking):
        $XROrigin3D/XRController3D_left.visible = not tracking
    
  3. ハンド トラッキング コントローラ ノードの [Show When Tracked] プロパティを有効にします。

    これで、ユーザーがハンド トラッキングを使用しているかコントローラを使用しているかに応じて、コントローラ モデルとハンド トラッキング モデルを視覚的に切り替えることができます。

  4. ハンド トラッキング コントローラ ノードの子として OpenXRFbHandTrackingMesh ノードを追加します。

  5. これらの OpenXRFbHandTrackingMesh ノードの子として XRHandModifier3D ノードを追加し、正しい Hand Tracker プロパティが設定されていることを確認して、リアルタイムのハンド トラッキング データをモデルに適用します。

    子ノードをコントローラ ノードに追加した後のシーンの例。

ハンド トラッキングのサポートを追加: OpenXR アクション マップでハンド インタラクション プロファイルを設定

次に、OpenXR アクション マップ手のインタラクション プロファイルを設定します。

  1. エディタの下部にある [OpenXR Action Map] メニューを開きます。
  2. Galaxy XR コントローラとの互換性の問題を回避するため、Simple Controller プロファイルを削除します。
  3. [プロファイルを追加] をクリックし、[手の操作] を選択して、[OK] をクリックします。
  4. このプロファイルを 1 つ以上のアクション セットに自由にマッピングします。

アプリの要件によっては、ハンド トラッキングによるユーザー入力の処理方法も調整する必要があります。

ハンド トラッキングのサポートを追加する: Android XR のメニュー ジェスチャーを設定する

最後に、Android XR のメニュー ジェスチャーを実装できます。これにより、プレーヤーの左手がメニュー ジェスチャーを行うのに正しい位置にあるときにアイコンが表示され、ユーザーがジェスチャーを行うとメニューが表示または非表示になります。この処理には、先ほど追加した HandTrackingAimLeft ノードを使用します。

  1. 左手のハンド トラッキング ノードに、選択したアイコンを表示するビルボードの四角形を追加します(前の手順で追加したコントローラ ノードの次の画像の MenuIcon ノードを参照)。

    子ノードをコントローラ ノードに追加した後のシーンの例。

  2. HandTrackingAimLeftbutton_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)

コードに関する主なポイント

  • XRController3D input_float_changed シグナルの特定のしきい値より float の値が大きいか小さいかを確認します。
  • pinch_pressed という仮想アクションを作成します。

XR Tools の関数とハンド トラッキングを併用する

このページでリンクされているオープンソース プロジェクトの一部を含め、多くの Godot XR プロジェクトで Godot XR Tools が利用されています。メニュー操作の FunctionPointer など、一部の XR Tools の関数を動作させるには、ユーザーがハンド トラッキングに切り替えたときに、検索対象のアクションを入れ替える追加のコードが必要です。

たとえば、メニュー操作に FunctionPointer を使用する場合は、XRController3D ノードの tracking_changed 信号に基づいて、active_button_action プロパティをハンド トラッキングのアクションに更新します(これらのノードは、前のハンド トラッキングの設定手順では HandTrackingLeftHandTrackingRight でした)。

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

コードに関する主なポイント

  • このコードは、ピンチをボタンの押下として登録するために作成できる pinch_pressed 仮想アクションに依存しています。

ハンド トラッキングと人工移動を併用する

プロジェクトで人工的な移動を使用している場合でも、ハンド トラッキングのサポートは可能です。たとえば、プレーヤーがジェスチャーで移動経路を描画できる移動システムを構築したり、プレーヤーが手を上下に動かして加速し、ジャンプ、クライミング、グライド用のジェスチャーを追加したりできます。

The Museum of All Things では、コントローラのサムスティックを使用して人工的な移動を行います。ハンド トラッキングによる移動は、「仮想サムスティック」を追加することで実装されました。プレーヤーは空中で指を挟んでトリガーし、サムスティックを動かしたい方向に手を動かします。

このサポートを実装したプルリクエストから得られた主なポイントは次のとおりです。

  • ピンチが検出されると、XRVirtualThumbstick シーンがインスタンス化されます。
  • ピンチが保持されている間、元のピンチ位置からの相対的な距離と方向が Vector2 に変換され、通常のサムスティック入力に仮想的にマッピングされます。
  • この入力の視覚的なフィードバックは、サムスティックの位置を示す 2 つのビルボード化された四角形メッシュの形式でプレイヤーに提供されます。

同様のアプローチを試して、既存のサムスティック駆動の移動コードを最小限の変更で動作させることができます。ただし、プロジェクトでハンド トラッキング用のカスタム移動ソリューションが必要になる場合があります。

パススルーのサポートを追加

パススルー サポートをアプリに追加すると、ユーザーが現実世界の周囲の状況を確認できるようになります。

アプリでこれを実現するには、次のようにコードを変更します。

  • OpenXR XRInterfaceenvironment_blend_modeXR_ENV_BLEND_MODE_ALPHA_BLEND に設定します。
  • WorldEnvironment ノードの background_modeBG_COLOR に設定します。
  • WorldEnvironment ノードの background_color を完全に透明な任意の色に設定します。
  • Viewport transparent_bg プロパティを true に設定します。

光推定拡張機能を使用する

パススルーを有効にする場合は、Android XR Light Estimation OpenXR 拡張機能の使用を検討してください。この拡張機能は、WorldEnvironmentDirectionalLight3D のプロパティを調整して、ユーザーの現実世界の環境の照明をより適切にエミュレートします。これにより、仮想オブジェクトが現実世界の照明条件にうまく溶け込みます。この拡張機能は、プロジェクトの設定で有効にできます。

  1. プロジェクトの設定を開き、[General] > [XR] > [OpenXR] に移動します。
  2. [Androidxr] セクションで、[Light Estimation] を選択します。

    次のオプションを構成します。

  3. OpenXRAndroidLightEstimation ノードをシーンツリーに追加し、シーンの WorldEnvironmentDirectionalLight3D に接続します。

    次のオプションがあります。

例: パススルーと照明推定を有効または無効にする

次のコードは、パススルーと光推定を有効または無効にします。

@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 をご覧ください。