アプリで 3D モデルをカスタマイズする

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

3D モデルをカスタマイズする前に、まずアプリに追加する必要があります。3D モデルをアプリに追加したら、3D モデルの見た目や動きをカスタマイズして、視覚的およびインタラクティブなエクスペリエンスを強化できます。

たとえば、埋め込まれた glTF アニメーションを再生して制御したり、モデルを構成するノードにアクセスして移動したり、カスタム テクスチャを読み込んでマテリアル プロパティを定義して内部メッシュをオーバーライドしたりできます。これらの機能を使用すると、実行時にオブジェクトの外観と動作を動的に変更できます。

Android XR の 3D オブジェクト

Jetpack XR SDK は、Khronos Group の 3D モデル向けオープン スタンダードである glTF 2.0 をサポートし、glTF 2.0 標準で指定された(サポートされている拡張機能とともに)物理ベース レンダリング(PBR)手法でこれらのオブジェクトをレンダリングします。glTF(Graphics Library Transmission Format)は、3D シーンとモデルの送信と読み込みのための標準ファイル形式です。glTF モデルは、内部コンポーネントの階層構造で構成されています。

理解すべき主なコンポーネントは次のとおりです。

  • ノード: モデルの構造と階層を定義します。各ノードには、独自の位置、回転、スケールを設定できます。
  • メッシュ: 3D オブジェクトの形状を形成する構造的な 3D ジオメトリ。
  • マテリアル: メッシュの色、粗さ、照明に対する反応など、メッシュの視覚的な外観を定義します。
  • テクスチャ: 3D モデルの表面に適用して、カスタム パターン、色、ディテールなどの視覚効果を作成できる画像アセット(PNG ファイルなど)。
  • アニメーション: 個々のノードとメッシュの変更を含み、時間の経過とともに動きがあるように見せる、事前定義されたシーケンスまたはアニメーション トラックです。

Jetpack Compose for XR では、SpatialGltfModel を使用してこれらのファイルをレンダリングし、SpatialGltfModelState を使用して読み込みとアニメーションのステータスを追跡します。詳しくは、アプリに 3D モデルを追加するをご覧ください。

3D モデルをアニメーション化する

3D モデルにはアニメーションを埋め込むことができます。内部的には、アニメーションはサンプラーを使用して動きのタイミングと値を定義し、チャンネルを使用してそれらの動きを個々のノードとメッシュに接続します。Jetpack XR SDK では、KHR_animation_pointer glTF 拡張機能で作成されたスケルトン アニメーションとマテリアル アニメーションがサポートされています。

Compose for XR を使用してアニメーションを再生するには、animations のリストから特定のトラックの名前を指定します。animation.start() を使用して再生を開始します。必要に応じて、SpatialGltfModelAnimation を使用して、速度、シーク時間、アニメーションをループさせるかどうかを指定できます。

val animation = modelState.animations.find { it.name == "Walk" }

animation?.animationState?.let { state ->
    LaunchedEffect(state) {
        Log.i("SpatialGltfModelAnimationSample", "Animation State: $state")
    }
}

DisposableEffect(animation) {
    animation?.loop()
    onDispose {
        animation?.stop()
    }
}

ノードの操作: ポーズと回転

モデルの特定の部分を操作して、回転やポーズなどのプロパティを変更するには、SpatialGltfModelState を使用して glTF モデルの内部 nodes をクエリする必要があります。

// Retrieve the list of nodes (individual components/meshes) defined within the glTF model.
val entityNodes = modelState.nodes

// Find a specific node by name to apply modifications, such as material overrides.
val node = entityNodes.find { it.name == "node_name" }

正しいノードを見つけたら、その localPose を設定して、直近の親 GltfModelNode に対する 3D の位置と回転を変更するか、modelPose を使用して GltfModelEntity ルートに対する位置を設定します。同様に、localScale/modelScale を使用して、親またはルートに対するモデルのスケールを変更できます。

LaunchedEffect(node, degrees) {
    val rotation = Quaternion.fromEulerAngles(degrees, 0f, degrees)
    node?.let {
        it.localPose = Pose(it.localPose.translation, rotation)
    }
}

3D モデルのマテリアル プロパティをカスタマイズする

実行時にマテリアル属性を調整して、ユーザー入力やアプリの現在の状態に基づいてオブジェクトの外観を動的に変更できます。

Jetpack XR では、KhronosPbrMaterial クラスと KhronosUnlitMaterial クラスを使用して、これらのマテリアルを作成および操作します。名前が示すように、KhronosUnlitMaterials は照明がなく、シーンの照明の影響を受けません。KhronosPbrMaterial を使用すると、光沢の色、オブジェクトのメタリック感や粗さ、発光するかどうかなど、より広範囲のプロパティをカスタマイズできます。

サポートされている各プロパティと Android XR のカスタマイズ可能なパラメータの詳細については、リファレンス ドキュメントをご覧ください。これらのプロパティをより深く理解するには、Khronos 用語集をご覧ください。

図 1. 3D モデルのベースカラーを変更する例。

3D モデルのマテリアル プロパティをカスタマイズするには、まず KhronosPbrMaterial を使用して新しいマテリアルを作成します。目的の視覚効果を実現するには、適切な AlphaMode を設定する必要があります。

次に、変更するプロパティを定義します。この例では、setBaseColorFactor を使用して、メッシュのベースカラーを紫に変更しています。このメソッドでは Vector4 が必要です。ここで、x, y, zw のコンポーネントは、それぞれ RGBA(赤、緑、青、アルファ)の値に対応しています。

// Maintain a reference to the custom material to avoid re-creating it on every recomposition.
var pbrMaterial by remember { mutableStateOf<KhronosPbrMaterial?>(null) }

// Create and apply the custom material once the session is ready and the target node is available.
LaunchedEffect(node) {
    val material = KhronosPbrMaterial.create(
        session = xrSession,
        alphaMode = AlphaMode.OPAQUE
    ).also {
        pbrMaterial = it
        // Apply a base color factor (RGBA) to change the color of the model.
        it.setBaseColorFactor(
            Vector4(
                x = 0.5f,
                y = 0.0f,
                z = 0.5f,
                w = 1.0f
            )
        )
    }

3D モデルのカスタム テクスチャを読み込む

Texture は、3D モデルの表面に適用して色、詳細、その他の表面情報を提供できる画像アセットです。Jetpack XR Texture API を使用すると、アプリの /assets/ フォルダから PNG ファイルなどの画像データを非同期で読み込むことができます。

テクスチャを読み込むときに、テクスチャのレンダリング方法を制御する TextureSampler を指定できます。サンプラーは、フィルタリング プロパティ(テクスチャが元のサイズよりも小さくまたは大きく表示される場合)とラッピング モード(標準の [0, 1] 範囲外の座標を処理する場合)を定義します。3D モデルに視覚効果を適用するには、TextureKhronosPbrMaterial に割り当てる必要があります。

図 2. 3D モデルのテクスチャを変更する例。

カスタム テクスチャを読み込むには、まず画像ファイルを /assets/ フォルダに保存する必要があります。効果的な手法として、そのフォルダに textures サブディレクトリを作成することをおすすめします。

ファイルを適切なディレクトリに保存したら、Texture API を使用してテクスチャを作成します。必要に応じて、ここでオプションの TextureSampler を適用することもできます。

この例では、オクルージョン テクスチャを適用し、オクルージョンの強さを設定します。

LaunchedEffect(node) {
    val material = KhronosPbrMaterial.create(
        session = xrSession,
        alphaMode = AlphaMode.OPAQUE
    ).also {
        pbrMaterial = it

        // Load a texture
        val texture = Texture.create(
            session = xrSession,
            path = Path("textures/texture_name.png")
        )

        // Set the texture and configure occlusion to define how the material surface handles ambient lighting.
        it.setOcclusionTexture(
            texture = texture,
            strength = 1.0f
        )
    }
    node?.setMaterialOverride(
        material = material
    )
}

3D オブジェクトにマテリアルとテクスチャを適用する

新しいマテリアルまたはテクスチャを適用するには、glTF ノードの特定のノードの既存のマテリアルをオーバーライドします。これを行うには、setMaterialOverride を呼び出します。

node?.setMaterialOverride(
    material = material
)

新しく作成したマテリアルを削除するには、以前にオーバーライドした ノードclearMaterialOverride を呼び出します。3D モデルがデフォルトの状態に戻ります。

if (removeMaterial) {
    node?.clearMaterialOverride()
}


glTF および glTF ロゴは、Khronos Group Inc. の商標です。