Version: 2020.1
Оптимизация производительности графики
Rendering statistics window

Батчинг вызовов отрисовки (Draw Call Batching)

Для отрисовки объекта на экране движок отправляет команду (draw call) графическому API (например, OpenGL или Direct3D). Графический API производит значительную работу для каждого DC, что сильно влияет на производительность CPU.

Unity uses two techniques to address this:

  • Dynamic batching: for small enough Meshes, this transforms their vertices on the CPU, groups many similar vertices together, and draws them all in one go.
  • Static batching: combines static (not moving) GameObjects into big Meshes, and renders them in a faster way.

Built-in batching has several benefits compared to manually merging GameObjects together; most notably, GameObjects can still be culled individually. However, it also has some downsides; static batching incurs memory and storage overhead, and dynamic batching incurs some CPU overhead.

You can enable or disable Dynamic and Static batching through Unity’s Player settings under Other Settings.

Material set-up for batching

Батчатся только объекты, имеющие один и тот же материал. Соответственно, для эффективного батчинга вам необходимо делать материалы общими для множества объектов, если это возможно.

Если у вас есть два одинаковых материала, отличающихся только текстурами, можно объединить эти текстуры в одну большую — процесс часто называемый созданием текстурного атласа. Так вы сможете использовать один материал вместо двух.

Если нужно получить доступ к свойствам общего материала из скрипта, то важно помнить, что изменение Renderer.material приведёт к созданию копии материала. Вместо этого следует использовать свойство Renderer.sharedMaterial, чтобы материал остался общим.

Shadow casters can often be batched together while rendering, even if their Materials are different. Shadow casters in Unity can use dynamic batching even with different Materials, as long as the values in the Materials needed by the shadow pass are the same. For example, many crates could use Materials with different Textures on them, but for the shadow caster rendering the textures are not relevant, so in this case they can be batched together.

Dynamic batching (Meshes)

Unity может автоматически батчить движущиеся объекты в один DC, если они используют общий материал и отвечают ряду других критериев. Динамический батчинг применяется автоматически и не требует дополнительных действий с вашей стороны.

  • 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.
    • If your Shader is using Vertex Position, Normal and single UV, then you can batch up to 300 verts, while if your Shader is using Vertex Position, Normal, UV0, UV1 and Tangent, then only 180 verts.
  • GameObjects are not batched if they contain mirroring on the transform (for example GameObject A with +1 scale and GameObject B with –1 scale cannot be batched together).
  • Использование разных экземпляров материалов — даже если они по сути своей являются одним материалом — сделает динамический батчинг невозможным.
  • Объекты с картами освещения имеют дополнительное свойство: индекс карты освещения и смещение/масштаб внутри карты освещения. Для батчинга объекты должны ссылаться на одно и то же место в карте освещения.
  • Multi-pass Shaders break batching.
    • Almost all Unity Shaders support several Lights in forward rendering, effectively doing additional passes for them. The draw calls for “additional per-pixel lights” are not batched.
    • The Legacy Deferred (light pre-pass) rendering path has dynamic batching disabled, because it has to draw GameObjects twice.

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)

Static batching allows the engine to reduce draw calls for geometry of any size provided it shares the same material, and does not move. It is often more efficient than dynamic batching (it does not transform vertices on the CPU), but it uses more memory.

При использовании статичного батчинга вы должны убедиться, что объекты статичны и не двигаются, не вращаются и не масштабируются во время выполнения. Если эти условия соблюдаются, можно пометить объекты как статичные, поставив галочку Static в Inspector:

Использование статичного батчинга требует дополнительной памяти для хранения объединённой геометрии. Если несколько объектов используют общую геометрию перед статичным батчингом, то копия геометрии создаётся для каждого объекта, либо в рантайме, либо в редакторе. Это может быть не очень удачной идеей — иногда вы можете пожертвовать производительностью визуализации некоторых объектов для снижения затрат памяти. Для примера, пометив все деревья как статичные на лесистом уровне вы можете получить серьёзный удар по объёму доступной памяти.

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).

Советы:

Currently, only Mesh Renderers, Trail Renderers, Line Renderers, Particle Systems and Sprite Renderers are batched. This means that skinned Meshes, Cloth, and other types of rendering components are not batched.

Renderers only ever batch with other Renderers of the same type.

Полупрозрачные шейдеры часто требуют объектов, которые визуализируются в порядке “от заднего к переднему”, чтобы прозрачность работала корректно. Unity сначала визуализирует объекты в этом порядке и лишь затем пробует сбатчить их — так как соблюдение этого порядка очень важно, то эффективность батчинга для полупрозрачных объектов страдает по сравнению с непрозрачнымию

Manually combining GameObjects that are close to each other can be a very good alternative to draw call batching. For example, a static cupboard with lots of drawers often makes sense to just combine into a single Mesh, either in a 3D modeling application or using Mesh.CombineMeshes.


  • 2017–10–26 Page amended

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

Оптимизация производительности графики
Rendering statistics window