Resolviendo problemas técnicos y de rendimiento en Laser Matrix

Marius Thorvaldsen, Martin Sivertsen y Sindre Askim Gronvoll fundaron Breach en 2016 para crear juegos inmersivos, experiencias XR y simulaciones 3D. En los últimos nueve años, el estudio de trabajo por encargo ha entregado soluciones XR mientras también desarrollaba sus propios juegos. En 2024, generaron ideas y comenzaron a prototipar mientras buscaban un nuevo proyecto interno. Un concepto de juego rápidamente entró en producción para convertirse en Laser Matrix.
El título es un juego de acción de rompecabezas de realidad mixta donde el fitness, la diversión y los desafíos futuristas colisionan. Los jugadores pueden resolver rompecabezas basados en luz, esquivar láseres en movimiento y desbloquear niveles usando su agilidad e ingenio.
Nos sentamos con Andreas Weibye, director de ingeniería en Breach, y Jonathan Jørgensen, uno de los desarrolladores del juego, para discutir la construcción del juego para Meta Quest y Android XR, y cómo superaron desafíos técnicos y de rendimiento.
¿Qué es Laser Matrix?
Andreas: Laser Matrix es un rompecabezas de acción de movimiento en VR. Es muy parecido a un arcade y puede convertir tu sala de estar en un laberinto peligroso por el que tienes que moverte rápida y hábilmente.
¿Cómo funcionó el proceso de implementación para Meta Quest y Android XR?
Andreas: No implementamos Meta Quest y Android XR simultáneamente desde el principio del proyecto. El prototipo comenzó solo para Meta Quest. Hemos trabajado extensamente con la plataforma, así que lo pusimos en marcha rápidamente. Android XR tampoco existía cuando comenzamos este prototipo, así que terminamos portando durante el proceso de desarrollo.
Jonathan: Comenzamos con la herramienta de "bloques de construcción" de Meta para hacer prototipos rápidos. Hizo que validar el concepto fuera más conveniente. Eventualmente nos dimos cuenta de que queríamos apuntar a XR multiplataforma y nos aseguramos de estructurar el juego de una manera más agnóstica a la plataforma. La jugabilidad central no depende realmente de características específicas de la plataforma, por lo que fue una transición fácil pasar a multiplataforma.

¿Qué pasos tomaste al implementar el seguimiento de manos en OpenXR?
Jonathan: Leímos datos de seguimiento en tiempo real del runtime de OpenXR. Los datos se procesan a través de capas de abstracción donde los datos en bruto se convierten en posiciones y rotaciones que luego se aplican a las mallas de las manos. Estas mallas de manos se interfazan con los sistemas de interacción integrados en Unity, que proporcionan utilidades para cosas comunes como tocar algo con tu dedo. Luego, finalmente, nuestras propias capas de jugabilidad encima de eso.
Todo se trata de la abstracción multicapa de esos datos en bruto. Muchos juegos de XR a menudo tienen necesidades similares, así que tratamos de usar soluciones existentes estables tanto como fuera posible y las unimos de manera ordenada. Para Laser Matrix, no hay muchos aspectos no estándar en el seguimiento de manos.

¿Qué desafíos técnicos encontró el equipo?
Andreas: Es una configuración de OpenXR bastante lista para usar en lo que respecta a la escena y los componentes utilizados. Tuvimos que sortear problemas relacionados con los momentos en que las manos pierden o ganan seguimiento y aparecerían en una ubicación diferente en ese fotograma. En algún momento, los jugadores comenzaron a perder el seguimiento de las manos, lo que les hizo perder vidas.
Jonathan: Diseñar en torno al seguimiento de manos fue uno de los mayores desafíos. Los diferentes puntos de contacto en la mano causaron algunos problemas. Es más sencillo para interacciones de UI normales y lentas, como presionar un botón. Sin embargo, en Laser Matrix, estás moviendo constantemente tu cuerpo y cabeza, lo que puede reducir la precisión del seguimiento de manos basado en cámara.
Andreas: Para la UI fuera del juego, implementamos botones que necesitas tocar con tus dedos, en lugar de usar raycasting. En nuestra experiencia, el raycasting con seguimiento de manos no es lo suficientemente preciso para tener una gran experiencia de juego, así que esto ayudó.
Jonathan: Para juegos de "pantalla plana", los desarrolladores pueden limitar cómo se utilizan entradas como el ratón, el teclado y los controladores. XR es diferente, porque un juego nunca puede detener verdaderamente tus manos físicas. Por ejemplo, los botones en el menú de Laser Matrix son bastante planos, y puedes empujar tu mano a través del botón. Esta es una interacción para la que no necesariamente diseñas, y no está claro qué debería suceder realmente. ¿Es una pulsación de botón válida? En general, hay algunas implicaciones interesantes que siguen cuando traduces patrones de interfaz de usuario más tradicionales a XR.

¿Qué problemas relacionados con el rendimiento encontró el equipo?
Andreas: Nuestro principal problema de rendimiento está en el lado gráfico. Desde el principio, se trata de encontrar el equilibrio con el sobre-dibujo de transparencia. Es uno de los mayores desafíos con el diseño de juegos actual porque si solo usaras contornos para estas cajas, puedes ver dónde están al mirar hacia arriba o hacia abajo y compararlas con algo. Pero cuando miras hacia adelante y estás tratando de entender tu distancia de una pared o cuán lejos puedes extender tu mano sin tocar, eso es más difícil.
Dado que queremos que el usuario pueda ver todo el laberinto al mismo tiempo y tomar decisiones estratégicas de ubicación, necesitamos una solución de transparencia o una alternativa, ambas intensivas en GPU.
Jonathan: Algunas de nuestras soluciones afectaron los visuales finales del juego. Por ejemplo, cambiamos el borde amarillo exterior del área de juego. Solía tener un tono amarillo transparente cubriendo toda la superficie de la pared, pero lo redujimos solo a los bordes, con un desvanecimiento gradual a completamente transparente. Dado que el borde del juego es visible en todo momento al jugar, esto redujo consistentemente el número de llamadas de sobrecarga, que fue uno de los principales contribuyentes a nuestro tiempo de fotogramas.
También observamos los cubos láser rojos que el jugador está tratando de evitar al moverse en el juego. Tienen un patrón de cuadrícula cuadrada en su superficie. Podríamos aplicar el mismo enfoque que con el cubo de borde amarillo, tratando de reducir la sobrecarga nuevamente. Dado que solo los bordes de las celdas de la cuadrícula se renderizan completamente, hicimos las celdas más grandes, lo que resultó en que más de la superficie fuera completamente transparente en promedio.
También hubo algunos problemas de rendimiento relacionados con la carga. Ocurrió un gran pico cada vez que comenzaba el nivel. Al principio, solo asumimos que estaba relacionado con la carga de niveles en general. Cargar un nivel de Matriz Láser significa que muchos elementos diferentes tienen que ser generados. Sin embargo, el culpable era específicamente la música. A través de la perfilación, descubrimos que el sistema recargaba el audio con cada nivel. Lo configuramos para precargar la música con la aplicación en su lugar, lo que hizo que el pico fuera imperceptible.
Andreas: Algunos de nuestros problemas de rendimiento surgieron porque convertimos un prototipo en un juego de producción. Deberíamos haber reescrito el sistema.

¿Qué herramientas y características de Unity fueron fundamentales durante la construcción?
Andreas: El beneficio de Unity es que nos permite crear un activo y un código y que funcione en múltiples plataformas desde el principio.
VFX Graph fue genial porque permitió a nuestro propietario del producto, que no tiene inclinación artística, esbozar lo que imaginaba que deberían parecer los efectos visuales. A partir de ahí, nuestro artista técnico y desarrollador lo pulieron.
Jonathan: Shader Graph fue una herramienta muy valiosa para hacer el juego. La mayoría de los elementos 3D del juego son shaders puros. Aparte de algunos cubos, manos y botones, hay muy pocos modelos 3D reales en este juego.
El simulador de dispositivos XR también se utilizó mucho. Cuando trabajas en XR, las pruebas pueden ser bastante físicas y agotadoras a largo plazo. Entre todos los pasos: levantarse, ponerse el visor, moverse y más, las horas realmente se acumulan. Al configurar el simulador y usar entradas de mouse para estimular interacciones, hemos ahorrado mucho tiempo y frustración.
Andreas: Dado que tenía el simulador de dispositivos XR disponible desde el principio, quería desarrollar nuevas características de maneras que pudiera probarlas más fácilmente en aislamiento. Me empujó a escribir sistemas más modulares y probables desde el principio, lo que también mejoró nuestra calidad de código.
Jonathan: El profiler de Unity también fue clave para ayudarnos a detectar de dónde venían los picos de rendimiento. Por ejemplo, con el problema de carga de audio que mencioné, el profiler nos ayudó a identificar tanto el pico como las llamadas activadas en ese momento exacto. Este tipo de información generalmente proporciona algunas pistas claras sobre dónde deberías comenzar al implementar una solución.

¿Qué nuevas características o actualizaciones en Unity 6 fueron más beneficiosas?
Jonathan: Construimos para bastantes objetivos y en diferentes contextos. Al ir multiplataforma, necesitamos que las construcciones tengan diferentes configuraciones para características y servicios específicos de la plataforma. Así que la capacidad de tener perfiles de construcción en Unity 6 nos permitió adaptar nuestras construcciones para esas diferentes plataformas. Hacer esto manualmente sería tedioso y propenso a errores.
¿Qué métricas clave de rendimiento tenías?
Jonathan: Cuando señalamos los problemas de rendimiento, que es un gran problema en XR específicamente debido a la cinetosis, medimos el fps promedio y buscamos caídas de fotogramas. Hay objetivos bien definidos sobre lo que es cómodo o no.
Al ajustar los umbrales en los diferentes shaders de cubo, ganamos alrededor del 10% en fps. Perfilamos el juego en un entorno de prueba donde dibujamos el número máximo de cubos para el juego. Esto nos proporcionó un contexto muy fijo y confiable para las pruebas.
Andreas: Para el rendimiento, nuestros límites duros son 72 fps en el Meta Quest 2 y 90 fps en el Meta Quest 3. Estamos en camino para la tasa de fotogramas promedio, pero podemos producir situaciones donde el usuario obtiene un resultado más bajo. Estos son casos muy específicos donde puedes terminar en el peor lugar posible.
Jonathan: A nivel de proyecto y equipo, nuestro tiempo de iteración se ha vuelto mucho más eficiente en los últimos meses. Como empresa, maduramos nuestro proceso de aseguramiento de calidad y lo vinculamos a nuestra pila de automatización, y ahora nuestro ciclo de retroalimentación y corrección es bastante rápido. Podemos abordar problemas lo suficientemente rápido como para que una acumulación de tareas no se acumule ni se descontrole.

¿Hay algo que el equipo desearía haber hecho de manera diferente durante el desarrollo?
Andreas: Deberíamos haber comenzado a usar OpenXR un poco antes. Al principio del proyecto, planeamos usar la función de marcado de habitaciones de Meta para definir la forma y el tamaño del área de juego. Si bien funcionó, no nos dio la funcionalidad de juego que estábamos buscando sin también abrir desafíos de diseño para los que aún no teníamos grandes soluciones. Nos dimos cuenta de eso durante la discusión sobre el escaneo de habitaciones. Deberíamos haber descartado ese sistema antes porque pasamos demasiado tiempo tratando de resolverlo. Además, mirando hacia atrás, una vez que el código de prototipo evolucionó a código de producción, reconocer que el sistema ya no servía al diseño habría ahorrado tiempo.
Para leer más sobre proyectos hechos con Unity, visita la página de Recursos.
