Version: 2018.1
Optimizando el Rendimiento Gráfico
Modelar Personajes para un Rendimiento Optimo

DrawCallBatching

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.

Dynamic batching (Meshes)

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 dynamic GameObjects has certain overhead per vertex, so batching is applied only to Meshes containing no more than 900 vertex attributes, and no more than 300 vertices.
    • 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.

Dynamic batching works by transforming all GameObject vertices into world space on the CPU, so it is only an advantage if that work is smaller than doing a draw call. The resource requirements of a draw call depends on many factors, primarily the graphics API used. For example, on consoles or modern APIs like Apple Metal, the draw call overhead is generally much lower, and often dynamic batching cannot be an advantage at all.

Dynamic batching (Particle Systems, Line Renderers, Trail Renderers)

For components with geometry that Unity generates dynamically, dynamic batching works differently compared to how it works for Meshes.

  • For each compatible renderer type, Unity builds all batchable content into 1 large Vertex Buffer.
  • The renderer sets up the Material state for the batch.
  • Unity binds the Vertex Buffer to the Graphics Device.
  • For each Renderer in the batch, Unity updates the offset into the Vertex Buffer, and then submits a new draw call.

When measuring the cost of the Graphics Device calls, the slowest part of rendering a Component is the set-up of the Material state. Submitting draw calls at different offsets into a shared Vertex Buffer is very fast by comparison.

This approach is very similar to how Unity submits draw calls when using Static batching.

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.

Internally, static batching works by transforming the static GameObjects into world space and building one shared vertex and index buffer for them. If you have enabled Optimized Mesh Data (in the Player Settings) then Unity removes any vertex elements that are not being used by any shader variant when building the vertex buffer. There are some special keyword checks to perform this; for example, if Unity does not detect the LIGHTMAP_ON keyword, it removes lightmap UVs from a batch. Then, for visible GameObjects in the same batch, Unity performs a series of simple draw calls, with almost no state changes in between each one. Technically, Unity does not save API draw calls, but instead saves on state changes between them (which is the resource-intensive part). Batch limits are 64k vertices and 64k indices on most platforms (48k indices on OpenGLES, 32k indices on macOS).

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.


  • 2017–10–26 Page amended with limited editorial review

  • Added note on dynamic batching being incompatible with graphics jobs in 2017.2

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