自定义应用中的 3D 模型

适用的 XR 设备
本指南可帮助您为以下类型的 XR 设备打造优质体验。
扩展现实头戴设备
有线扩展现实眼镜

在自定义 3D 模型之前,您需要先将其添加到应用中。将 3D 模型添加到应用后,您可以通过自定义 3D 模型的外观和移动方式来增强视觉和互动体验。

例如,您可以播放和控制嵌入式 glTF 动画、访问和移动构成模型的节点,甚至加载自定义纹理并定义材质属性以替换内部网格。借助这些功能,您可以在运行时动态更改对象的外观和行为。

Android XR 中的 3D 对象

Jetpack XR SDK 支持 Khronos Group 针对 3D 模型制定的 glTF 2.0 开放标准,并使用 glTF 2.0 标准中指定的基于物理的渲染 (PBR) 技术(以及受支持的扩展程序)渲染这些对象。glTF(图形库传输格式)是一种用于传输和加载 3D 场景和模型的标准文件格式。glTF 模型由内部组件的层次结构组成。

以下是需要了解的关键组件:

  • 节点:用于定义模型的结构和层次结构。每个节点都可以有自己的位置、旋转和缩放。
  • 网格:构成 3D 对象形状的结构性 3D 几何体。
  • 材质:这些属性定义了网格的视觉外观,例如颜色、粗糙度或对光照的反应。
  • 纹理:一种图片素材资源(例如 PNG 文件),可应用于 3D 模型的表面,以创建自定义图案、颜色、细节或其他视觉效果。
  • 动画:这些是预定义的序列或动画轨道,包含对各个节点和网格的更改,以创建随时间推移而产生的运动效果。

在 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 中,KhronosPbrMaterialKhronosUnlitMaterial 类用于创建和操纵这些材质。顾名思义,KhronosUnlitMaterials 不受光照影响,也不会发光。借助 KhronosPbrMaterial,您可以自定义更多属性,例如光泽颜色、对象的金属感或粗糙度,以及对象是否发光。

如需详细了解 Android XR 中支持的各项属性和可自定义的参数,请参阅我们的参考文档。如需更好地了解这些属性,请参阅 Khronos 词汇表

图 1. 更改 3D 模型上的基本颜色的示例。

如需自定义 3D 模型的材质属性,请先使用 KhronosPbrMaterial 创建新材质。您需要为要实现的视觉效果设置适当的 AlphaMode

接下来,定义要修改的属性。此示例使用 setBaseColorFactor 将网格的基本颜色更改为紫色。此方法需要一个 Vector4,其中 x, y, zw 分量分别对应于 RGBA(红色、绿色、蓝色和 Alpha)值:

// 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] 范围之外的坐标)。必须将 Texture 分配给 KhronosPbrMaterial,才能对 3D 模型产生视觉效果。

图 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. 的商标。