Optimizando el Rendimiento Gráfico
Modelar Personajes para un Rendimiento Optimo

Agrupamiento de Draw Calls

Para dibujar un objeto en la pantalla, el motor tiene que emitir un draw call (llamado de dibujo) al API de gráficas (e.g. OpenGL o Direct3D). Los Draw Calls a menudo son costosos, con el API de gráficas haciendo un trabajo significante para cada draw call, causando una sobrecarga en el rendimiento por el lado del CPU. Esto en su mayoría es causado por los cambios de estado hechos entre los draw calls (e.g. cambiando a un material diferente), que causa pasos de validación costosos y de translación en el driver gráfico.

Unity utiliza varias técnicas para abordar esto:

  • Dynamic Batching: para una cantidad pequeña de meshes, transforma sus vertices en el CPU, agrupa aquellos bastantes similares, y los dibuja en una sola pasada.
  • Static Batching: combina objetos estáticos (i.e. sin movimiento) a meshes grandes, y los renderiza de una manera rápida.

El procesamiento por batching (lotes) integrado ofrece varios beneficios en comparación con la fusión manual de GameObjects; lo más notable, los GameObjects todavía se pueden seleccionar de forma individual. Sin embargo, también tiene algunas desventajas; el procesamiento por lotes estático genera una sobrecarga de memoria y almacenamiento, y el dynamic batching (procesamiento de lotes dinámicos) genera cierta sobrecarga de la CPU.

Configuración de Material para Batching

Solamente los objetos compartiendo el mismo material pueden ser batched juntos. Por lo tanto, si usted quiere lograr un buen batching, usted necesita compartir muchos materiales entre diferentes objetos como sea posible.

Si usted tiene dos materiales idénticos que difieren solo en texturas, usted puede combinar esas texturas a una sola gran textura - un proceso llamado texture atlasing. Una vez las texturas estén en el mismo atlas, usted puede utilizar un solo material más bien.

Si usted necesitar acceder las propiedades compartidas del material desde los scripts, entonces es importante tener en cuenta que modificar Renderer.material va a crear una copia del material. En vez, usted debería utilizar Renderer.sharedMaterial para mantener el material compartido.

Mientras renderice shadow caster (emisores de sombras), estos a menudo pueden ser batched juntos incluso si su materiales son diferentes. Los shadow caster en Unity pueden utilizar dynamic batching incluso con diferentes materiales, con tal de que los valores en los materiales necesitados por el shadow pass sean el mismo. Por ejemplo, muchas cajas pueden utilizar materiales con diferentes texturas, pero para un renderizado de shadow caster las texturas no son relevantes – en este caso estos pueden ser batched juntos.

Batching Dinámico

Unity puede automáticamente batch objetos en movimiento al mismo draw call si ellos comparten el mismo material y cumplen con los otros criterios. El batching dinámico es hecho automáticamente y no requiere un esfuerzo adicional por su lado.

  • Batching objetos dinámicos tienen una cierta sobre carga por vértice, entonces batching es aplicado solamente a meshes conteniendo menos de 900 atributos de vértice en total.
    • Si su sombreador está utilizando un Posicionamiento de Vértice(Vertex Position), Normal y un solo UV, entonces usted puede batch hasta 300 vértices; dónde si su sombreador está utilizando Posicionamiento de Vértices, Normal, UV0, UV1 y Tangente, entonces solo 180 vértices.
    • _Por favor tener en cuenta: el limite de la cuenta de atributos puede cambiar en el futuro.
  • Los objetos no serán batched si contienen espejos en el transform (mirroring), por ejemplo el objeto A con +1 scale y el objeto B con –1 scale no pueden ser batched juntos.
  • Utilizar diferentes instancias de material - así sea si ellos son esencialmente lo mismo - va a hacer que los objetos no se batched juntos. La excepción es shadow caster rendering.
  • Objetos con lightmaps tienen un parámetro adicional de renderizado: un indice lightmap y offset/scale al lightmap. Entonces generalmente los objetos dinámicos lightmapped deberían apuntar a exactamente la misma ubicación lightmap para ser batched.
  • Shaders Multi-pass van a romper el batching.
    • Casi todos los Unity shaders soportan varias luces en forward rendering, efectivamente haciendo adicionales passes por estas. Los draw calls para “per-pixel lights adicionales” no serán batched. *Legacy Deferred (light pre-pass) rendering path tiene dynamic batching desactivado, ya que tiene que dibujar objetos dos veces.

Ya que trabaja transformando todas las vértices de objeto en espacio del mundo en el CPU, solamente es una ganancia si ese trabajo es menor que hacer un “draw call”. Exactamente qué tan costoso es un draw call depende de muchos factores, principalmente en la API gráfica utilizada. Por ejemplo, en consolas o APIs modernos como Apple Metal la sobre carga de draw call es mucho menor, y por lo general el dynamic batching no puede ser una ganancia en absoluto.

Static Batching (Agrupamiento Estático)

El Static batching le permite al motor reducir los draw calls por geometría de cualquier tamaño (teniendo en cuenta que no se mueva y comparta el mismo material). A menudo es más eficiente que dynamic batching (no transforma vértices en el CPU), pero utiliza más memoria.

Con el fin de tomar ventaja del static batching, usted necesita especificar que ciertos objetos son estáticos y no se moverán, girarán, ni escalar en el juego. Para hacer esto, usted puede marcar los objetos como estáticos utilizando la casilla de verificación Static en el Inspector:

Utilizar el batching estático va a requerir una memoria adicional para almacenar la geometría combinada. Si varios objetos comparten la misma geometría antes del batching estático, entonces una copia de la geometría será creada para cada objeto, ya sea en el Editor, o en el tiempo de ejecución. Esto no siempre será una buena idea - a veces usted va a tener que sacrificar el rendimiento de renderización evitando el batching estático para algunos objetos para mantener una huella pequeña de memoria. Por ejemplo, marcando árboles como estáticos en un nivel denso de bosque puede tener serios impactos de memoria.

Internamente, el batching estático funciona al transformar los objetos estáticos a espacio del mundo y construir un vértice grande + un buffer indice para estos. Luego para los objetos visibles en el mismo batch, una serie de draw calls “baratos” se realiza, con al menos ningún cambio de estado entre ellos. Por lo que técnicamente no tiene “3D API draw calls”, pero guarda los cambios de estados hechos entre ellos (lo cual es la parte costosa).

Recomendaciones:

Actualmente, solo los Mesh Renderers, Trail Renderers, Line Renderers, Particle Systems y Sprite Renderers están agrupados. Esto significa que skinned Meshes, Cloth (tela) y otros tipos de componentes de renderización no son agrupados.

Los Renderers solo hacen un batch (lote) con otros Renderers del mismo tipo.

Sombreadores semitransparentes en su mayoría requieren que lo objetos sean renderizados en un orden de atrás para adelante para que la transparencia funcione. Unity primero ordena los objetos en este orden, y luego intenta batchlos - pero ya que el orden debe ser estrictamente satisfecho, esto en su mayoría significa que menos batching puede lograrse con objetos opacos.

Combinar los objetos que están cerca manualmente puede ser una buena alternativa para draw call batching. Por ejemplo, un armario con muchos cajones puede tener sentido en solo combinarlo a un solo mesh, ya sea en una aplicación de modelado 3D o utilizando Mesh.CombineMeshes.


Optimizando el Rendimiento Gráfico
Modelar Personajes para un Rendimiento Optimo