空間コンテナを使用してビルドする

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

空間コンテナは、OpenXR にボリュメトリック ウィンドウ処理をもたらします。OpenXR 1.1 の XR_EXT_spatial_container 拡張機能と XR_EXT_spatial_container_self_rendering 拡張機能で定義されている空間コンテナは、ユーザーの空間内のシステム管理の 3D ボリューム領域です。アプリは、標準の OpenXR コンポジション レイヤを使用して 3D コンテンツをレンダリングします。

従来、OpenXR セッションはユーザーの画角全体への排他的アクセスを要求します。空間コンテナを使用すると、アプリはユーザーの環境内の境界付き 3D ボックス内に 3D OpenXR コンテンツをレンダリングしたり、いつでも境界のない全画面表示の没入型エクスペリエンスに移行したりできます。

空間コンテナについて

空間コンテナは、Android XR システムによって管理され、OpenXR アプリによってレンダリングされる、境界付きまたは境界なしの 3D 領域です。

  • 境界モード: アプリが 3D 寸法(幅、高さ、奥行き(メートル単位))を提案し、システムがユーザーの環境に 3D 境界ボックスを割り当てます。アプリはボリューム内にステレオ 3D コンテンツをレンダリングし、システムはレンダリングされたコンテンツを 3D ボックスの境界にクリップします。
  • 没入モード: 空間コンテナが無限の境界に拡張され、従来のフルスクリーン OpenXR セッションのように、ユーザーの画角全体がアプリに提供されます。
フルスペース モードで同時に実行されている 3 つの空間コンテナ。オレンジ色の床に固定された 3D 地形コンテナ、2D UI がアタッチされた青色の 3D アヒルモデル、緑色の 2D UI コンテナ。
図 1. フルスペース モードの複数の空間コンテナ: 床に固定された 3D 地形ボリューム(左)、2D UI とペアになった 3D アヒル ボリューム(中央)、2D UI コンテナ(右)。

ユーザーが空間コンテナを操作する方法

Android XR システムは、空間コンテナのウィンドウ コントロールと物理空間での配置を管理し、アプリ間で一貫したインタラクション モデルを提供します。

  • 移動と再配置: ユーザーは、ハンド ジェスチャー(ピンチなど)やモーション コントローラを使用して、空間コンテナのシステム ハンドルを掴み、3D 空間で再配置できます。
  • 最小化と終了: システム ウィンドウ コントロールを使用すると、ユーザーは個々の空間コンテナを最小化または終了できます。ユーザーがコンテナを閉じると、システムはアプリに通知し、アプリがリソースをクリーンアップできるようにします。
  • シーン認識による床へのロック: アプリが android.permission.SCENE_UNDERSTANDING_COARSE 権限を宣言してリクエストすると、システムは自動的にサーフェス スナップを有効にします。これにより、ユーザーは追加のアプリ構成なしで、空間コンテナを物理的な床に配置してロックできます。図 1 のオレンジ色の地形コンテナがその例です。
  • 直接 3D 操作: コンテナがフォーカスされ、操作可能な場合、ユーザーはハンド トラッキング、視線、6DoF コントローラを使用して、ボリューム内の 3D コンテンツを直接操作できます。
ハンド トラッキングを使用して、境界のある青い空間コンテナ内の 3D のアヒルを操作しているユーザー。
図 2. ハンド トラッキングを使用して、境界のある空間コンテナ内の 3D コンテンツを操作するユーザー。
  • 境界モードと没入モードの切り替え: ユーザーまたはアプリは、OpenXR セッションを再起動することなく、境界付き 3D ボックスと境界なしの全画面没入ビューの間でコンテナを切り替えることができます。
境界のある空間コンテナから境界のない全画面没入型ビューに移行した後の 3D アヒルのシーン。
図 3. 境界モードから没入モードに移行した後の空間コンテナ。ユーザーの画角全体に表示されます。
  • 移動中のフォローモード: システムが各空間コンテナの座標空間(xrCreateSpatialContainerSpaceEXT)のポーズを制御するため、ユーザーはシステム ウィンドウ コントロールからフォローモードを有効にできます。これにより、境界付き 3D コンテナが自動的にユーザーを追跡し、ユーザーが歩き回っている間も画角内に留まります。アプリで追加の構成は必要ありません。

Android XR で空間コンテナを使用する方法

Spatial Containers を使用してアプリを構築する場合は、コンテナの境界、状態の変化、背景ブレンドモードを中心にシーンを設計します。

3D コンテンツをコンテナの境界に合わせる

境界モードでは、空間コンテナ空間(xrCreateSpatialContainerSpaceEXT)の原点 (0, 0, 0) は 3D 境界ボックスの中心にあります。システムはユーザーの環境におけるコンテナ空間のポーズを管理するため、アプリは (0, 0, 0) を基準に 3D コンテンツをレンダリングし、システムはユーザーの再配置とフォローモードを処理します。システムは、ボックスの幅、高さ、奥行きの外側にレンダリングされたジオメトリをクリップして、コンテンツが割り当てられたボリューム内に収まるようにします。

アプリは、ランタイムからの境界変更イベントをリッスンし、3D シーンをスケーリングまたは再配置して、主要なコンテンツがコンテナの現在のサイズに収まるようにする必要があります。コンテナが没入モードに移行すると、境界は無限になり、シーンを完全な 1:1 のワールド スケールに復元できます。

コンテナの状態の変化に対応する

各空間コンテナは、アプリケーション レベルでのみ可視性とフォーカスを管理するのではなく、独自の状態を報告するため、アプリはそれに応じて対応できます。

  • 公開設定: コンテナが現在表示されているか非表示になっているかを示します。コンテナが非表示になっている間は、アニメーション、音声、シミュレーションの更新を一時停止します。アプリは、コンテナの表示または非表示をリクエストすることもできます。
  • インタラクション可能性: コンテナがフォーカスされ、ハンド トラッキング、コントローラ、視線からユーザー入力を受け取っているかどうかを示します。フォーカスが変更されたときに、インタラクティブなハイライト表示と入力処理を有効または無効にします。
  • 境界モード: コンテナが現在 XR_SPATIAL_CONTAINER_BOUNDS_MODE_BOUNDED_EXT(3D ボックスにクリップされている)か XR_SPATIAL_CONTAINER_BOUNDS_MODE_IMMERSIVE_EXT(境界のない全画面表示)かを示します。モードが変更されたときに、シーンのスケールを更新し、環境ビジュアル(スカイボックスやパススルーなど)を切り替えます。アプリは、境界モードと没入モードの間の切り替えをいつでもリクエストできます。

境界モードでアルファ ブレンドの透明度を使用する

境界モードでは、背景が透明になるため、3D モデルの周囲にユーザーの物理的な環境や他のウィンドウが表示されます。透明な背景でカメラまたはビューポートを構成し、アルファブレンド環境ブレンドモードを使用します。没入モードに切り替えるときに、パススルーを有効にしたままにするか、不透明なスカイボックス環境に切り替えることができます。

機能の可用性を確認してマニフェストを構成する

空間コンテナには、空間 API レベル 4 以降をサポートする Android XR デバイスが必要です。Android API レベルを直接確認するのではなく、OpenXR ランタイムにクエリして、空間コンテナがサポートされているかどうかを判断します。xrEnumerateInstanceExtensionProperties を呼び出して XR_EXT_spatial_container と XR_EXT_spatial_container_self_rendering が使用可能であることを確認し、XrSystemSpatialContainerPropertiesEXT を指定して xrGetSystemProperties を呼び出して supportsBounded と supportsImmersive を検査します。

Spatial Containers を使用するアプリをビルドする前に、AndroidManifest.xml でアクティビティの開始モードと機能固有の権限を構成します。

AndroidManifest.xml でフルスペース モードを有効にする

空間コンテナには、スタンドアロンの OpenXR アプリであっても、フルスペース マネージド モードが必要です。従来の全画面 OpenXR アプリは、システム ウィンドウ管理なしでディスプレイを排他的に制御するために XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED を宣言します。一方、空間コンテナを使用するアプリは、Android XR システム コンポジタに依存して、フルスペース モードで 3D 境界ボリューム、ウィンドウ コントロール、空間配置を管理します。また、android.window.PROPERTY_XR_ACTIVITY_START_MODE を XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED に設定する必要があります。

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application ...>
        <!-- Spatial Containers require Full Space Managed mode -->
        <property
            android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
            android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" />

        <activity android:name=".MainActivity" ...>
            <!-- Optional hint declaring which bounds modes the activity uses -->
            <property
                android:name="org.khronos.openxr.PROPERTY_ACTIVITY_HINT_XR_SPATIAL_CONTAINER_USED_BOUNDS_MODES"
                android:value="XR_SPATIAL_CONTAINER_BOUNDS_MODE_BOUNDED_EXT|XR_SPATIAL_CONTAINER_BOUNDS_MODE_IMMERSIVE_EXT" />
        </activity>
    </application>
</manifest>

機能固有の権限を宣言してリクエストする

基本的な空間コンテナの作成とレンダリングには、危険な実行時の権限は必要ありません。ただし、特定の機能では、対応する Android XR 権限を宣言してリクエストする必要があります。

  • シーン認識を使用して空間コンテナを物理的な床にロックして固定するには、実行時に危険な android.permission.SCENE_UNDERSTANDING_COARSE 権限を宣言してリクエストします。
  • OpenXR でユーザーの頭部のポーズを追跡するには、android.permission.HEAD_TRACKING を宣言してリクエストします。
<uses-permission android:name="android.permission.HEAD_TRACKING" />
<uses-permission android:name="android.permission.SCENE_UNDERSTANDING_COARSE" />

実行時に危険な XR 権限を宣言してリクエストする方法については、XR の権限についてをご覧ください。

プロジェクトで Spatial Containers を有効にする

Spatial Containers を使用してビルドするには、Unity、Godot、または C++ で OpenXR を直接使用します。タブを選択して、お好みの環境の前提条件、エディタの設定、コード例を確認してください。

Unity

前提条件

プロジェクトを構成する

  1. [Edit] > [プロジェクト設定] > [XR Plug-in Management] > [OpenXR] に移動します。
  2. [Android XR (Extensions): Session Management] の横にある設定アイコン をクリックし、[Immersive XR] をオフにします。
  3. [OpenXR Feature Groups] リストで、[Spatial Container] を有効にします。

C# で XRSpatialContainerFeature を使用して、境界のクエリ、コンテナ イベントへの応答、境界モードと没入モードの切り替えを行います。

void OnEnable()
{
    XRSpatialContainerFeature.OnSpatialContainerBoundsChanged += OnBoundsChanged;
}

private void OnBoundsChanged(Vector3 bounds, bool infiniteBounds)
{
    float minScale = Mathf.Min(bounds.x, bounds.y, bounds.z);
    transform.localScale = infiniteBounds ? Vector3.one : Vector3.one * minScale;
}

public void SetImmersiveMode(bool immersive)
{
    XRSpatialContainerFeature.TryRequestBoundsMode(immersive);
}

プロジェクトの設定手順、マニフェストの構成、権限の処理の詳細については、Unity で空間コンテナを使用するをご覧ください。

Godot

前提条件

プロジェクトを構成する

  1. プロジェクト設定 に移動し、Advanced Settings を有効にして、[General] > [XR] > [OpenXR] > [Extensions] に移動します。
  2. [Spatial Container] サブセクションで [Enabled] を選択し、[Bounds Mode] と [Bounds] を構成します。
  3. [Project] > [Export...]> [Android] を選択し、[Android XR Features] で [Use Experimental Features] を選択します。

GDScript の OpenXRSpatialContainerExtension シングルトンを使用して、コンテナの境界とモードの変更に対応します。

func _ready() -> void:
    if OpenXRSpatialContainerExtension.is_enabled():
        OpenXRSpatialContainerExtension.spatial_container_bounds_changed.connect(
            _on_bounds_changed
        )

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

func set_immersive_mode() -> void:
    OpenXRSpatialContainerExtension.request_main_spatial_container_bounds_mode(
        OpenXRSpatialContainerState.IMMERSIVE
    )

プロジェクト設定、エクスポート権限、GDScript の例の詳細については、Godot で Spatial Container を使用するをご覧ください。

OpenXR

前提条件

XrInstance の作成時に XR_EXT_spatial_container と XR_EXT_spatial_container_self_rendering を有効にしてから、空間コンテナを作成してレンダリングします。

// 1. Enable the Spatial Container extensions during xrCreateInstance
const char* enabledExtensions[] = {
    XR_EXT_SPATIAL_CONTAINER_EXTENSION_NAME,
    XR_EXT_SPATIAL_CONTAINER_SELF_RENDERING_EXTENSION_NAME,
};

// 2. Configure and create a self-rendering spatial container
XrSpatialContainerConfigurationSelfRenderingEXT selfRenderingConfig{
    .type = XR_TYPE_SPATIAL_CONTAINER_CONFIGURATION_SELF_RENDERING_EXT,
    .next = nullptr,
    .viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
    .suggestedBounds = {1.5f, 1.5f, 1.5f}, // Width, height, depth in meters
};

XrSpatialContainerCreateInfoEXT createInfo{
    .type = XR_TYPE_SPATIAL_CONTAINER_CREATE_INFO_EXT,
    .next = &selfRenderingConfig,
    .spatialContainerConfig =
        reinterpret_cast<const XrSpatialContainerConfigurationBaseHeaderEXT*>(
            &selfRenderingConfig),
};

XrSpatialContainerEXT spatialContainer = XR_NULL_HANDLE;
xrCreateSpatialContainerEXT(session, &createInfo, &spatialContainer);

// 3. Request bounded mode and make the container visible
xrRequestSpatialContainerBoundsModeEXT(
    spatialContainer, XR_SPATIAL_CONTAINER_BOUNDS_MODE_BOUNDED_EXT);
xrRequestSpatialContainerVisibilityEXT(spatialContainer, XR_TRUE);

関連情報


OpenXR™ および OpenXR ロゴは、The Khronos Group Inc. が所有する商標であり、中国、欧州連合、日本、英国で商標として登録されています。