Optimización móvil en Unreal Engine: cómo hacer que MetaHumans y PCG funcionen a 60 FPS
En resumen
Esta guía técnica detalla cómo optimizar características avanzadas de Unreal Engine como MetaHumans, PCG y materiales de Substrate para que funcionen a 60 FPS en plataformas móviles. Se explican flujos de trabajo clave como la restricción del bone skinning en DefaultEngine.ini, el uso de hair cards en lugar de strands para el cabello y el pre-bake de grafos procedimentales. Por último, aborda la importancia de la optimización de red en entornos móviles y cómo delegar la infraestructura del backend en plataformas dedicadas.
La barrera móvil: llevando gráficos Next-Gen a dispositivos móviles
Tu excelente proyecto de PC funciona a unos impecables 120 FPS en tu estación de trabajo de desarrollo, pero en el momento en que pruebas la compilación para móvil, la tasa de frames cae a un solo dígito, el teléfono de prueba se calienta y la GPU sufre un crash debido a un skinning buffer overflow. Las características de gama alta como MetaHumans, Procedural Content Generation (PCG) y materiales de Substrate se ven espectaculares en PC y consolas, pero son famosas por poner de rodillas a los dispositivos móviles. Las GPUs y CPUs móviles operan bajo limitaciones térmicas y de energía muy estrictas (thermal and power envelopes), donde el memory bandwidth es un recurso crítico. Adaptar estas funciones de última generación para el despliegue en móviles no es solo cuestión de marcar una casilla de configuración; requiere una comprensión profunda y sistemática de los límites de bone skinning, las estructuras de groom, los flujos de trabajo de procedural baking y las complejidades del material shading.
El desafío del GPU Skinning y el límite de huesos
El cuello de botella del GPU Skinning en móviles
Las skeletal meshes con skinning se dividen en chunks de vértices y huesos antes de enviarse a la GPU. Cada chunk se procesa en una sola draw call, y las GPUs móviles tienen un límite estricto de hardware en la cantidad de matrices de huesos que pueden procesar con skinning simultáneamente. Esta limitación viene definida por el número de uniform vectors disponibles para el vertex shader. El skeleton por defecto de un personaje de MetaHuman contiene más de 600 huesos, lo que supera fácilmente los límites de los móviles y provoca errores de renderizado, vertex tearing o bloqueos completos de la GPU.
Para evitar esta limitación de hardware, debes forzar al engine a particionar los chunks de la skeletal mesh de manera que ninguna draw call haga referencia a más de un número específico de huesos. Esto se logra ajustando la configuración de compatibilidad del skinning. Si no aplicas esta configuración, el skinning de tus modelos de personajes no funcionará correctamente en dispositivos Android y iOS, mostrando meshes estáticas o fuertemente distorsionadas.
Configuración de DefaultEngine.ini
Para resolver los límites del bone skinning, debes modificar el archivo de configuración DefaultEngine.ini de tu proyecto. Busca este archivo en la carpeta Config de la raíz del proyecto. Bajo la sección [ConsoleVariables], añade la siguiente línea:
[ConsoleVariables]
Compat.MAX_GPUSKIN_BONES=75
Esta variable de consola le indica al compilador de shaders que limite el número máximo de huesos por chunk de skinning a 75. Se trata de un límite de hardware estricto para GPUs móviles de gama media o baja. Ten en cuenta que establecer este valor más bajo obliga al compilador de skeletal meshes a dividir la mesh en un número mayor de chunks. Aunque esto resuelve la compatibilidad del renderizado, un mayor número de chunks significa más draw calls, lo que puede trasladar el cuello de botella de rendimiento a tu hilo de renderizado de la CPU (CPU render thread).
Reducción del número de huesos y Component Stripping
Para personajes de fondo o personajes no jugadores (NPCs) que no requieran una articulación facial completa, deberías simplificar el skeleton. Por ejemplo, eliminar los dedos de las manos, de los pies y los huesos de expresión facial puede reducir el número total de huesos de un personaje de más de 600 a menos de 75. Esto permite que la mesh del personaje se renderice como un solo chunk sin inflar la cantidad de draw calls.
Si también estás desplegando Dedicated Servers para tu juego multiplayer, las optimizaciones en el lado del cliente son solo la mitad de la historia. También necesitarás optimizar el rendimiento en el lado del servidor eliminando por completo los assets de renderizado. Echa un vistazo a nuestra guía paso a paso sobre cómo dominar el asset stripping en Dedicated Servers de Unreal Engine para reducir la sobrecarga de memoria del servidor y optimizar el rendimiento de la CPU.
Optimización del pelo de MetaHuman: Groom Strands vs. Hair Cards
El coste de renderizado de Strand
La tecnología de renderizado groom strand de Epic dibuja curvas de pelo individuales de forma dinámica. Aunque esto produce un cabello sumamente detallado en GPUs de escritorio de gama alta, es increíblemente costoso. El renderizado por strands depende de pases de compute shader para el depth sorting y la generación de shadow maps, lo que consume una cantidad sustancial de pixel fill rate y memory bandwidth.
En dispositivos móviles, el renderizado de strands no está soportado en absoluto o bien se ejecuta a un coste inaceptable, consumiendo a menudo más de 15 ms de tiempo de GPU solo para el pelo de un único personaje. Las GPUs móviles carecen del memory bandwidth bruto necesario para ordenar y sombrear cientos de miles de curvas de pelo individuales por frame.
Implementación de Hair Cards
La solución consiste en sustituir los grooms basados en strands por hair cards. Las hair cards representan el cabello mediante meshes de polígonos planos y simplificados con texturas de pelo pre-renderizadas. Este enfoque es altamente compatible con el mobile forward render path.
Para implementar hair cards, abre el MetaHuman Creator y asegúrate de generar los LODs de groom basados en cards para tu personaje. Reemplazar el cabello basado en strands por grooms basados en cards reduce el tiempo de renderizado del pelo de un solo personaje de aproximadamente 18.2 ms a 0.9 ms en un chip móvil moderno como el Apple A15 o Snapdragon 8 Gen 1. Este enorme ahorro te permite destinar tu presupuesto de renderizado a elementos de gameplay o detalles del entorno.
Deshabilitar Post-Process Anim Blueprints
Los MetaHumans utilizan post-process animation blueprints para gestionar el movimiento secundario de los huesos, formas musculares correctivas y la dinámica de las articulaciones. Aunque esto añade un movimiento de piel realista en PC, ejecuta complejos cálculos esqueléticos en la CPU en cada frame. En móviles, esta sobrecarga de CPU puede convertirse fácilmente en un cuello de botella para el game thread.
Puedes deshabilitar el post-process animation blueprint en dispositivos móviles para recuperar ciclos de CPU. Esto se hace estableciendo bDisablePostProcessAnims = true en los componentes de skeletal mesh. Deshabilitar estos post-procesos ahorra hasta 4.5 ms de tiempo de frame de CPU en hardware móvil estándar.
Optimización de PCG para entornos móviles
La sobrecarga de la ejecución de PCG en runtime
El framework de Procedural Content Generation (PCG) te permite poblar tus entornos de forma dinámica distribuyendo static meshes, follaje y actores basándose en reglas y volúmenes. Sin embargo, la ejecución de grafos de PCG en runtime en CPUs móviles provoca severas caídas de rendimiento (hitches). Una generación típica de grafos en runtime puede congelar el game thread durante 1.5 a 3 segundos durante la carga de niveles o el spawn de jugadores.
En un juego multiplayer, esta interrupción es peligrosa; puede provocar packet loss y desencadenar una desincronización del estado cliente-servidor. Para mantener un alto rendimiento, debes pre-bake tus grafos de PCG en el editor. Esto convierte las instancias procedimentales en geometría estática antes de compilar (packaging) tu juego.
Flujo de trabajo paso a paso para el PCG Baking
- Selecciona el volumen de PCG: En el viewport de Unreal Editor, selecciona el volumen de PCG que contiene los elementos de tu entorno.
- Generar e inspeccionar: En el panel de detalles del volumen, haz clic en Generate para previsualizar la colocación procedimental de tus assets.
- Exportar a Actor: Localiza la opción Export to Actor dentro del menú de utilidades de PCG.
- Elegir Instanced Meshes: Selecciona Hierarchical Instanced Static Mesh (HISM) como formato de destino. Este grupo de instancias está altamente optimizado para GPUs móviles, ya que dibuja todas las meshes idénticas en una sola draw call de GPU.
- Limpiar el grafo: Después de exportar, establece el disparador de generación del volumen de PCG en Editor Only o limpia el volumen. Esto evita que el engine intente recrear el grafo en runtime.
Culling dinámico y streaming de HISM
Una vez que hayas exportado tus instancias de PCG a HISMs, debes configurar sus distancias de culling. Los HISMs soportan culling por instancia, lo que significa que las instancias que estén más allá de cierta distancia de la cámara no se dibujarán. Define la Start Cull Distance y la End Cull Distance en el panel de detalles de tus componentes HISM. Para móviles, se recomienda una distancia de culling de 5000 a 8000 unidades para mantener la cantidad total de polígonos visibles dentro del presupuesto de la GPU móvil.
Script de optimización en C++ para producción
Para automatizar estas optimizaciones en runtime, puedes escribir una clase auxiliar personalizada. El siguiente código en C++ demuestra cómo comprobar la plataforma de destino, forzar programáticamente LODs bajos, deshabilitar los post-process animation blueprints y forzar los componentes de groom a usar el renderizado basado en cards al hacer spawn de un MetaHuman en un dispositivo móvil. Puedes implementar esto en una clase como UMetaHumanMobileOptimizer:
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Components/SkeletalMeshComponent.h"
#include "GroomComponent.h"
#include "MetaHumanMobileOptimizer.generated.h"
UCLASS()
class MYPROJECT_API UMetaHumanMobileOptimizer : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Optimization")
static void OptimizeMetaHumanForMobile(AActor* MetaHumanActor)
{
if (!MetaHumanActor)
{
return;
}
// Apply optimizations exclusively on Android and iOS platforms
#if PLATFORM_ANDROID || PLATFORM_IOS
TArray<USkeletalMeshComponent*> SkeletalComponents;
MetaHumanActor->GetComponents<USkeletalMeshComponent>(SkeletalComponents);
for (USkeletalMeshComponent* MeshComp : SkeletalComponents)
{
if (MeshComp)
{
// Force a low LOD (LOD 3 or 4) to bypass dense meshes
MeshComp->SetMinLOD(3);
MeshComp->SetForcedLOD(3);
// Disable expensive post-process animation blueprints
MeshComp->bDisablePostProcessAnims = true;
// Adjust animation tick rate to only calculate when visible
MeshComp->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
// Strip physics asset to avoid CPU collision overhead on cosmetic joints
MeshComp->SetPhysicsAsset(nullptr);
}
}
TArray<UGroomComponent*> GroomComponents;
MetaHumanActor->GetComponents<UGroomComponent>(GroomComponents);
for (UGroomComponent* GroomComp : GroomComponents)
{
if (GroomComp)
{
// Force the groom to use card rendering instead of strands
GroomComp->SetUseCards(true);
}
}
#endif
}
};
Esta función auxiliar se puede llamar desde el evento BeginPlay de tu personaje o inmediatamente después de hacer spawn de un actor MetaHuman. Al utilizar macros de compilación condicional (PLATFORM_ANDROID || PLATFORM_IOS), el compilador elimina estas anulaciones en las compilaciones de PC y consolas, lo que te permite mantener la fidelidad visual multiplataforma de forma automática.
Adaptación de materiales de Substrate para GPUs móviles
¿Qué es Substrate?
Substrate reemplaza el tradicional shading model de Unreal Engine por un framework de materiales modular y multicapa. Substrate permite a los desarrolladores apilar múltiples shading slabs (por ejemplo, colocar una capa de clear coat brillante directamente sobre una capa de metal rugoso). Aunque Substrate es excelente para assets cinematográficos de alta gama, presenta un grave obstáculo de rendimiento para los renderizadores móviles.
Las GPUs móviles dependen en gran medida de arquitecturas de tiled rendering, donde el bus de memoria entre el núcleo de la GPU y el frame buffer integrado en el chip es un importante cuello de botella. Los materiales complejos de Substrate incrementan la cantidad de bytes por píxel (BPP) que se escriben en el frame buffer, lo que provoca thermal throttling y caídas en la tasa de frames.
Gestión de la complejidad del material mediante Quality Level Switches
Para que los materiales de Substrate sigan siendo eficientes en móviles, debes utilizar los nodos Material Quality Level Switch y Feature Level Switch dentro del Material Editor. Estos nodos te permiten simplificar el material graph en función de la plataforma de destino.
Para plataformas móviles, simplifica el grafo omitiendo las mezclas multicapa de Substrate. En su lugar, utiliza un único slab que emule el estilo visual de tu asset. Al dirigir los nodos de tu material a través de un switch de calidad, puedes reducir el ancho de banda de escritura de 32 bytes por píxel a un estándar de 8 bytes por píxel, lo que se traduce en un dispositivo que se calienta menos y tasas de frames estables.
5 mejores prácticas aplicables para la optimización móvil
- Pre-bake todos los grafos de PCG en HISMs: No ejecutes grafos de PCG en el cliente en runtime. Realiza un pre-bake de los grafos en Hierarchical Instanced Static Meshes (HISMs) durante el desarrollo en el editor y configura las distancias de inicio/fin de culling adecuadas.
- Restringe el número de huesos de forma global: Añade
Compat.MAX_GPUSKIN_BONES=75al archivo DefaultEngine.ini de tu proyecto para asegurar que las skeletal meshes se rendericen correctamente en GPUs móviles sin provocar desbordamientos de búfer (buffer overflows). - Usa exclusivamente grooms basados en cards: Desactiva los grooms basados en strands para perfiles móviles. El renderizado de pelo basado en cards reduce los tiempos de frame de la GPU de 18 ms a menos de 1 ms por personaje.
- Aprovecha los Material Quality Switches: Implementa el nodo Material Quality Level Switch en tus materiales de Substrate para simplificar las capas complejas de sombreado en un único slab en plataformas móviles, reduciendo así el ancho de banda de la GPU.
- Deshabilita los post-process animation blueprints: Establece
bDisablePostProcessAnims = trueen los componentes de skeletal mesh de tu personaje en móviles para recuperar valiosos ciclos de CPU en el game thread.
La ecuación del Multiplayer y el Backend
Más allá del renderizado: optimización de red móvil
Al desarrollar juegos multiplayer multiplataforma, las optimizaciones del lado del cliente son solo una parte de la ecuación. Los dispositivos móviles experimentan con frecuencia fluctuaciones de red, alternando entre datos móviles (5G/4G) y Wi-Fi. Estas fluctuaciones introducen packet loss, jitter y picos altos de latencia.
Si tu código de sincronización de red no es robusto, estos picos de latencia pueden desencadenar el bug de sincronización multiplayer de Unreal Engine, donde la replicación de actores se desincroniza y rompe el estado del mundo. Gestionar estados multiplayer bajo las limitaciones de las redes móviles es un problema complejo que requiere controladores de red resilientes, delta compression y server-authoritative reconciliation.
Delegando la infraestructura con horizOn
Construir y mantener un backend multiplayer resiliente por tu cuenta representa un esfuerzo de ingeniería enorme. Tendrías que aprovisionar load balancers, gestionar la replicación global de bases de datos, implementar lógica de matchmaking y gestionar la facturación móvil. Este trabajo de infraestructura puede requerir meses de desarrollo y un mantenimiento continuo.
Con horizOn, estos servicios de backend vienen ya preconfigurados. horizOn ofrece a los desarrolladores de videojuegos matchmaking de sesiones, sincronización de estado de baja latencia, persistencia de base de datos y autenticación multiplataforma listos para usar (out of the box). Esto te permite concentrarte en optimizar tus clientes y pulir tu bucle de juego (game loop), en lugar de administrar clusters de servidores y la escalabilidad de bases de datos.
Conclusión y próximos pasos
Optimizar características de última generación como MetaHumans y PCG para dispositivos móviles exige un control riguroso de los presupuestos de renderizado, la compilación de skeletal meshes y la complejidad de sombreado de los materiales. Mediante el pre-bake de tus assets procedimentales, la restricción de los límites de huesos y el uso de renderizado de cabello basado en cards, puedes ofrecer experiencias multiplataforma de alta fidelidad en dispositivos móviles.
¿Listo para escalar tu backend multiplayer? Prueba horizOn de forma gratuita o consulta la documentación de la API para ver cómo puedes simplificar tu infraestructura y mantener a tus jugadores sincronizados en PC, consolas y móviles.
Fuente: Tutorial: Optimizing Next Gen Features for Mobile Game Development