Godot en XREAL AURA: Una guía práctica para el desarrollo espacial nativo
En resumen
Aprende a desarrollar en Godot para XREAL AURA: usa el editor en las gafas, contenedores OpenXR y evita la deriva de anclaje con esta guía práctica.
Tu pipeline de build XR actualmente implica atarte a un escritorio, exportar un APK, hacer sideload por ADB, ponerte las gafas, descubrir un typo y empezar de nuevo. XREAL AURA elimina ese bucle por completo, y Godot está en el catálogo de lanzamiento con un editor completo que se ejecuta en las propias gafas. Eso cambia lo que significa "iterar" para el desarrollo espacial.
Esta guía recorre el flujo de trabajo real: poner el editor en marcha en AURA, estructurar una escena espacial con OpenXR Spatial Containers, manejar el modelo de paso a través (see-through) que diferencia las gafas ópticas de los headsets VR, y los escollos que te morderán en tu primera exportación.
Por qué el see-through óptico cambia tus supuestos de diseño
XREAL AURA es el primer dispositivo óptico see-through en Android XR. Esa sola frase rompe los supuestos arraigados en la mayoría de tutoriales de Godot XR.
En un headset VR, la cámara del headset renderiza todo. El usuario ve tu entorno y nada más. En gafas ópticas see-through, el usuario ve a través de las lentes el mundo real, y tu contenido renderizado se compone encima. Esto no es lo mismo que el paso a través por vídeo en una Quest: el video passthrough captura la realidad con cámaras y la vuelve a mostrar, lo que introduce latencia y pérdida de luz. El see-through óptico tiene cero latencia de composición para el mundo real.
Consecuencias prácticas para tu presupuesto de renderizado:
- No puedes oscurecer el mundo real. El negro en una pantalla transparente es transparente. No tienes fondo opaco, así que una UI que dependa del contraste sobre paneles oscuros fallará en una habitación luminosa.
- Gana el contenido de aspecto aditivo. El contenido emisivo brillante se lee bien; el contenido oscuro y desaturado desaparece. Diseña tu paleta con 2-3 veces la luminancia que usarías en VR.
- El campo de visión es más estrecho que en VR. El contenido colocado en ángulos extremos queda fuera del área de visualización. Mantén los objetivos de interacción principales dentro de aproximadamente ±30 grados del centro frontal.
Si has publicado en VR antes, espera tener que reajustar cada material y cada panel de UI. Presupuesta un día completo por escena para ello.
Configurar el editor de Godot en las gafas
El editor se distribuye en Google Play, no como un APK con sideload. Eso importa porque significa que puedes actualizarlo como cualquier otra app.
La secuencia de configuración:
- Instala el editor de Godot en XREAL AURA desde Play Store.
- Instala la app complementaria de entorno de build Gradle. Esta incluye la cadena de herramientas de exportación de Android, así no tienes que construir un JDK y un Android SDK desde cero en el dispositivo.
- Inicia sesión con una identidad de desarrollador de Android si planeas firmar y publicar builds desde el dispositivo.
- Lanza el editor: se abre en un espacio de trabajo espacial multi-ventana en lugar de una sola ventana plana.
Ese cuarto punto es el interesante. El editor te da el conjunto de funciones estilo escritorio, pero dispuestas como ventanas flotantes en el espacio. Puedes tener el Scene tree en un volumen y el viewport 2D en otro.
Lo que realmente te aporta el flujo de trabajo en el dispositivo
La respuesta honesta: iteración rápida en sensación, iteración más lenta en assets.
Editar shaders, ajustar transforms de nodos y probar mapeos de entrada en el dispositivo objetivo elimina todo el ciclo de exportación-prueba. Ese ciclo suele ser de 3-8 minutos una vez que cuentas el tiempo de build, transferencia y relanzamiento. Diez iteraciones son una hora perdida.
Lo que no ayuda: importar atlas de texturas grandes, ejecutar bakes largos de lightmap o cualquier cosa con mucho consumo de CPU. Eso hazlo en una estación de trabajo. La división realista es creación de assets en escritorio, ensamblaje de escena y ajuste en las gafas.
Construir contenido espacial con OpenXR Spatial Containers
El soporte Android XR de Godot incluye OpenXR Spatial Containers: volúmenes gestionados por el sistema donde tu app coloca contenido espacial. La analogía de la propia plataforma es casi exacta: las apps tradicionales dibujan contenido 2D dentro de ventanas en un escritorio; las apps espaciales dibujan contenido 3D dentro de contenedores en una habitación.
Hay dos tipos de contenedor que merece la pena entender antes de escribir código:
| Tipo de contenedor | Ideal para | Trade-off |
|---|---|---|
| Volume | Objetos 3D con profundidad real, colocación anclada al mundo | El sistema puede limitar los límites del volumen |
| Panel | Superficies de UI, texto, juegos 2D | Se renderiza en un plano fijo; las señales de profundidad son planas |
El error que comete la mayoría de desarrolladores es elegir volume para la UI. El texto en un contenedor volume se escala y mueve por el sistema de maneras que no puedes predecir del todo, y tu widget de radar cuidadosamente posicionado se desplaza. Pon la UI en un contenedor panel y deja que el sistema maneje la colocación.
Trabajar con la API de Spatial Containers
Godot expone los spatial containers mediante clases de extensión de OpenXR. Los nombres de clase exactos dependen de tu versión de Godot, así que revisa la lista de features del motor para los bindings actuales de spatial containers antes de escribir código de producción. El patrón de abajo refleja cómo se estructura típicamente el contenido XR basado en contenedores.
extends Node3D
signal container_created(handle: int)
# Spatial container setup for Android XR.
# Class names are version-dependent; verify against the
# OpenXR extension bindings shipped with your Godot build.
var volume_container: SpatialContainer
var panel_container: SpatialContainer
func _ready() -> void:
var xr_interface: XRInterface = XRServer.find_interface("OpenXR")
if xr_interface == null or not xr_interface.is_initialized():
push_error("OpenXR interface unavailable on this device.")
return
# Volume container for the 3D board.
volume_container = SpatialContainer.new()
volume_container.container_type = SpatialContainer.TYPE_VOLUME
volume_container.extent = Vector3(0.6, 0.4, 0.6) # 60cm x 40cm x 60cm
if volume_container.request_container() != OK:
push_error("Volume container request failed.")
return
# Panel container for the HUD.
panel_container = SpatialContainer.new()
panel_container.container_type = SpatialContainer.TYPE_PANEL
panel_container.extent = Vector3(0.4, 0.4, 0.02)
panel_container.request_container()
add_child(volume_container)
add_child(panel_container)
container_created.emit(volume_container.get_container_handle())
func _process(_delta: float) -> void:
# Containers can be rejected or resized by the system.
if volume_container and not volume_container.is_active():
_handle_container_loss()
func _handle_container_loss() -> void:
push_warning("Volume container lost - repositioning.")
# Never assume the container survives; re-request on loss.
volume_container.request_container()
La línea crítica es _handle_container_loss(). Los contenedores gestionados por el sistema están, por definición, gestionados por el sistema. El usuario se va, el asistente reposiciona el contenido o el dispositivo reclama espacio. Si tu manejo de entrada no sobrevive a la pérdida de un contenedor, tu app se quedará con un tablero invisible y un jugador machacando botones.
El escollo que casi todo el mundo encuentra: la deriva de anclaje (anchor drift)
Aquí está el problema concreto, y es el que te costará más tiempo de depuración.
Colocas un tablero 3D en un contenedor volume. Pulsas Play. Todo se ve bien. Te quitas las gafas, te las vuelves a poner dos minutos después, y el tablero ahora está medio metro a la izquierda y rotado 20 grados.
¿Por qué? Porque anclaste tu contenido al origen del mundo en lugar de al contenedor. El origen del mundo en un dispositivo espacial no es un lugar estable: se define en relación con la pose de inicio de la sesión. Cuando la sesión se reancla, el origen del mundo se mueve.
La solución es mantener cada pieza de tu escena como hija del transform del contenedor, y nunca leer ni escribir posición global para contenido espacial:
# WRONG: assumes world origin is stable
func place_piece(piece: Node3D, board_pos: Vector3) -> void:
piece.global_position = board_pos
# RIGHT: position relative to the container transform
func place_piece(piece: Node3D, board_pos: Vector3) -> void:
piece.position = board_pos # local to container
piece.rotation = Vector3.ZERO
Haz un grep en tu proyecto por .global_position y .global_transform antes de publicar. Cada aparición en contenido espacial es un posible bug de deriva. Esta clase de bug también aparece en trabajo 3D convencional y multiplayer: los errores de anclaje y propiedad en un transform replicado producen exactamente el mismo síntoma de "objeto teletransportado para algunos clientes", por eso tratar los transforms como locales al contenedor en lugar de absolutos es un hábito que merece la pena llevar a cualquier proyecto Godot en red.
Verificar la corrección
Para confirmar que el anclaje es correcto:
- Lanza tu escena y anota la posición del tablero.
- Quítate el dispositivo, espera 60 segundos, vuelve a entrar en la app.
- El tablero debería aparecer en la misma ubicación física relativa a la habitación, no en el mismo offset respecto a donde estés de pie.
- Repite con el dispositivo en otra orientación: sentado y luego de pie.
Si se desplaza, tu árbol de contenido todavía tiene referencias absolutas. Si salta pero se mantiene consistente después del salto, el contenedor está siendo reposicionado y tu contenido lo sigue correctamente: eso es comportamiento esperado, no un bug.
Manejar la identidad del jugador y el estado persistente
Las apps espaciales en Android XR son apps de Android. Se suspenden, se reanudan, el usuario puede tener varias identidades con sesión iniciada en el dispositivo, y tus datos de guardado viven en el mismo ecosistema de cuentas que todo lo demás.
El modo de fallo es sutil: un jugador juega espacialmente en las gafas y luego abre el mismo juego en su teléfono. Si tu estado de guardado es local al dispositivo, ahora tienen dos mundos divergentes y ninguna forma de reconciliarlos. Arreglar esto no es un problema de renderizado, es un problema de identidad de cuenta.
Hacerlo bien por tu cuenta implica implementar flujos de inicio de sesión, un almacén de guardado en servidor y —la parte que todos subestiman— gestión de conflictos cuando dos dispositivos escriben en el mismo slot de guardado. Un modelo de lectura/escritura consciente de revisiones donde el cliente compara versiones y resuelve conflictos explícitamente es la única versión que sobrevive al contacto con usuarios reales. Construir eso desde cero es un trabajo de varias semanas; horizOn proporciona guardado en la nube vinculado a la cuenta con lecturas y escrituras conscientes de revisiones exactamente para este caso, junto con autenticación por email, anónima, Google y Apple, de modo que la misma identidad de jugador se mantiene entre las gafas y el teléfono.
Sea cual sea el backend que uses, decide la política de conflictos antes de publicar. Last-write-wins destruye silenciosamente el progreso. Preguntar al jugador es mejor que perder datos.
Buenas prácticas para publicar en XREAL AURA
- Diseña para la luz ambiental. Prueba cada panel de UI al mediodía en exteriores y en una habitación oscura. Si tu texto se vuelve ilegible en cualquiera de las dos, sube el contraste y añade un contorno brillante sutil en lugar de una sombra oscura: las sombras no hacen nada en una pantalla transparente.
- Mantén los contenedores pequeños y re-solicitables. Un volumen de 60 cm es más fácil de colocar de forma fiable para el sistema que uno de 2 m. Asume que cualquier contenedor puede perderse en cualquier momento y escribe la ruta de recuperación primero, no al final.
- Recorta agresivamente tu presupuesto de renderizado. Son gafas, no una GPU de escritorio. Apunta a un tiempo de frame por debajo de 11 ms (clase 90 Hz) con el anti-aliasing temporal desactivado a favor de MSAA, que cuesta menos en resoluciones espaciales.
- Pon la UI en paneles y el contenido en volúmenes. No luches contra la lógica de colocación del sistema para el texto. Reserva los volúmenes para cosas con profundidad real que el jugador inspeccione desde varios ángulos.
- Verifica en el dispositivo antes de cada hito. El editor en las gafas hace que esto sea barato. Los resultados del simulador no revelarán la deriva de anclaje, los fallos de luminancia ni el comportamiento de pérdida de contenedores.
Dar el siguiente paso
El editor en el dispositivo es lo realmente destacado. Comprime el bucle de iteración espacial de minutos a segundos, y esa es la diferencia entre ajustar un diseño y adivinar uno.
Empieza instalando el editor y la app complementaria de Gradle en AURA, y luego reconstruye un pequeño proyecto existente como escena espacial en lugar de empezar de cero: sacarás a la superficie los problemas de anclaje y luminancia inmediatamente, en contenido que ya entiendes. Desde ahí, añade un contenedor volume 3D y un panel de UI y consigue que ambos sean estables a lo largo de un ciclo de suspensión/reanudación. Cuando eso se mantenga, estarás listo para diseñar para la plataforma en lugar de contra ella.
Si el estado persistente entre dispositivos está en tu lista, horizOn gestiona el guardado en la nube vinculado a la cuenta con resolución de conflictos en el cliente, de modo que tu sesión espacial y tu sesión en pantalla plana se mantengan de acuerdo.
Fuente: Listo para XREAL AURA