Direccionables de Unity: siempre suficiente memoria

imagen

Lideras un equipo de varios programadores y artistas que trabajan en portar un hermoso juego de PS4 VR a Oculus Quest. Tienes seis meses para hacerlo. ¿Cuál será tu primer movimiento? Intentemos usar los direccionables de Unity.

Entiende que tiene que resolver varias tareas bastante difíciles al mismo tiempo. Algunos serán más difíciles para usted que otros, depende de su experiencia en cada una de las áreas. Si eliges cuál de ellos te priva del sueño con más frecuencia, ¿cuál será?

Supongo lo siguiente: aproximadamente el 70% de los lectores dirán que el mayor problema al portar un juego a Quest es el rendimiento de la CPU / GPU. Puedo responder esto: lo más probable es que tengas razón. Mejorar la productividad es una de las áreas más difíciles en un juego de realidad virtual. Las optimizaciones de este tipo requieren un estudio exhaustivo del producto, y esto lleva tiempo. A veces, la optimización adicional es imposible, por lo que generalmente debes deshacerte de los elementos costosos del juego y los gráficos. Y es peligroso decepcionar a los jugadores.

Velocidad, velocidad, velocidad ... ¿Qué esperar a este respecto de la plataforma Quest? ¿Cuán productivo es? El hecho es que si ya tenía experiencia en desarrollarlo, entonces sabe que a pesar de su movilidad, es sorprendentemente poderoso.

“Vamos, autor, ¿por qué mientes? Mi teléfono comienza a ralentizarse tan pronto como abro la segunda pestaña del navegador. ¿Cómo puede decir que las plataformas móviles pueden ser productivas?

La gran diferencia radica en el sistema de enfriamiento activo Quest , que brinda una gran ventaja a su CPU / GPU que no es proporcionada por ninguna otra plataforma móvil. Este es un poderoso ventilador que elimina el polvo de tu cabello y evita que el procesador se derrita en tu cara.

Además, un sistema operativo más especializado está mejor optimizado para renderizar realidad virtual (sorpresa) que Android estándar. En los últimos años, el hardware móvil ha comenzado a ponerse rápidamente al día con las plataformas fijas.

Pero al mismo tiempo, no negaré que la tarea de renderizado constante con una frecuencia de 72 fps será difícil, especialmente para los puertos de juegos de realidad virtual que provienen de plataformas potentes. Cuando hablamos de Oculus Quest, puedes imaginar el Snapdragon 835 con una pantalla, batería, cuatro cámaras y un ventilador.

Lo que parece un defecto en realidad se puede tomar como una ventaja. Esta plataforma móvil es un dispositivo bien investigado con hierro débil. Podemos decir que hay miles de trucos conocidos para reducir rápidamente la carga en la CPU y la GPU a un nivel aceptable. Si está interesado, puede leerlo en mis publicaciones posteriores. Y en este artículo pondremos el rendimiento fuera de discusión.

Nuestra atención en este problema puede ser que, en comparación con PS4, Quest tiene una característica de hardware que es la mitad: la capacidad de RAM . Es decir, el volumen disminuyó de 8 a 4 GB de RAM. Esta es una aproximación, porque en ambas plataformas el sistema operativo no permite usarlas por completo, por lo que puede realizar un seguimientoVarios subsistemas necesarios para el funcionamiento del ecosistema. En Quest, puede usar hasta aproximadamente 2.2 GB de RAM; Si más, el caos ya está comenzando.

"¿Pero qué quieres decir con caos ?" El hecho es que para el juego es fundamental implementar la gestión de memoria correcta. Sucedió porque tenemos dos limitaciones:

  • Límite de memoria dura : si supera un cierto umbral, el sistema operativo simplemente matará el juego
  • Límite de memoria suave

Obviamente, no queremos que ocurra el primero o el segundo en el juego. ¿Te imaginas la furia de un jugador que ha perdido las últimas dos horas de pase? Sí, definitivamente irá a la tienda de aplicaciones y no dirá nada agradable allí.

Por supuesto, la disponibilidad garantizada de 2,2 GB de RAM no es tanto. Por lo general, esto no es un problema para nuevos proyectos en los que las estadísticas se controlan constantemente desde el principio, pero definitivamente se convierte en una dificultad para un puerto con hardware mucho más débil.

Si ha tratado con puertos similares en el pasado, se dará cuenta rápidamente de lo extremadamente difícil que resulta reducir a la mitad la cantidad de RAM disponible . Depende en gran medida de qué tan bien esté preparada la arquitectura del juego para tal cambio, pero en la mayoría de los casos solo provoca lágrimas.

Las estrategias más populares para reducir los requisitos de memoria son cambiar los parámetros de compresión de los activos, optimizar los scripts, reducir las variaciones del sombreador, etc. Con mucha frecuencia, la primera decisión es cambiar la configuración de importación de texturas, pero si es necesario, puede usar la compresión de mallas, animaciones y sonido. El problema es que tales técnicas suelen ser complejas y tienen su propio techo .

No todas las plataformas admiten los mismos parámetros de importación: cuando se desarrollan para diferentes dispositivos, los costos de la tubería de ensamblaje aumentan significativamente, sin mencionar la complejidad del control de calidad, los gráficos de diseño y la programación. Por ejemplo, ¿esto es compatible con dispositivos Android ASTC, o solo ETC2 (y generalmente cualquiera de ellos)? Ah, y todavía necesitamos versiones de 64 bits, pero al mismo tiempo queremos mantener a los jugadores con versiones de 32 bits. ¿Cuántos APK individuales necesitamos para crear y probar para cada actualización en el juego? Si desea simplificar su vida, entonces no debe confiar solo en estas técnicas.

Por lo tanto, tenemos que ir más profundo. Por supuesto, queremos que todo sea lo más simple posible, especialmente al crear un puerto. Reciclar el juego por completo para el rendimiento es una opción aún peor que simplemente no portarlo. Como parte del tema del artículo, mostraré una de las ventajas más importantes: aprenderá a reducir la cantidad de memoria requerida a la mitad en unas pocas horas .

¿No es genial?

Bueno, vamos, pregúnteme: ¿es esto realmente posible en su caso? Contestaré: depende de las condiciones iniciales, pero en mi experiencia, la respuesta es . Unity Addressables puede hacer un gran servicio aquí. Cual es el truco Tienes que invertir y dominar el proceso. Pero ese flujo de trabajo le permitirá ganar el título de empleado del mes.

Si está interesado, continúe leyendo.

En esta publicación, pasaremos de la gestión de activos tradicional a la gestión de activos basada en direcciones . Para ilustrar este proceso, estamos trasladando un proyecto simplificado de la vieja escuela a la nueva era de Unity Addressables.

Puede hacer una pregunta: ¿por qué no muestra el resultado en su trabajo real?

En un mundo sin competencia, solo te mostraría todos los materiales que creé. Sin embargo, en el mundo real, lo más probable es que me castiguen por esto. Y luego me meterán en la cárcel.

Entonces, en cambio, ofrezco mi ayuda: elaboraremos un proyecto que presente todas las dificultades que enfrentará mañana en su próximo proyecto. Y para comenzar, tomaremos Unity Addressables en nuestra familia de paquetes recomendados .

En esta publicación, le presentaré las direcciones direccionables para que pueda implementar su propio sistema Unity Addressables en minutos .


Direccionables de unidad: ¿por qué son necesarios?


Se debe prestar atención a esta importante sección. Nuestra tarea es reconocer formas simples de optimizar el uso de la memoria e implementarlas rápidamente. Hay varias formas de hacer esto, pero una de las más poderosas y al mismo tiempo más simple es cargar la primera escena y ejecutar el generador de perfiles. ¿Por qué?

Debido a que la arquitectura no optimizada del juego se puede reconocer en cualquier momento del juego , la forma más rápida de verificar esto es perfilando la primera escena. La razón de esto es que el uso a menudo excesivamente activo de scripts como singleton-s contiene enlaces a todos los activos, por si acaso .

En otras palabras, muchos juegos suelen tener un guión omnipotente que crea muchos enlaces a los activos .Este componente mantiene cada activo cargado constantemente, independientemente de si se está utilizando actualmente.

¿Qué tan malo es eso?

Las situaciones son diferentes. Si su juego es probable que esté limitado por la memoria? entonces esta es una decisión muy arriesgada, porque el juego no escalará bien con el aumento en la cantidad de activos agregados (por ejemplo, piense en futuros DLC). Si está desarrollando dispositivos heterogéneos, por ejemplo, para Android, entonces no tiene una sola cantidad de memoria; Cada dispositivo tiene su propia capacidad, por lo que debe confiar en el peor de los casos. El sistema operativo puede decidir eliminar la aplicación en cualquier momento si el usuario cambia repentinamente para responder un mensaje en Facebook. Cuando regrese, una sorpresa lo estará esperando: el juego ya ha sido cerrado.

¿Es divertido?

Absolutamente no.

Lo que complica la situación es el hecho de que si luego decides (o alguien decide por ti) trasladar el juego a otra plataforma menos poderosa mientras mantienes el juego cruzado, solo puedes desear buena suerte. Definitivamente no querrás enfrentar un problema tan técnico.

Por otro lado, ¿hay situaciones en las que la gestión de activos tradicional sea adecuada? Sí, por supuesto. Si está desarrollando una plataforma uniforme, como PS4, y la mayoría de los requisitos se conocen desde el principio, los beneficios de los objetos globales podrían superar la complejidad añadida de un sistema de administración de memoria mejorado.

Porque tienes que admitirlo: el viejo objeto global que almacena todo lo que necesitamos es una solución simple si te conviene. Simplificará el código y precargará todos los activos referenciados.

Sea como fuere, la gestión de memoria tradicional es inaceptable para los desarrolladores que buscan maximizar el uso de los recursos de hierro . Estás leyendo un artículo, lo que significa que quieres mejorar tus habilidades. Así que ha llegado el momento de hacerlo.

Conoce a los destinatarios de Unity.

Requisitos del proyecto con unidades direccionables


Si planea leer esta publicación, la pantalla será suficiente. Si quieres hacer todo conmigo. entonces necesitará lo siguiente:

  • Manos
  • Mente inteligente
  • Unidad 2019.2.0f1 o superior
  • Proyecto de nivel 1 con GitHub (descarga zip o por línea de comando)
  • El deseo de profundizar en el interior de las unidades direccionables

El repositorio de git contiene tres confirmaciones, una para cada nivel de esta publicación (a menos que mezcle algo y cree una confirmación con una corrección).

Descargue el proyecto en formato ZIP directamente desde GitHub


Desarrollador de Nivel 1: Gestión de Activos Tradicional


Comenzaremos con el método de gestión de activos más simple. En nuestro caso, para esto tenemos que hacer una lista de enlaces directos a los materiales de skybox en el componente.

Si haces esto conmigo, la preparación tomará tres pasos simples:

  1. Descargar el proyecto desde git
  2. Abrir un proyecto en Unity
  3. ¡Haz clic en el botón de reproducción!

Multa. Ahora puede hacer clic en los botones para cambiar el skybox. Tan original ... y aburrido. Según tengo entendido, hasta ahora no hay unidades direccionables.

Pronto verás por qué soportamos estos momentos de aburrimiento.

En primer lugar, ¿cómo está estructurado nuestro proyecto? Se basa en dos sistemas principales. Por un lado, tenemos un objeto Game Manager . Este componente es el script principal que almacena enlaces a materiales de skybox y los cambia según los eventos de la interfaz de usuario. Es muy simple

using UnityEngine;

public class Manager : MonoBehaviour
{
    [SerializeField] private Material[] _skyboxMaterials;

    public void SetSkybox(int skyboxIndex)
    {
        RenderSettings.skybox = _skyboxMaterials[skyboxIndex];
    }
}

Manager proporciona al sistema de IU una función para aplicar material específico a la escena mediante el uso de la API RenderSettings .

En segundo lugar, tenemos un CanvasSkyboxSelector . Este objeto del juego contiene un componente de lienzo que representa un conjunto de botones distribuidos verticalmente. Cada botón, cuando se presiona, llama a la función Manager mencionada anteriormente , que reemplaza el skybox renderizado dependiendo de la identificación del botón. En otras palabras, el evento OnClick de cada botón llama a la función SetSkybox del objeto Administrador . Es simple, ¿no es así?


Direccionables de Unity: jerarquía de escenas

Ahora es el momento de comenzar. Abramos el generador de perfiles ( ctrl / cmd + 7 o Window - Analysis - Profiler ). Asumiré que está familiarizado con esta herramienta, lo que significa que sabe qué hacer con el botón de grabación superior . Después de unos segundos de grabación, deténgalo y observe las métricas: CPU, memoria, etc. ¿Hay algo interesante?

El rendimiento es bastante bueno, y esto no es sorprendente dada la escala del proyecto. Simplemente puede convertir este proyecto en un juego de realidad virtual y le garantizo que ninguno de los jugadores se sentirá enfermo, como suele ser el caso en Eve: Valkyrie .

En nuestro caso, nos centraremos en la sección de memoria. En el modo de visualización simple, verá algo como esto:


Gestión de activos de nivel 1: perfiles de memoria simples Los

valores de tamaño de textura parecen demasiado grandes para mostrar un cuadro de cielo a la vez, ¿no? Le espera una sorpresa: se puede encontrar un patrón similar en muchos juegos no optimizados, cuyo desarrollo liderará . Pero en nuestro caso es solo un conjunto de skyboxes. En otros proyectos, estos serán personajes, planetas, sonidos, música ...

Si la responsabilidad de trabajar con muchos activos recae en usted, entonces me alegra que esté leyendo este artículo. Te ayudaré a hacer la transición a una solución que se adapte bien.

Ha llegado el momento de la magia. Cambie el generador de perfiles de memoria al modo detallado. ¡Míralo!


Gestión de activos de nivel 1: perfiles detallados de memoria

Maldición, ¿qué pasó aquí? Todas las texturas de skybox se cargan en la memoria, pero solo se muestra una de ellas a la vez. ¿Ves lo que tenemos? Esta arquitectura en bruto ocupa hasta 400 MB .

Esto definitivamente no nos conviene, dado que esto es solo una pequeña parte del juego futuro. La solución a este problema en sí se convertirá en la base de la siguiente sección.

Resumir:

  • La gestión tradicional de activos implica enlaces directos
  • Por lo tanto, todos los objetos se cargan constantemente
  • El proyecto no escala bien


Desarrollador de nivel 2: Proceso de unidades direccionables


En los juegos, comenzamos desde el nivel 1, y eso nos conviene, pero tan pronto como descubramos las reglas del juego, es hora de abandonar los muros seguros de la ciudad y elevar nuestro nivel. De esto se trata esta sección.

Ahora descargue el proyecto de nivel 2 .

Como vimos anteriormente en el generador de perfiles, todos los skyboxes se cargan en la memoria, aunque solo uno se usa activamente . Esta solución no escala, porque en algún momento estaremos limitados por el número de variaciones de activos diferentes que podemos ofrecer al jugador. ¿Qué consejo puedo dar? No limite el interés del juego a los usuarios.

Deja que te ayude. Tome una pala para cavar un túnel de jailbreak de gestión de activos tradicionales. Agreguemos una nueva herramienta interesante a nuestra colección: la API de Unity Addressables .

Lo primero que debemos hacer es instalar el paquete Direccionables. Para hacer esto, vaya a Ventana → Administrador de paquetes :


Unity Package Manager - Unity Addressables

Después de la instalación, debemos marcar los materiales como direccionables. Selecciónelos y active la bandera direccionable en la ventana del inspector.


Gestión de activos de nivel 2 (unidades direccionables de Unity)

Por lo tanto, solicitamos cortésmente a Unity que incluya estos materiales y sus dependencias de textura en la base de datos de direcciones. Esta base de datos se usará durante las compilaciones para empaquetar activos en fragmentos, que se pueden cargar fácilmente en cualquier momento del juego.

Ahora te mostraré algo genial. Ventana abierta -> Gestión de activos -> Direccionables . ¿Adivina qué es esto? ¡Esta es nuestra base de datos que está ansiosa por cobrar vida!


Gestionar activos de nivel 2 Unity Addressables es la ventana principal

Estimado lector, esta fue la parte fácil. Y ahora comienza la diversión.

Quiero que visite a nuestro viejo amigo de la sección anterior: Sir Manager . Si lo comprobamos, descubriremos que todavía almacena enlaces directos a activos. No necesitamos esto.

En cambio, le enseñaremos al administrador cómo usar enlaces indirectos, es decir AssetReference (en Unreal Engine se denominan referencias suaves).

Hagamos que nuestro componente sea más hermoso:

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Manager : MonoBehaviour
{
    [SerializeField] private List<AssetReference> _skyboxMaterials;

    private AsyncOperationHandle  _currentSkyboxMaterialOperationHandle;

    public void SetSkybox(int skyboxIndex)
    {
        StartCoroutine(SetSkyboxInternal(skyboxIndex));
    }

    private IEnumerator SetSkyboxInternal(int skyboxIndex)
    {
        if (_currentSkyboxMaterialOperationHandle.IsValid())
        {
            Addressables.Release(_currentSkyboxMaterialOperationHandle);
        }

        var skyboxMaterialReference = _skyboxMaterials[skyboxIndex];
        _currentSkyboxMaterialOperationHandle = skyboxMaterialReference.LoadAssetAsync();
        yield return _currentSkyboxMaterialOperationHandle;
        RenderSettings.skybox = _currentSkyboxMaterialOperationHandle.Result;
    }
}

Aquí sucede lo siguiente:

  • 7, (AssetReference) . , . . .
  • 13: , . ,
  • 18-20 , , , , . , API Addressables, , . — , , addressable-.
  • addressable 23, LoadAssetAsync, yield ( 25), . . !
  • , , , 26. Result, , .


Nivel 2 Gestión de activos (unidades direccionables) - Lista de referencias de activos

Recuerde: este código no está listo para la producción. No lo use cuando programe un avión. Decidí que, en aras de la simplicidad, sacrificar la fiabilidad.

Pero suficiente explicación. Es hora de verlo en acción.

Por favor siga estos pasos:

  1. En la ventana direccionables, prepare el contenido ( compilar contenido del reproductor )
  2. Luego compila para la plataforma seleccionada
  3. Ejecútelo y conecte el generador de perfiles (memoria).
  4. No dejes caer la mandíbula con sorpresa.


Nivel 2 (Direccionables de Unity): crea contenido de jugador


Nivel 2 Gestión de memoria (Unity Addressables) - Memory Profiler

¿No son sabrosos los activos cocinados?

Me gusta cuando el perfilador está satisfecho. Y ahora vemos el perfilador más feliz del mundo. Un perfilador satisfecho significa lo siguiente: en primer lugar, hay jugadores más satisfechos que pueden jugar tu juego incluso en Nokia 3210 . En segundo lugar, estos son productores satisfechos. Y para usted, esto significa que su billetera estará satisfecha.

Este es el poder del sistema Direccionables.

Pero los destinatarios imponen pequeños costos laborales adicionales. Por un lado, los programadores deben proporcionar soporte para flujos de trabajo asíncronos (esto se implementa fácilmente usando la rutina). Además, los diseñadores deberán estudiar las capacidades del sistema, por ejemplo, grupos direccionables, y adquirir experiencia para tomar decisiones informadas. Y finalmente, el departamento de TI estará muy contento de que tendrá que configurar la infraestructura para transferir activos a través de la red si prefiere alojarlos en línea.

Debo felicitarte. Explicaré lo que hemos logrado:

  • Gestión adecuada de la memoria.
  • Arranque más rápido.
  • Tiempo de instalación más rápido, tamaño de aplicación reducido en la tienda.
  • Mayor compatibilidad del dispositivo.
  • Arquitectura asincrónica.
  • Abrieron la puerta para almacenar este contenido en línea → es decir, a la separación de datos del código.

Estaría orgulloso de tales logros. Este es un buen retorno de nuestra inversión laboral.

Ah, y no olvide mencionar la experiencia con los destinatarios en una entrevista.

Materiales de apoyo: creación de instancias y conteo de enlaces. La información sobre este tema se puede encontrar en mi publicación .

Opcional: estrategias de descarga alternativas. Puedes leer sobre ellos en mi publicación .

Resumir:

  • La gestión de activos basada en direcciones se escala notablemente bien.
  • Los direccionables agregan un comportamiento asincrónico
  • ¡No olvides preparar el contenido para los cambios, de lo contrario el juego tendrá un tono rosado!


Gestión de activos de nivel 3 (??) - Entrega de contenido de red

Gestión de activos de nivel 3 (??) - Entrega de contenido de red


En la sección anterior, hicimos el avance más importante. Mejora tus habilidades al pasar de un sistema de gestión de activos tradicional a un flujo de trabajo basado en direcciones. Esta es una gran victoria para el proyecto, porque gracias a la pequeña inversión de tiempo, hemos proporcionado espacio para escalar el volumen de activos, manteniendo un bajo nivel de consumo de memoria. Este logro realmente te actualizó al nivel 2, ¡felicidades! Sin embargo, todavía tenemos que responder otra pregunta:

¿es todo esto?

No se . Apenas tocamos el tema Direccionables, hay otras formas de mejorar el proyecto gracias a este poderoso paquete.

Por supuesto, no es necesario que recuerde todos los detalles del uso de direccionables, pero le recomiendo que los lea brevemente, porque en el futuro lo más probable es que se encuentre con nuevas pruebas, y estará agradecido por un estudio más profundo. Por eso preparé otra guía breve.

De él aprenderá sobre los siguientes aspectos:

  • Ventana Direccionables : detalles importantes
  • Perfiles direccionables : no permita que las pérdidas de memoria arruinen su vida
  • Entrega en red : tiempo reducido desde la instalación hasta el juego
  • Integración de tubería de ensamblaje
  • Estrategias prácticas : acelerar el flujo de trabajo, eliminar la necesidad de pausas para tomar café de diez minutos

Y, lo que es más importante, responderemos las siguientes preguntas:

  • ¿Cuál es el significado oculto de Enviar eventos de Profiler ?
  • ¿Qué tan útil es la API AddressableAssetSettings ?
  • ¿Cómo integrar todo esto con la API BuildPlayerWindow ?
  • ¿Cuál es la diferencia entre el modo virtual y el modo empaquetado ?

La orientación de nivel 3 se puede encontrar en mi publicación .

All Articles