Antes de personalizar un modelo 3D, primero debes agregarlo a tu app. Después de agregar un modelo 3D a tu app, puedes mejorar la experiencia visual e interactiva personalizando el aspecto y el movimiento del modelo 3D.
Por ejemplo, puedes reproducir y controlar animaciones glTF incorporadas, acceder a los nodos que componen tu modelo y moverlos, o incluso cargar texturas personalizadas y definir propiedades de materiales para anular las mallas internas. Estas funciones te permiten modificar de forma dinámica la apariencia y el comportamiento de un objeto en el tiempo de ejecución.
Objetos 3D en Android XR
El SDK de Jetpack XR admite el estándar abierto glTF 2.0 de Khronos Group para modelos 3D y renderiza estos objetos con técnicas de renderización basada en la física (PBR) especificadas en el estándar glTF 2.0 (junto con las extensiones compatibles). Un glTF (Graphics Library Transmission Format) es un formato de archivo estándar para transmitir y cargar escenas y modelos 3D. Un modelo glTF se compone de una estructura jerárquica de componentes internos.
Estos son los componentes clave que debes comprender:
- Nodos: Definen la estructura y la jerarquía del modelo. Cada nodo puede tener su propia posición, rotación y escala.
- Mallas: Es la geometría estructural 3D que forma la forma de un objeto 3D.
- Materiales: Estos definen la apariencia visual de las mallas, como su color, rugosidad o cómo reaccionan a la iluminación.
- Texturas: Es un recurso de imagen, como un archivo PNG, que puedes aplicar a la superficie de un modelo 3D para crear patrones, colores, detalles o efectos visuales personalizados.
- Animaciones: Son secuencias predefinidas o pistas de animación que contienen cambios en nodos y mallas individuales para crear la apariencia de movimiento a lo largo del tiempo.
En Jetpack Compose para XR, renderizas estos archivos con SpatialGltfModel
y realizas un seguimiento de su estado de carga y animación con un SpatialGltfModelState.
Para obtener más información, consulta Cómo agregar modelos 3D a tu app.
Cómo animar modelos 3D
Los modelos 3D pueden tener animaciones incorporadas. Internamente, las animaciones usan
muestreadores para definir el tiempo y los valores de un movimiento, y
canales para conectar esos movimientos a nodos y
mallas individuales. Las animaciones esqueléticas y las animaciones de materiales creadas con la
KHR_animation_pointer extensión glTF son
compatibles con el SDK de Jetpack XR.
Con Compose para XR, para reproducir una animación, especifica el nombre de la pista específica
de la lista de animations. Usa animation.start() para comenzar
a reproducir. De manera opcional, puedes especificar la velocidad, el tiempo de búsqueda y si la animación debe repetirse o
no con 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() } }
Cómo manipular nodos: Poses y rotación
Para manipular partes específicas de un modelo y cambiar sus propiedades, como la rotación o la pose, deberás consultar los nodes internos del modelo glTF con SpatialGltfModelState.
// 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" }
Después de encontrar el nodo correcto, puedes configurar su localPose para cambiar su posición y rotación 3D
en relación con su elemento superior inmediato GltfModelNode o
usar modelPose para establecer la posición en relación con la raíz
GltfModelEntity. Del mismo modo, puedes usar localScale/modelScale para cambiar la escala del modelo en relación con su elemento superior o raíz.
LaunchedEffect(node, degrees) { val rotation = Quaternion.fromEulerAngles(degrees, 0f, degrees) node?.let { it.localPose = Pose(it.localPose.translation, rotation) } }
Cómo personalizar las propiedades de materiales de tu modelo 3D
Puedes ajustar los atributos de materiales durante el tiempo de ejecución para cambiar la apariencia de un objeto de forma dinámica según la entrada del usuario o el estado actual de la app.
En Jetpack XR, las KhronosPbrMaterial y KhronosUnlitMaterial
clases se usan para crear y manipular estos materiales. Como su nombre lo indica,
KhronosUnlitMaterials no están iluminados y no se ven afectados por la iluminación de la escena.
KhronosPbrMaterial te permite personalizar una gama más amplia de propiedades, como el color de brillo, qué tan metálico o rugoso es un objeto y si emite luz.
Para obtener más información sobre cada propiedad compatible y los parámetros personalizables en Android XR, consulta nuestra documentación de referencia. Para comprender mejor estas propiedades, consulta el glosario de Khronos.
Para personalizar las propiedades de materiales de tu modelo 3D, primero crearás el
material nuevo con KhronosPbrMaterial. Deberás configurar el
adecuado AlphaMode para la apariencia visual que intentas
lograr:
A continuación, define las propiedades que deseas modificar. En este ejemplo, se usa
setBaseColorFactor para cambiar el color base de la malla a morado. Este método requiere un Vector4, en el que los componentes x, y, z y w corresponden a los valores RGBA (rojo, verde, azul y alfa), respectivamente:
// 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 ) ) }
Cómo cargar texturas personalizadas para tu modelo 3D
Una Texture es un recurso de imagen que puedes aplicar a la superficie de un modelo 3D
para proporcionar color, detalles o cualquier otra información de la superficie. La API de Texture de Jetpack XR te permite cargar datos de imágenes, como archivos PNG, de la carpeta /assets/ de tu app de forma asíncrona.
Cuando cargas una textura, puedes especificar un TextureSampler, que controla
cómo se renderiza la textura. El muestreador define las propiedades de filtrado (para cuando la textura aparece más pequeña o más grande que su tamaño original) y los modos de ajuste (para controlar las coordenadas fuera del rango estándar [0, 1]). Se debe asignar un Texture a un KhronosPbrMaterial para que tenga un efecto visual en un modelo 3D.
Para cargar una textura personalizada, primero debes guardar el archivo de imagen en la carpeta /assets/. Como práctica recomendada, es posible que también quieras crear un subdirectorio textures en esa carpeta.
Después de guardar el archivo en el directorio adecuado, crea la textura
con la Texture API. Aquí también puedes aplicar un TextureSampler opcional si es necesario.
En este ejemplo, se aplica una textura de oclusión y se establece la intensidad de la oclusión:
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 ) }
Cómo aplicar materiales y texturas a tus objetos 3D
Para aplicar el material o la textura nuevos, anula el material existente para un
nodo específico en tu nodo glTF node. Para ello, llama a
setMaterialOverride:
node?.setMaterialOverride( material = material )
Para quitar los materiales recién creados, llama a clearMaterialOverride en el
nodo anulado anteriormente. Esto devuelve tu modelo 3D a su estado predeterminado:
if (removeMaterial) { node?.clearMaterialOverride() }
glTF y el logotipo de glTF son marcas comerciales de la Khronos Group Inc.