¿Cómo lograr una buena performance en un juego VR?

Performance VR

Qué aprendimos desarrollando en Unity para esta plataforma y qué herramientas usamos

POR FACUNDO BALBOA, TECHNICAL LEADER EN ETERMAX

Trabajando en etermax como programadores normalmente nos encontramos desarrollando aplicaciones de videojuegos para dispositivos móviles que corren en Android y iOS. Sin embargo, durante el 2022 decidimos apuntar a una nueva plataforma en el campo de realidad virtual: en nuestro caso, Oculus Quest 2 fue la plataforma que decidimos utilizar.

Al inicio nos encontramos con la gran ventaja de que no sólo era un único dispositivo, a diferencia de lo que nos sucede normalmente al trabajar para aplicaciones móviles, si no que además el mismo corría aplicaciones de Android, y esto nos presentó muchas facilidades. Sin embargo, se nos presentaron nuevos desafíos entre los cuales uno era la performance. Dentro del mundo VR, tener un buen framerate constante, 72 siendo lo recomendado por Meta, es una necesidad básica para que la experiencia del usuario sea agradable.

A su vez, no queríamos sacrificar calidad visual, por lo cual tuvimos que trabajar en conjunto programadores y artistas para aprovechar los recursos del dispositivo al máximo.

Desde esta problemática, comenzamos a investigar diversas fuentes y logramos una serie de guidelines a seguir para lograr una buena performance en un juego VR.

A continuación, se encuentran algunos datos que recopilamos y seguimos para poder lograr este objetivo:

Utilización de herramientas

En etermax casi siempre utilizamos Unity como herramienta para nuestros desarrollos. Algo muy positivo para nuestros workflows de trabajo fue que gran cantidad de herramientas internas que utilizamos en la empresa pudieron ser reutilizadas, ya que en esta ocasión volvimos a utilizar Unity como motor para nuestra aplicación en VR.

Algo fundamental para nosotros fue la investigación de herramientas que pudieran ayudarnos a la hora de desarrollar esta aplicación. Por ejemplo, el ya conocido Profiler de Unity y otras herramientas más específicas de desarrollo en el Oculus Quest 2. Veamos una por una las herramientas que decidimos utilizar.

Profiler: Esta herramienta clásica de Unity nos sirve para identificar usos excesivos de recursos en algunos casos puntuales. Tiene la utilidad de que podemos ver la fuente de esos gastos de recursos. Sin embargo, el mayor uso extra que podemos darle es el Bridge Profiling.

Bridge Profiling: Es quizá la herramienta que menos uso tuvo al inicio pero luego demostró ser de gran utilidad. Se trata de mantener el dispositivo conectado y crear una build para el mismo. Una vez que esté listo, permite tomar las métricas de performance en el profiler directamente desde el dispositivo. Esto es una gran ventaja sobre hacer Profiler en editor, ya que el uso del Profiler en cuanto a performance es menor, ensucia mucho menos la evaluación, y lo más importante, se prueba  la aplicación directamente en el dispositivo con los recursos y su comportamiento normal.

Frame Debugger: También es otra herramienta que trae Unity y la utilizamos principalmente para poder analizar la cantidad de Draw Calls que tuvimos por frame. Uno de los principales datos que encontramos en esta herramienta es el motivo por el cual un Draw Call no pudo ser batcheado con el anterior. Esto nos permite buscar otra solución posible en cuanto al uso de materiales por ejemplo.

OVR Metrics: Una de las herramientas específicas de Oculus para poder analizar el uso actual del dispositivo. Una práctica que comenzamos a utilizar en el equipo fue tener siempre habilitado el OVR Metrics en overlay para buscar bajas de performances o comportamientos extraños. Con el tiempo, al utilizar VR de manera cotidiana, varios de nosotros desarrollamos una resistencia mayor al motion sickness con lo cual tenemos un sesgo sobre la percepción a posibles caídas de framerate. Mantener estas métricas constantemente nos ayuda a visualizar mejor estos problemas.

La herramienta nos permite visualizar, entre otras cosas, el frame rate, el uso del CPU y el GPU, los frames early y stale. Principalmente de acá utilizamos la información del frame rate para cumplir con el requerimiento de Meta y los usos de CPU y GPU para no utilizar recursos innecesariamente todo el tiempo. Es importante utilizar al mínimo los recursos para garantizar más duración de batería.

RenderDoc: Una de las herramientas más completas, si no la más completa, que toma una captura de una aplicación con todos sus modelos, texturas, materiales y drawcalls entre otros y nos permite inspeccionarlos para encontrar problemas o fallas. Si bien su uso no es tan intenso y cotidiano como pueden ser otras herramientas, al momento de encontrar un problema difícil de identificar es la herramienta que nos permite hacerlo.

Project Auditor: Esta herramienta es desarrollada por Unity y se puede conseguir desde el Package Manager pero aún no tuvimos un uso extenso de la misma. Encontramos que la herramienta genera rápidamente un informe con problemas de performance de todo tipo en el proyecto. 

Estos problemas que identifica son problemas en las prácticas dentro del código, configuraciones que pueden mejorarse en Project Settings, mejoras que se pueden hacer al uso de assets, información sobre los shaders que se están utilizando y un análisis del tiempo de build y el tamaño final.

Todas estas herramientas nos están siendo útiles al momento de desarrollar para VR en Unity que tanto cuidado a la performance requiere. Algunas fueron más fáciles e intuitivas de implementar y pedirle el uso a todo el equipo, como es el ejemplo de OVR Metrics, mientras que otras por ahora son más utilizadas por gente especializada, como es el caso de RenderDoc, principalmente utilizada por artistas técnicos. Independientemente del caso, buscamos que todo el equipo vele por la performance ya que aprendimos y creemos que es fundamental al momento de desarrollar cualquier aplicación, pero principalmente en VR.

Power Management

Durante nuestra investigación, descubrimos  que podíamos modificar el poder de procesamiento del dispositivo. Esto es importante por varias razones. 

En principio, todos los dispositivos de Android se encuentran normalmente afectados por el poder de procesamiento del dispositivo y su capacidad de disipar el calor que este genera.

Acá nos juegan dos cosas que queremos mantener balanceadas. Una es que necesitamos tener la mayor cantidad de recursos disponibles, ya que necesitamos ser capaces de poder mantener un buen framerate. Pero por otro lado, esto nos juega en contra al momento de buscar una buena optimización en general ya que aumenta la temperatura del dispositivo, afectando el rendimiento, y consume un mayor uso de batería, siendo que Meta pide específicamente un mínimo de vida al dispositivo desconectado teniendo la aplicación abierta.

Debido a esto, debimos buscar un balance entre cuánto queríamos pedir de recursos en cada situación y la realidad es que no existe un número mágico o predefinido. De hecho, el número por defecto si este valor no se modifica es utilizar al máximo todos los recursos constantemente.

Desde el SDK de Oculus no pudimos asignar un valor específico para estos recursos ya que, al momento de escribir este artículo, se encuentra depecado. Lo que sí se puede hacer, es asignar una sugerencia al CPU y al GPU de cuál es el valor que esperamos utilizar.

Los valores disponibles, yendo de menor a mayor uso, son: PowerSavings, SustainedLow, SustainedHigh y Boost. En base a estos, decidimos hacer un par de pruebas asignando SustainedLow tanto al CPU como al GPU:

OVRManager.suggestedCpuPerfLevel = OVRManager.ProcessorPerformanceLevel.SustainedLow;

OVRManager.suggestedGpuPerfLevel = OVRManager.ProcessorPerformanceLevel.SustainedLow;

Desde ahí, probando con la aplicación y el OVRMetrics abierto, encontramos que el framerate no se vió afectado en sí mismo, con lo cual al usuario era imperceptible. Más aún, notamos que para el CPU la mayor parte del tiempo se encontraba en SustainedLow subiendo sólo de a ratos al ser necesario mientras que para el GPU se mantenía principalmente en SustainedHigh subiendo momentáneamente a Boost

También notamos una caída mínima del framerate más marcada al momento de tener que cargar cosas debido al cambio en los niveles de uso de los recursos del dispositivo pero al ser sólo por unos segundos durante una pantalla de carga, decidimos priorizar mantener un valor bajo y dejar que el dispositivo ajuste el resto.

Conclusión

Durante todo este tiempo de desarrollo en Unity para la plataforma VR fuimos no sólo aprendiendo sobre la importancia de la performance, que se vuelve fundamental y más compleja en este tipo de proyectos, si no que también fuimos aprendiendo como realmente ocuparnos de la misma.

Ya no sólo se trató de mantener texturas en potencia de dos, utilizar atlas y bajos polígonos. Aprendimos sobre la utilización de herramientas de manera extensiva más allá del profiler y creamos prácticas a nivel equipo para poder velar en conjunto sobre cómo identificar estos problemas para luego resolverlos.

También es importante pensar en la performance no sólo como no provocar errores genéricos sino también pensar en que es necesario para la plataforma que desarrollamos. Investigar sobre cómo funciona el hardware específico, aprovechando al ser único en principio, es algo fundamental cuando el objetivo es exprimir todos los recursos del dispositivo.

En resumen, la recomendación al desarrollar en VR es hacer una investigación exhaustiva sobre el funcionamiento del dispositivo y las recomendaciones a tener en cuenta sobre la performance del mismo. Luego adquirir las herramientas necesarias para poder hacer esas mediciones y aprender a usarlas. Y durante todo el desarrollo, pasar el ownership al equipo sobre velar por esas métricas de performance para identificar los problemas lo antes posible y solucionarlos para evitar problemas a largo plazo.