En esta publicación, miramos usar Packed Level Actors para Unreal Engine para mejorar el rendimiento al renderizar múltiples instancias de una malla.
Es crucial ser eficiente con los recursos limitados disponibles al desarrollar para visores VR/MR, que tienen hardware bastante limitado. Por ejemplo, Meta menciona rangos de ejemplo de 200 - 1000 draw-calls y 1.3m - 1.8m triángulos para un Quest 3/3s, dependiendo del uso de CPU de la aplicación.
Stack Tecnológico
Para esta exploración, estamos usando el siguiente stack tecnológico:
Packed Level Actors
Un Packed Level Actor agrega mallas/actores seleccionados en un solo Nivel / Blueprint usando Instanced Static Mesh Components, ver documentación de Unreal Engine para detalles sobre cómo crear un Packed Level Actor.
El propósito principal es optimizar el rendimiento (usando Instanced Static Mesh Components, que usa un solo draw-call incluso al renderizar múltiples instancias de la misma malla por material), y potencialmente hacer más conveniente colocar ciertas composiciones de malla en un nivel múltiples veces.
Múltiples instancias de Packed Level Actor en un solo nivel
Después de algunas pruebas, parece que Unreal Engine no agrega automáticamente múltiples instancias de un Packed Level Actor cuando se colocan en un nivel, lo que mejoraría el rendimiento al reducir los draw-calls necesarios.
Usamos el siguiente escenario de prueba:
- Tener un Packed Level Actor con un solo Instanced Static Mesh Component con 1 instancia para un segmento de edificio de aproximadamente 1.8k triángulos con 4 LODs
- Colocar este Packed Level Actor 550 veces en un nivel
- Observar el número de draw-calls y triángulos renderizados en el nivel usando la herramienta de depuración
stat unit(valoresDrawsyPrims)
El resultado se puede ver en la siguiente imagen.

El resultado es bastante malo, dado que cada instancia de Packed Level Actor resulta en 1 draw-call. Al menos los LODs apropiados se usan para cada instancia, reduciendo el número de triángulos renderizados significativamente por debajo del máximo de 990k.
Fusionando múltiples instancias de Packed Level Actor en un solo nivel
En un intento de mejorar esta situación, creamos un Actor Blueprint que fusiona instancias idénticas de Packed Level Actor en tiempo de ejecución, comparando la malla y materiales usados.
El Blueprint básicamente hace lo siguiente:
- Iterar sobre todos los Packed Level Actors en el nivel
- Iterar sobre cada Instanced Static Mesh Component en el Packed Level Actor (
source-component)- Si ya tenemos otro Instanced Static Mesh Component para la misma malla / materiales, agregar todas las instancias del
source-componenta este componente - Si aún no tenemos otro Instanced Static Mesh Component para la misma malla / materiales, usar el
source-componentpara esto la próxima vez
- Si ya tenemos otro Instanced Static Mesh Component para la misma malla / materiales, agregar todas las instancias del
- Iterar sobre cada Instanced Static Mesh Component en el Packed Level Actor (
El resultado se puede ver en la siguiente imagen.

El número de draw-calls se redujo significativamente (como se esperaba), pero el número de triángulos ha aumentado significativamente, lo cual es bastante malo. La razón es que el Instanced Static Mesh Component usado selecciona el LOD para la instancia más cercana, y usa eso para renderizar todas las instancias, sin importar qué tan lejos puedan estar.
El principal inconveniente de esta solución es que no funciona con iluminación horneada, ya que el resultado se verá terrible. Para niveles generados dinámicamente con iluminación dinámica funciona muy bien sin embargo.
Cuando se usa iluminación horneada, puedes en su lugar crear manualmente un Packed Level Actor que contiene todos los otros Packed Level Actors en el nivel. Unreal Engine soporta Packed Level Actors anidados, y agrega correctamente todo en (Hierarchical) Instanced Static Meshes.
Usando Hierarchical Instanced Static Mesh Components
En un intento de mejorar esta situación, hemos reemplazado el Instanced Static Mesh Component en el Blueprint del Packed Level Actor con un Hierarchical Instanced Static Mesh Component con los mismos atributos. Esto agrega un ligero overhead, pero elegirá el LOD apropiado para cada instancia, lo que puede reducir significativamente el número de triángulos renderizados, a costa de algunos draw-calls extra.
El resultado se puede ver en la siguiente imagen.

Este resultado es bastante bueno, considerando cuántas mallas se renderizan.
Conclusión
Durante el desarrollo es importante monitorear el rendimiento, especialmente para VR/MR dado el hardware limitado disponible. Al crear un Actor Blueprint para fusionar Packed Level Actors idénticos, y usar Hierarchical Instanced Static Mesh Components, podemos usar significativamente más y más mallas detalladas en un nivel, mientras mantenemos el rendimiento en niveles aceptables.
En este escenario de ejemplo, redujimos el número de draw-calls de 559 a 14, mientras aún consideramos LODs para mantener el número de triángulos alrededor de 130k, al crear un Actor Blueprint para fusionar instancias de Packed Level Actor en tiempo de ejecución, y usar Hierarchical Instanced Static Mesh Components.
| Escenario | Draw calls | Triángulos |
|---|---|---|
| 550 Packed Level Actors individuales | 559 | 130k |
| 550 Packed Level Actors fusionados usando ISM | 10 | 995k |
| 550 Packed Level Actors fusionados usando HISM | 14 | 127k |
Nosotros en Immerstory estamos emocionados de apoyar a nuestros clientes con sus experiencias inmersivas, y esperamos compartir más progreso de exploración pronto.
¿Qué experiencia inmersiva te gustaría ver? ¡Déjanos saber!

