アプリにサブスペースを追加する

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

サブスペースは、アプリ内の 3D 空間を区切ったパーティションです。これにより、3D モデルの配置、3D レイアウトの構築、2D コンテンツへの奥行き追加ができるようになります。サブスペースは、空間化が有効になっている場合にのみレンダリングされます。ホーム スペースまたは非 XR デバイスでは、そのサブスペース内のコードは無視されます。

SpatialPanel、SpatialRow、SpatialColumn などのサブスペース コンポーザブルを使用して、レイアウトを作成し、2D コンテンツを 3D 空間に配置できます。3D コンテンツを配置するには、3D モデルの場合は SceneCoreEntity、ステレオ画像の場合は SpatialExternalSurface など、適切な Subspace コンポーザブルを使用します。Orbiter や SpatialDialog などの一部の XR コンポーネントは、2D UI 階層のどこでも使用できる標準の 2D コンポーザブルですが、SubspaceComposable はアプリのサブスペースで呼び出す必要があります。これを行うには、Subspace サブスペース コンポーザブルを使用します。

サブスペース階層について

最上位の Subspace は、アプリによって呼び出される最も外側のサブスペースです。Subspace の呼び出しごとに、新しい独立した空間 UI 階層が作成されます。ネストされている親 Subspace の空間位置、向き、スケールは継承されません。

SpatialPanel、Orbiter、SpatialPopup などのコンポーネント内に埋め込みまたはネストされた Subspace を作成するには、PlanarEmbeddedSubspace を使用します。

PlanarEmbeddedSubspace には、Subspace との間に次の 2 つの主な違いがあります。

  • 呼び出された 2D レイアウトに参加します。つまり、サブスペースの高さと幅は、その 2D 親レイアウトの高さと幅によって制約されます。
  • 呼び出されたエンティティの子として動作します。つまり、SpatialPanel 内にネストされたサブスペース コンポーザブルを呼び出すと、そのサブスペースは呼び出し元の SpatialPanel の子になります。

PlanarEmbeddedSubspace のこれらの動作により、次のような機能が実現します。

  • 親エンティティとともに子を移動する
  • オフセット SubspaceModifier を使用して子の位置をオフセットする
  • 2D UI の上に浮かび、2D レイアウトの適切なスペースの高さと幅に一致する 3D オブジェクトを表示する

サブスペースのレイアウトを調整する

Android XR では、アプリのレイアウトはデフォルトでフルスペース モードの Subspace の VolumeConstraints にバインドされます。そのため、ユーザーが利用できる表示スペースの量を考慮し、それに応じてレイアウトを調整する必要があります。recommendedContentBoxInFullSpace は、ActivitySpace 内の境界ボックスの特定の寸法を提供し、コンテンツをユーザーの画角内に配置できるようにします。

アプリの主要コンテンツはこのボックス内に収まるようにしてください。推奨される境界を超えるコンテンツがある場合は、ユーザーが頭を動かして空間を探索するようなレイアウトを検討してください。recommendedContentBoxInFullSpace のデフォルトの制約は、SubspaceModifier.requiredSizeIn などのカスタム サイズベースの修飾子を適用することでオーバーライドできます。境界のない動作の場合は、allowUnboundedSubspace = true を設定します。

必要に応じて、現在の Session を使用して recommendedContentBoxInFullSpace を呼び出し、これらの特定のディメンションを取得します。次の例をご覧ください。

val session = LocalSession.current
session?.scene?.activitySpace?.recommendedContentBoxInFullSpace

アプリにサブスペースを追加する

次のコード例は、アプリに Subspace と PlanarEmbeddedSubspace を追加する方法を示しています。

setContent {
    // This is a top-level subspace
    Subspace {
        SpatialPanel {
            MyComposable()
        }
    }
}

@Composable
private fun MyComposable() {
    Row {
        PrimaryPane()
        SecondaryPane()
    }
}

@Composable
private fun PrimaryPane() {
    // This is an embedded subspace, because PrimaryPane is in a SpatialPanel
    // and that SpatialPanel is in the top-level Subspace
    PlanarEmbeddedSubspace {
        SpatialPanel {}
    }
}

詳細については、Subspace と PlanarEmbeddedSubspace の完全なリファレンス ドキュメントをご覧ください。