在 Godot 中使用空間容器

適用的 XR 裝置
本指南可協助您為這類 XR 裝置打造體驗。
XR 頭戴式裝置
有線 XR 眼鏡

空間容器可讓應用程式在全螢幕模式下,於系統管理的 3D 體積定界框內算繪 3D OpenXR 內容,或在執行階段轉換為全螢幕無邊界體驗。

請按照這份指南,在專案中設定及使用空間容器。

在 Android XR 上,多個空間容器在全螢幕模式下執行。
圖 1. 全螢幕模式中的空間容器,包括固定在地板上的 3D 地形容器,以及與 2D UI 配對的 3D 模型。

空間容器的運作方式

在專案設定中啟用空間容器後:

  • 整個 3D 場景會放在單一主要空間容器中,並以場景原點 (0, 0, 0) 為中心。您不需要標記或指派個別 Node3D 節點,即可將其放入容器中。
  • 應用程式會使用專案設定中的邊界模式 (Bounded 或 Immersive) 和初始邊界尺寸,啟動至受管理的完整空間模式。在有界模式下,系統會自動裁剪場景中超出定界框尺寸的任何 3D 幾何圖形。
  • 根據預設,Android XR 系統會提供視窗控制項,讓使用者在 3D 空間中抓取、移動及重新定位有界容器,或將其最小化及關閉。在執行階段,應用程式可以調整容器大小、在有界模式 (OpenXRSpatialContainerState.BOUNDED) 和全螢幕沉浸模式 (OpenXRSpatialContainerState.IMMERSIVE) 之間切換,並使用 OpenXRSpatialContainerExtension 單例模式回應邊界和狀態變更。

必要條件

開始之前,請確認開發環境和目標裝置符合下列需求:

  • Godot 版本:Godot 4.8-dev 以上版本。
  • 專案設定:完成 Godot Engine 專案設定指南中的所有步驟。
  • Godot OpenXR Vendors Plugin:安裝 5.2 以上版本的 Godot OpenXR Vendors Plugin,即可支援 Android XR 專屬擴充功能。
  • 目標裝置:支援 Spatial API 級別 4 以上版本的 Android XR 裝置。在執行階段呼叫 OpenXRSpatialContainerExtension.is_enabled(),確認裝置是否支援擴充功能。

在專案設定中啟用空間容器

調整專案設定,啟用 OpenXR、空間容器、自動執行階段權限,以及 Alpha 混合穿透模式:

  1. 依序開啟「Project」>「專案設定」。
  2. 在「專案設定」視窗的右上角,啟用「Advanced Settings」切換鈕。
  3. 依序前往「General」>「XR」>「Shaders」,然後選取「Enabled」。
  4. 依序前往「General」>「XR」>「OpenXR」,然後調整下列設定:
    • 選取「Enabled」,為專案啟用 OpenXR。
    • 將「Environment Blend Mode」設為「Alpha Blend」。
  5. 同樣在「OpenXR」下方,前往「Extensions」部分,並進行下列設定:
    • 選取「Automatically Request Runtime Permissions」,應用程式就會在啟動時,自動提示使用者授予 Android 資訊清單中宣告的 XR 執行階段權限。
    • 在「Spatial Container」子節下方,選取「Enabled」。
    • 將「Bounds Mode」設為「Bounded」,即可在 3D 定界框中啟動,或設為「Immersive」,即可在全螢幕沉浸模式中啟動。
    • 將「Bounds」設為初始寬度、高度和深度尺寸 (以公尺為單位),例如 Vector3(1.0, 1.0, 1.0)。
  6. 依序前往「General」>「Rendering」>「Viewport」,然後選取「Transparent Background」。

設定 Android 匯出、權限和全螢幕模式

接著,請設定 Android 匯出預設、權限和活動啟動模式,讓應用程式在全螢幕模式下執行,並啟用空間容器。

設定 Android 匯出預設設定

  1. 依序前往「Project」>「Export...」,然後選取「Android」匯出預設設定。
  2. 在「Gradle Build」下方,選取「Use Gradle Build」,並將「Min SDK」設為 34 以上。

    啟用

  3. 在「XR Features」下方,將「XR Mode」設為「OpenXR」,然後選取「Enable AndroidXR Plugin」。

    在

  4. 在「Android XR Features」下方,選取「Use Experimental Features」。

新增場景理解權限,以便鎖定樓層

建立及算繪基本空間容器時,不需要危險的執行階段權限 (啟用「Use Experimental Features」時,系統會自動將 android.permission.HEAD_TRACKING 新增至資訊清單)。不過,如果應用程式使用場景理解功能,例如將空間容器鎖定並錨定至實體地板,則必須在執行階段宣告並要求 android.permission.SCENE_UNDERSTANDING_COARSE 權限。

如要進一步瞭解 Android XR 權限,請參閱「瞭解 XR 權限」。如果應用程式使用樓層鎖定或場景理解功能,請宣告並要求 android.permission.SCENE_UNDERSTANDING_COARSE:

  1. 依序點選「Project」>「Export...」> Android,依序前往「Permissions」>「Custom Permissions」,然後新增 android.permission.SCENE_UNDERSTANDING_COARSE。

  2. 在「Project Settings」>「General」>「XR」>「OpenXR」>「Extensions」中選取「Automatically Request Runtime Permissions」後,應用程式會在 OpenXR 啟動時自動要求權限。如果需要在 GDScript 中手動要求權限,請呼叫 OS.request_permission():

    if not OS.get_granted_permissions().has("android.permission.SCENE_UNDERSTANDING_COARSE"):
        OS.request_permission("android.permission.SCENE_UNDERSTANDING_COARSE")
    

設定全螢幕模式

Android XR 的空間容器僅支援全螢幕模式 (XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED)。請務必在自訂建構範本 (android/build/AndroidManifest.xml,使用「Project」>「Install Android Build Template...」安裝) 中,為 Android 活動宣告 XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED:

<manifest ...>
    <application ...>
        <property
            android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
            android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED"
            tools:replace="android:value" />
        ...
    </application>
</manifest>

在 GDScript 中使用空間容器

OpenXRSpatialContainerExtension 單例模式和 OpenXRSpatialContainerState 類別會向 GDScript 公開 XR_EXT_spatial_container 和 XR_EXT_spatial_container_self_rendering 擴充功能。在執行階段,使用 OpenXRSpatialContainerExtension 檢查主要空間容器的狀態和邊界、監聽容器信號,並要求在 BOUNDED 模式 (3D 定界框) 和 IMMERSIVE 模式 (全螢幕無邊界檢視畫面) 之間切換。

連結至空間容器信號

檢查 OpenXRSpatialContainerExtension.is_enabled(),確認目前裝置支援並啟用 Spatial Container 擴充功能,並在 _ready() 中連結至容器邊界和狀態信號。

OpenXRSpatialContainerExtension 會為空間容器發出下列狀態信號:

  • spatial_container_visibility_changed:容器顯示 (true) 或隱藏 (false) 時,與 (spatial_container, is_visible) 一起發出。當 is_visible 為 false 時,暫停動畫、音訊或模擬更新。
  • spatial_container_interactability_changed:當容器取得 (true) 或失去 (false) 使用者輸入焦點時,會與 (spatial_container, is_interactive) 一起發出。啟用或停用互動式醒目顯示,以及焦點變更時的輸入處理。
  • spatial_container_bounds_mode_changed:當容器在 OpenXRSpatialContainerState.BOUNDED 和 OpenXRSpatialContainerState.IMMERSIVE 之間切換時,與 (spatial_container, bounds_mode) 一起發出。切換環境視覺效果 (例如天空盒或穿透模式) 和特定模式的 UI 控制項。
func _ready() -> void:
    if OpenXRSpatialContainerExtension.is_enabled():
        OpenXRSpatialContainerExtension.spatial_container_bounds_changed.connect(
            _on_bounds_changed
        )
        OpenXRSpatialContainerExtension.spatial_container_bounds_mode_changed.connect(
            _on_bounds_mode_changed
        )
        OpenXRSpatialContainerExtension.spatial_container_visibility_changed.connect(
            _on_visibility_changed
        )
        OpenXRSpatialContainerExtension.spatial_container_interactability_changed.connect(
            _on_interactability_changed
        )

func _on_visibility_changed(_rid: RID, is_visible: bool) -> void:
    # Pause or resume simulation and audio based on visibility
    pass

func _on_interactability_changed(_rid: RID, is_interactive: bool) -> void:
    # Enable or disable input handling and focus highlights
    pass

將 3D 內容縮放至容器邊界

在 BOUNDED 模式下,請依 bounds 的最小 尺寸等比例縮放 3D 內容,以保留顯示比例,並一律符合 容器最小的一側。轉換至 IMMERSIVE 模式時,請將場景還原為 1:1 比例:

func _on_bounds_changed(_rid: RID, bounds: Vector3) -> void:
    var uniform_scale: float = min(bounds.x, bounds.y, bounds.z)
    content_root.scale = Vector3.ONE * uniform_scale

func _on_bounds_mode_changed(
    _rid: RID, bounds_mode: OpenXRSpatialContainerState.BoundsMode
) -> void:
    if bounds_mode == OpenXRSpatialContainerState.IMMERSIVE:
        content_root.scale = Vector3.ONE

切換有界和沉浸模式

使用 OpenXRSpatialContainerState.BOUNDED 或 OpenXRSpatialContainerState.IMMERSIVE 呼叫 request_main_spatial_container_bounds_mode,即可在有邊界的 3D 體積和全螢幕沉浸式檢視畫面之間切換:

# Request transitioning to immersive mode (or pass BOUNDED to return)
OpenXRSpatialContainerExtension.request_main_spatial_container_bounds_mode(
    OpenXRSpatialContainerState.IMMERSIVE
)

另請參閱


OpenXR™ 和 OpenXR 標誌是 Khronos Group Inc. 擁有的商標,並已在中國、歐盟、日本和英國註冊為商標。