Optimización de Sonic Dream Team para alcanzar objetivos FPS en dispositivos Apple Arcade

Sonic Dream Team es un juego de plataformas desarrollado por Hardlight y publicado por SEGA. El juego, una parte de la serie Sonic the Hedgehog, tiene a Sonic y a sus amigos atravesando los retorcidos paisajes oníricos del malvado Doctor Eggman para frustrar su búsqueda de dominación del mundo.
Apple Arcade exige que los estudios alcancen los mismos objetivos de rendimiento en todos los dispositivos compatibles, lo que ejerce más presión sobre el equipo para que optimice a fin de que el juego se vea genial en todo, desde un iPhone 6s Plus hasta un iPhone 16. Esta es la manera en que alcanzaron la tasa de frames requerida en dispositivos de gama baja y alta.
EL DESAFÍO:
Creación de un juego de alta fidelidad y rendimiento en una amplia gama de dispositivos
PLATAFORMA:
Apple Arcade (iOS, macOS, tvOS, iPadOS)
UBICACIÓN:
Warwickshire, U.K.
PERSONAL DEL PROYECTO:
20 artistas, 10 ingenieros y 8 diseñadores
Sonic Dream Team: Caso de estudio de Unity
¿Cómo se optimiza un equipo para alcanzar la tasa de frames requerida en dispositivos tanto de gama baja como alta?
Después de 10 años con el erizo, Hardlight quería un nuevo desafío ampliando la historia, con más personajes y combinando estilos de acción y aventura con imágenes de alta fidelidad. Eso se veía genial en todos los dispositivos donde se pueden jugar juegos Apple Arcade. Mientras trabajaban para lograr estos objetivos, el equipo encontró problemas de rendimiento relacionados con CPU y GPU que los impulsaron a seguir optimizando.

Los resultados
Redujeron los tiempos de frames de CPU de 52 ms a 16 ms en dispositivos de potencia media y alta
Redujeron a la mitad el tamaño de compilación en iOS de 4 GB a 2 GB
Reducción del tiempo de ejecución de la variante de shader de 1 GB o más a menos de 100 MB
Abordar problemas de renderizado
Para analizar el rendimiento, el equipo utilizó las diferentes herramientas de análisis que ofrece Unity, en particular Profiler, Frame Debugger y Memory Profiler. Esto ayudó al equipo a entender mejor de dónde vinieron los problemas para llegar a 30 FPS y 60 FPS en todos los dispositivos.
El renderizado representó una gran parte del presupuesto total para frametime, especialmente en dispositivos de baja gama. El equipo recurrió a la agrupación por lotes SRP para ayudar a reducir este costo.
"Elegimos el canal de renderizado universal (URP) debido a su enfoque de renderizado moderno y al soporte continuo que nos brinda Unity en el futuro", dice Fraser Hutchison, artista técnico de Hardlight. El equipo priorizó funciones como SRP Batching y Shader Graph para permitir nuevas formas de enviar sus imágenes a los dispositivos móviles. "El mezclador SRP hizo mucho trabajo pesado por nosotros y les dio a nuestros artistas la flexibilidad de no preocuparse por las restricciones de materiales, como sucede con el mezclador estático estándar", continúa Hutchison. "Tuvimos un promedio de 100 a 200 lotes, principalmente estando en la cola opaca, lo que funcionó bien".

Sonic Dream Team | Hardlight | SEGA
El equipo también redujo las sondas de reflexión y utilizó una cola de clasificación de materiales e iluminación integrada para aumentar la eficiencia del procesamiento por lotes y reducir su costo de renderizado.
Debido al tamaño de sus niveles, implementaron un sistema de culling de volúmenes jerárquico personalizado para reducir la sobrecarga del renderizado. "Cada nivel se dividió en grandes fragmentos, que llamamos 'islas', y se desactivó o activó según la posición del jugador", dice Hutchison. "Esto también significó que pudimos desactivar los animadores y los efectos de partículas para esas islas. En general, esta fue una solución ligera que se adaptó bien a nuestras necesidades».

Sonic Dream Team | Hardlight | SEGA
"Los artistas del equipo querían gráficos de alta fidelidad con muchos datos de malla únicos, efectos de shader y posprocesamiento para ayudar a impulsar la calidad onírica del mundo que estaban creando. Con el URP, al tener funciones tales como el posprocesamiento integrado, podemos simular imágenes rápidamente sin necesitar siempre soluciones completamente personalizadas". Simon Dew, director de arte de Hardlight
Reducir los tiempos de frames de CPU
Para garantizar una jugabilidad uniforme en todos los dispositivos iOS, el equipo de Hardlight estableció su frecuencia física en 60 Hz, en lugar de los 50 Hz predeterminados. Usaron FixedUpdate para imponer un paso temporal esperado entre las actualizaciones de un objeto particular a fin de mejorar el determinismo.
Cuando el tiempo de frames aumenta significativamente debido a problemas de rendimiento, se realizan varias llamadas a FixedUpdate dentro de un solo frame en Unity para mantener la tasa de actualización de física deseada.
"Finalmente, la simulación no pudo procesar todas las actualizaciones necesarias a tiempo, lo que generó tiempos de frames aún mayores", dice Louis Macan, ingeniero de software en jefe de Hardlight. El impacto de tener el mismo paso de tiempo de física generó un aumento en la cantidad de llamadas a FixedUpdate por frame en dispositivos de gama baja, que ejecutan el juego a 30 FPS.

Sonic Dream Team | Hardlight | SEGA
Para mantener una buena tasa de frames en dispositivos antiguos, como el iPhone 6S Plus, el equipo optimizó cada actualización fija. Al medir el rendimiento de una llamada de FixedUpdate individual, notaron que la gran mayoría del tiempo de FixedUpdate se retenía mediante llamadas de actualización de cientos de instancias de scripts. Aunque estos scripts salieron rápidamente mediante una condición de salida anticipada, las llamadas a FixedUpdate aún se ejecutan.
"Incluso si parece que FixedUpdate no está haciendo nada si no se cumple una condición, cada función de evento Unity declarada en un script causará una sobrecarga", dice Macan. "Si bien la carga adicional es pequeña, las miles de llamadas de actualización, actualización fija y actualización tardía ejecutadas por scripts agregados durante la creación del nivel tuvieron un gran impacto".
Para solucionar esto, se requería una combinación de enfoques. Primero, se agregó un administrador para que los scripts se registraran a sí mismos y el administrador marcaba cada objeto por turno con la frecuencia de actualización requerida. Eso significaba que se podían eliminar todas las funciones de los eventos Unity y que ya no ocupaban tiempo en el CPU. Por último, se configuró que los objetos que no interactuaban con la física del jugador marcaran Update (actualización), lo que redujo a la mitad el costo computacional en los dispositivos de baja gama.

Sonic Dream Team | Hardlight | SEGA
Mejora de los Particle Systems del juego
El equipo también notó que la cantidad excesiva de Particle Systems en una escena afectaba el rendimiento del CPU. Como parte de un sistema de agrupación de partículas, el equipo habilitó o desactivó los sistemas de partículas utilizando la API ParticleSystemRenderer mediante un componente personalizado de ParticleEffectsWrapper. Dado que se procesaron más de 500 actualizaciones del Particle System en el subproceso principal y el subproceso principal, esto tomó alrededor de 5.2 ms de tiempo de frames de CPU.
"Visual Effect Graph de Unity no era una opción para nosotros en este proyecto, ya que muchos de nuestros dispositivos de gama baja no admiten computación de GPU en la que confía ese sistema", dice Hutchison. «Si hubiéramos podido usarlo, nos habríamos beneficiado de su mejor tecnología de creación de instancias».
Los sistemas de partículas en Unity pueden ser procedimentales o no procedimentales. Un Particle System procedimental se puede rebobinar libremente o avanzar rápidamente en cualquier momento.
"Con procedural, Unity puede eliminar de forma segura el Particle System y todo su procesamiento asociado cuando está fuera de la pantalla, y luego simplemente avanzar rápidamente al estado correcto cuando vuelva a ser visible", dice Hutchison. "Esto puede generar mejoras considerables en el rendimiento. Sin embargo, esto a menudo se pasa por alto en la creación de efectos de partículas y es muy fácil hacer que el efecto sea accidentalmente no procedimental".

Sonic Dream Team | Hardlight | SEGA
Para evitar esto, el componente ParticleEffectsWrapper no solo eliminaba las partículas según el tronco de la cámara, sino que también definía límites de renderizado personalizados para que, incluso si una partícula se marcaba como procedimental, los límites establecidos manualmente pudieran eliminar el sistema.
"Con una gran cantidad de Particle Systems en una escena, se hizo importante asegurarse de que la mayor cantidad posible de sistemas fueran procedimentales y, si no, que sus límites de renderizado estuvieran establecidos en el componente ParticleEffectWrapper", dice Macan. «Esto evitó cómputos y llamadas de dibujo innecesarios, lo que mejoró significativamente el rendimiento».
Junto con el culling, el equipo priorizó las buenas prácticas de creación para lograr efectos. Usaron solo la cantidad de Particle Systems necesaria y fijaron el máximo de partículas para reducir el sobredibujo alfa y la asignación de memoria. También se enfocaron en trabajar con el atlas de textura de sus efectos de partículas y evitar tiempos de duración excesivos. También habilitaron el procesamiento dinámico por lotes a través del selector «Show All Hidden Properties» (mostrar todas las propiedades ocultas) en la configuración de renderizado del URP. Este pequeño cambio ayudó a reducir las llamadas de extracción de partículas y a acelerar el renderizado.

Sonic Dream Team | Hardlight | SEGA
Encontrar cuellos de botella en la GPU
La Vision de Sonic Dream Team requería gráficos avanzados y un juego rápido. Para la personalización, utilizaron funciones de renderizado para ciertos efectos, como Screen Space Ambient Occlusion (oclusión ambiental del espacio de pantalla), efectos personalizados de pantalla completa y decals de espacio de pantalla. Esto generó retrasos en el renderizado y problemas de memoria.
"Durante el desarrollo, descubrimos que, al utilizar decals de espacio de pantalla basados en profundidad para personajes y sombras de blob enemigas, la función de renderizado provocaba una prepasada normal de profundidad innecesaria", dice Hutchison. "Esto significó que una gran parte del tiempo de renderizado se invirtió en trabajo innecesario y aumentó la memoria objetivo del renderizado, ya que no necesitábamos el búfer normal. Trabajamos con el equipo de Unity para resolver esto, y la corrección se agregó en una versión de parche del motor».

Sonic Dream Team | Hardlight | SEGA
El precalentamiento de los shaders también fue un problema, con picos significativos de CPU/GPU en todos los niveles que causaron tartamudez. "Para precalentar eficazmente los shaders en Metal, los shaders deben contener todas las palabras clave requeridas y tener el grupo de layout de vértices específico de cada malla en la que se renderizarán. Eso significaba que no era posible almacenar el caché solo para el Editor", dice Hutchison.
Para combatir esto, los ingenieros de Hardlight crearon un sistema para «renderizar flasheando» todos los objetos frente a la cámara en el momento de la carga, detrás de la pantalla de carga.
«Nuestra tecnología de Island Culling facilitó el acceso a las listas de todos los renderizadores que aparecen en la escena. Al hacer esto en el dispositivo, teníamos todos los datos del estado del canal y las palabras clave correctas de la configuración de calidad antes de que el jugador ingresara oficialmente al nivel", dice Hutchison. "Esto aumentó ligeramente los tiempos de carga del nivel, pero valió la pena por la experiencia del jugador".
Aunque contento con sus resultados que superan el precalentamiento de los shaders, Hutchison está considerando otras opciones en el futuro. «Desde el lanzamiento del juego, Unity lanzó el almacenamiento en caché y el precalentamiento de PSO a través de GraphicStateCollections, que queremos utilizar en el futuro».

Sonic Dream Team | Hardlight | SEGA
Reducción del tamaño de la memoria con Addressables
Durante el desarrollo, el juego utilizó 1,35 GB de memoria en el tiempo de ejecución. Dado que el iPhone 6s Plus solo tenía 2 GB de memoria física, esto podría haber generado problemas, incluido el riesgo de que el sistema operativo cerrara la aplicación.
"La duplicación de assets fue un gran obstáculo. El juego tenía más de 3,000 assets duplicados, lo que aumentó su tamaño y provocó que los mismos assets se cargaran varias veces durante el tiempo de ejecución", dice Macan.
En ese momento, Unity Addressable System solo administraba una pequeña fracción de los assets del juego. Esto llevó a casos en los que se hacía referencia a assets tanto en binario como a través de Addressable Groups, lo que causó duplicación.
En las primeras etapas del desarrollo, el equipo utilizó un solo Addressable Group y lo configuró para que se empaquetara por separado. Esto significaba que cada asset del grupo tenía su propio AssetBundle separado. Si bien es útil en casos específicos, este enfoque granular también generó una gran cantidad de assets duplicados. Asegurarse de que todos los assets fueran Addressable y tener un enfoque estructurado para Addressable Groups redujo el tamaño de compilación en iOS de 4 GB a 2 GB.

Sonic Dream Team | Hardlight | SEGA
Reducción de la memoria de variantes de shaders
Las variantes de shaders fueron un área de gran enfoque para el equipo durante toda la producción del juego, con una memoria de shaders en tiempo de ejecución que aumentó a más de 1 GB. La cantidad de variantes también aumentó los tiempos de compilación. Abordaron el problema utilizando varios métodos: principalmente la eliminación de shaders con IPreprocessShaders, el prefiltrado de Unity, la carga dinámica de shaders de Unity y la reducción de la ramificación de shaders.
"Usamos nuestra propia implementación personalizada de striptease de IPreprocessShaders, que eliminó globalmente las palabras clave de shaders de todos los shaders y un enfoque local a través de Shader Control de Unity Asset Store", dice Hutchison. "Ser más intencional sobre cuándo usar una palabra clave en los shaders también fue una gran victoria".
Sus shaders utilizaron Shader Graph, que inherentemente incluye palabras clave predefinidas por Unity, y agregar palabras clave adicionales a estas tuvo un efecto exponencial. Cambiar alguna lógica por ramas dinámicas o eliminar por completo las palabras clave redujo significativamente el total de variantes.
"Con todos estos métodos combinados, redujimos la memoria de las variantes del shader en tiempo de ejecución a un promedio de 100 MB o menos", dice Hutchison. "También utilizamos Project Auditor de Unity, que ofrece una vista global de todos los assets y ajustes de la compilación. Utilizando esto en combinación con Memory Profiler, identificamos texturas y mallas que se beneficiaron con la mejora de los ajustes predefinidos de importación. Esto redujo aún más las presiones de memoria de los assets de arte y audio".

Sonic Dream Team | Hardlight | SEGA
Celebrar las victorias y mirar hacia el futuro
A lo largo de más de una década, Unity y Hardlight han creado una capa de tecnología compartida con la que el estudio cuenta. "Seguimos apoyando los juegos que hicimos en Unity hace 10 años", dice Macan.
Unity ha agregado tanto a lo largo de los años, señaló, que el estudio simplificó su mantenimiento al eliminar algo de código nativo para la API de Unity. "Unity maneja gran parte de la compatibilidad con dispositivos de bajo nivel, por lo que podemos enfocarnos en crear el juego en sí. A medida que la tecnología evoluciona, confío en que Unity nos ayudará a mantenernos al día", exclama.
Sonic Dream Team demuestra que aún puedes enseñarle nuevos trucos a un viejo erizo. Y, al igual que Sonic, Hardlight y Unity tienen un historial sólido y un futuro brillante.
Descarga Unity Pro hoy mismo
Comienza a crear juegos que compiten con la calidad y el éxito de los lanzamientos de los grandes estudios, e incluso los superan, con la ayuda de poderosas herramientas, soporte, socios verificados y una vibrante comunidad.