Parte: 13 — VR, AR y experiencias inmersivas · Fuente: Documentación de XR y del renderer Mobile de Godot 4, y guías de rendimiento de Meta Quest ⏱️ Duración estimada: 85 min · Nivel: Avanzado
En un juego plano, una caída de frames es una molestia; en VR, es un problema físico: por debajo del framerate objetivo del visor el cerebro detecta el desfase entre movimiento y visión y aparece el mareo (cybersickness). Por eso los 90 fps (o 72/120 según el visor) no son un lujo, son un requisito. Además hay que renderizar dos veces, una por ojo, con un presupuesto de frame diminuto. En esta clase aprenderás a presupuestar el frame en XR y a usar las herramientas del motor: foveated rendering, MSAA, el renderer Mobile para standalone (Quest) y la reducción de draw calls y overdraw.
En el laboratorio configurarás un proyecto VR para Quest —renderer Mobile, MSAA y foveation— medirás el framerate real y aplicarás optimizaciones hasta sostener el objetivo. El principio: medir primero, optimizar lo que de verdad cuesta.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | El mareo y el framerate | Explica por qué 90 fps son obligatorios. |
| 2 | Presupuesto de frame en XR | Tienes ~11 ms para dos ojos a 90 fps. |
| 3 | Renderer Mobile | Necesario para standalone como Quest. |
| 4 | Foveated rendering | Ahorra píxeles fuera del centro de la vista. |
| 5 | MSAA | Antialiasing asequible y clave en VR. |
| 6 | Draw calls y batching | Cada llamada cuesta; menos es más rápido. |
| 7 | Overdraw | Pintar píxeles varias veces desperdicia GPU. |
| 8 | Medir antes de optimizar | Evita optimizar lo que no cuesta. |
Trabaja sobre un proyecto VR con OpenXR activado (clase 231). Para Quest necesitas los export templates de Android y el visor en modo desarrollador (por Link para iterar rápido, o exportando el APK). Cambia el backend de render en Project → Project Settings → Rendering → Renderer a Mobile. Ten a mano el monitor de rendimiento (Debug → Monitors) y la clase Performance para leer fps y draw calls por código.
Referencias: renderers de Godot en https://docs.godotengine.org/en/stable/tutorials/rendering/index.html, optimización en https://docs.godotengine.org/en/stable/tutorials/performance/index.html y guías de Quest de Meta en https://developer.oculus.com/documentation/.
Configuraremos un proyecto VR para Quest y sostendremos el framerate objetivo.
En Project Settings → Rendering → Renderer, selecciona Mobile. Es el backend adecuado para la GPU del Quest y para el export Android que usa el standalone.
Activa el antialiasing MSAA en Rendering → Anti Aliasing → MSAA 3D a 2x. En VR, MSAA suaviza bordes sin el coste de otras técnicas. Evita 4x salvo que sobre presupuesto.
Activa el foveated rendering de OpenXR. En el gestor XR, tras inicializar, sube el nivel de foveation para descargar la periferia:
extends Node3D
@onready var interfaz_xr: XRInterface = XRServer.find_interface("OpenXR")
func _ready() -> void:
if interfaz_xr and interfaz_xr.is_initialized():
get_viewport().use_xr = true
# Foveation: 0 = off, valores altos = mas ahorro en periferia.
get_viewport().vrs_mode = Viewport.VRS_XR
print("Renderer Mobile + foveation activos.")
else:
push_error("OpenXR no inicializado.")
extends Label
func _process(_delta: float) -> void:
var fps := Engine.get_frames_per_second()
var draw_calls := Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME)
text = "FPS: %d | Draw calls: %d" % [fps, draw_calls]
Ejecuta con el visor y lee el framerate. Si está por debajo del objetivo, no toques nada aún: identifica la causa. Mira las draw calls: si son altas, el cuello es CPU; si el framerate cae al acercarte a superficies grandes translúcidas, es overdraw.
Reduce draw calls: agrupa mallas estáticas que comparten material (usa instancias del mismo Mesh), desactiva sombras en objetos que no las necesitan y baja el número de luces dinámicas. Vuelve a medir tras cada cambio.
Reduce overdraw: elimina transparencias innecesarias, recorta partículas y evita geometría superpuesta. Sube MSAA solo si tras estabilizar el framerate sobra margen. El objetivo es un framerate estable en el número que pida tu visor, no picos altos con caídas.
Con el presupuesto controlado, la experiencia se siente fluida y cómoda. En la próxima clase añadimos audio espacial y hápticos.
Toma una escena VR que caiga por debajo del framerate objetivo y optimízala hasta sostenerlo de forma estable, usando renderer Mobile, MSAA y foveation, y reduciendo draw calls y overdraw. Documenta el framerate antes y después y qué cambio produjo cada mejora.
Criterio de aceptación: la escena mantiene el framerate objetivo del visor de forma estable durante movimiento, y el alumno puede señalar con datos medidos (fps y draw calls) qué optimización aportó cada ganancia.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| El visor va a tirones y marea | Framerate por debajo del objetivo. Reduce carga hasta sostenerlo estable. |
| No mejora pese a optimizar | Optimizaste algo que no era el cuello. Mide antes: mira fps y draw calls. |
| Bordes muy dentados | MSAA desactivado o a 0. Súbelo a 2x en el renderer Mobile. |
| Framerate cae cerca de cristales/humo | Overdraw por transparencias. Reduce o elimina las capas translúcidas. |
| El export a Quest no arranca | Falta renderer Mobile o export templates Android. Configúralos antes de exportar. |
❓ ¿Por qué exactamente 90 fps y no 60? Cada visor fija su objetivo (72/90/120). Por debajo, la reproyección y la latencia provocan mareo. Cumple el número de tu visor.
❓ ¿El foveated rendering se nota? Bien calibrado, apenas: el ojo solo ve nítido el centro. Un nivel excesivo sí deja borrosa la periferia.
❓ ¿Uso renderer Forward+ o Mobile en Quest? Mobile. Forward+ apunta a GPU de escritorio; el standalone necesita Mobile por el export Android.
❓ ¿Optimizo antes de medir? Nunca. Mide primero para saber si el cuello es CPU (draw calls) o GPU (overdraw/resolución) y ataca la causa real.
Clase 236 - AR con ARCore y ARKit