Search Unity

I am sure that you know about Unity’s built-in Dynamic and Static Batching, which help reduce the number of draw calls in your game.

You can see Batching working in the Stats window when the “Saved by batching” count is greater than zero. But unfortunately it is much harder to tell why Batching is NOT working. The Unity Manual provides some information about why this might be happening, though you have to rely on an educated guess based on that information.

Fortunately, Unity 5.6 adds a new feature to the Frame Debugger which says exactly why Unity started a new batch.

Frame Debugger is a window in Unity which shows every batch in your game along with additional details about shaders, textures, and numerous settings used in a batch. The Frame Debugger window can be opened from the Window > Frame Debugger menu and has been available since Unity 5.0.

Before digging deeper into cases when Unity starts a new batch, let’s talk about what batches and batching are.

With Unity 5.6 the Frame Debugger now says exactly why Unity started a new batch.

Batch

To draw an object on screen in your game Unity needs to issue a “Draw” command to the graphics API. This action is essentially called a “Draw Call”. But before doing this, Unity also needs to set all the GPU states required to draw this object: mesh, shader, textures, blending settings and other shader properties. State change commands plus one or more draw commands is what we call a Batch.

Batching

What makes a batch slow is the GPU state change commands, while draw commands are actually pretty cheap. This is why Unity tries to pack several objects being rendered using the same GPU state into one batch. This process is called Batching.

Unity has three types of batching: static batching, dynamic batching and GPU instancing.

  • Static batching combines static meshes in one or more large meshes at build time and at run time renders them as one batch per mesh.
  • Dynamic batching takes several small meshes each frame, transforms their vertices on the CPU, groups many similar vertices together, and draws them all in one go.
  • GPU instancing (added in Unity 5.4) draws many identical objects with different positions, rotations, and other shader properties in fewer draw calls.

What breaks batching

Sometimes you can clearly see in the editor that objects you expect to be batched, for some reason, are not. First of all, check if batching is enabled in Player Settings. It sounds silly, but you won’t believe how many support requests we’ve received where this was the culprit.

Especially for you, we’ve prepared a sample project which illustrates all the cases when Unity has to start a new batch. Please clone it to your machine to follow along. Note that you need Unity 5.6 with the updated Frame Debugger to see the batch breaking causes illustrated in this project.

Here are batch breaking causes from the sample project (as of Unity 5.6). Each says why the object being rendered is in a separate batch:

  • Additional Vertex Streams — the object has additional vertex streams set using MeshRenderer.additionalVertexStreams.
  • Deferred Objects on Different Lighting Layers — the object is on a different light layer.
  • Deferred Objects Split by Shadow Distance — one of the objects is within shadow distance, the other one is not.
  • Different Combined Meshes — the object belongs to another combined static mesh.
  • Different Custom Properties — the object has a different MaterialProperyBlock set.
  • Different Lights — the object is affected by a different forward light.
  • Different Materials — the object has a different material.
  • Different Reflection Probes — the object is affected by a different reflection probe.
  • Different Shadow Caster Hash — the objects either have different shadow caster shaders, or have different shader properties / keywords that affect the output of the shadow caster pass.
  • Different Shadow Receiving Settings — the objects either have different “Receive Shadows” settings, or some objects are within the shadow distance, while some other objects are not.
  • Different Static Batching Flags — the object has different static batching settings.
  • Dynamic Batching Disabled to Avoid Z-Fighting — dynamic batching is turned off in Player Settings or disabled temporarily in the current context to avoid z-fighting.
  • Instancing Different Geometries — rendering different meshes or sub-meshes with GPU instancing.
  • Lightmapped Objects — the object uses a different light map or has different light map uv transformations within the same light map.
  • Lightprobe Affected Objects — the object is affected by different light probes.
  • Mixed Sided Mode Shadow Casters — objects have different “Cast Shadows” settings.
  • Multipass — the object is using a multi-pass shader.
  • Multiple Forward Lights — the object is affected by multiple forward lights.
  • Non-instanceable Property Set — non-instanced properties are set for an instanced shader.
  • Odd Negative Scaling — the object has odd negative scaling (e.g. (1, -1, 1)).
  • Shader Disables Batching — the shader explicitly disables batching with the “DisableBatching” tag.
  • Too Many Indices in Dynamic Batch — there are too many indices (more than 32k) in a dynamic batch.
  • Too Many Indices in Static Batch — there are too many indices in the combined mesh of a static batch. The limit is 48k indices on OpenGL ES, 32k on OSX and 64k on other platforms.
  • Too Many Vertex Attributes for Dynamic Batching — a submesh we are trying to dynamically batch has more than 900 vertex attributes.
  • Too Many Vertices for Dynamic Batching — a submesh we are trying to dynamically batch has more than 300 vertices.

Conclusion

Now you can use this new exciting Frame Debugger feature in your project and see if there’s something you can do with your scene to improve how Unity batches objects.

Please follow the project on Github for updates if new batch breaking causes are added as the engine evolves.

31 Comments

Subscribe to comments

Comments are closed.

  1. The new frame debugger is great, and I’m loving all the new extra information it’s giving me.

    I’m curious, how does Unity choose what object belong to which combined mesh? And is there a way to manually help it along? For example, in the editor sorting / ordering gameobjects based on their world position, or transform index.

    I’m working on a large open world game, and identical large rock objects which I’d assume would be perfect for batching are actually batched like 2-3 at a time. The new debugger tells me that it’s because they belong to different combined meshes. So it’s almost like Unity is randomly picking objects around the scene, and combining them regardless of their proximity to one another, or their world position relative to one another, or their transform index as children.

    It would be great to have a little bit more transparency with this, even at build time, as the whole batching process still seems like black magic most of the time.

  2. What exactly is a Forward Light ? My camera is set to deferred yet some lights seem to be rendered in a type of forward rendering pass.

    1. Valentin Simonov

      April 28, 2017 at 10:25 am

      A ‘forward light’ is just a light in forward rendering path (probably needs better wording). This means that some of your draw calls appear to be rendered in forward even if the camera is set to deferred. This happens when the shader doesn’t provide a deferred pass (LightMode = Deferred).

  3. You should help tell the solutions to the breaking causes above.

  4. Unfortunately the frame debugger is buggy. On a gtx970 it flickers the game view and the list.

  5. Kirill Nadezhdin

    April 9, 2017 at 7:18 am

    Lightmapped Objects — the object uses a different light map or has different light map uv transformations within the same light map.”

    What exactly is meant by “uv transformations“? Lightmap offset and tiling?

  6. This is a great feature !

    I just tried out on a relatively big scene with static batching on. I’ve found out some failed to batch together for “Different Combined Meshes” while sharing the same material. It made me realize that some of those automatically generated 64k verts combined meshes, are combining meshes with different material (so with several submeshes), and thus leaving meshes with shared material in different combined meshes which then failed to be drawn at once.

    Is there a way to configure that ? I mean combining meshes that have different materials won’t get batched together anyway (since you need the material change), so I would prefer to force the mesh combining step to get combined meshes by same material in the scene, so as to get better result in term of draw calls numbers. That would be sweet.

    Anyway, cool stuff !

    1. Valentin Simonov

      April 6, 2017 at 11:06 am

      I am looking at the static batching code and we actually do sorting by material and lightmap id.
      You can try using https://docs.unity3d.com/ScriptReference/StaticBatchingUtility.Combine.html and bake meshes manually.

    2. Valentin Simonov

      April 6, 2017 at 11:22 am

      Ah, wait. It sorts materials based on Renderer.sharedMaterial which doesn’t take into account different materials on submeshes. Probably we should rethink how this code works.

      1. Good to know. Thanks for that.

  7. very stable version compare to prior released , but I’ve found HDR problem, HDR not working on mobile device, Is there anybody with same problem??

  8. This doesn’t seem to work with UI batches. You can select the batches in the Frame Debugger but no reason is given for new batches.

    1. Valentin Simonov

      April 5, 2017 at 3:10 am

      UI generates its mesh separately from other objects.
      We are working on the UI Profiler view the Profiler Window, stay tuned.

  9. I have many objects which are identical, yet they can’t be batched. The frame debugger states that the material is different than the previous one. Of course it is different because the previous object is a totally different one. Why does this matter and how can I force Unity to draw objects in some order so that the gnomes in charge of batching are happy?

    1. Valentin Simonov

      April 4, 2017 at 12:27 pm

      This depends on your scene. When rendering a scene, Unity sorts all objects (front to back for opaque objects and back to front for transparent objects) and puts them into groups. If your objects happen to be far away along camera forward axis they will end up in different groups and will not be batched.

      1. All objects are exactly on the same distance to the camera (give or take a few mm), yet batching still doesn’t work. By the way, this requirement is not documented anywhere.

    2. quote…. “I have many objects which are identical, yet they can’t be batched”
      quote…. “Of course it is different because the previous object is a totally different one.”

      How can they be totally different if they are identical?

      1. The object Unity renders is a different object (different material) than the one before and thus batching brakes.

    3. you can use Material.renderQueue to control the render order of objects – I used this to break unity’s sorting and force batching for the same objects at different depths from camera. It used to be only accessible from script, but I believe new unity has this exposed in material inspector.

      1. Thanks, will try that.

  10. Andrei Khristoradov

    April 4, 2017 at 10:44 am

    Thank you very much for this structured and clean explanations. The only thing what i would like to know is how to avoid batch break when using light probes. Will it be possible to use light probes with dynamic batching at all?

    1. Valentin Simonov

      April 4, 2017 at 12:23 pm

      Unfortunately this is not going to happen because such objects need different shader uniform data. We are working on enabling light probes for instancing though.

  11. Isn’t batching irrelevant when using DX12 or Vulcan?

    1. Valentin Simonov

      April 4, 2017 at 12:29 pm

      These APIs don’t magically let you draw millions of different objects on screen, you will still have to optimize your content manually or rely on Unity to do so. But of course, it really depends on your project — make sure that batching doesn’t take more resources than it tries to save by testing with batching disabled.

  12. Ciro Continisio

    April 4, 2017 at 8:59 am

    Really good post, Valentin!

  13. This is exciting, I hope you will further improve this, like adding:
    – color code the meshes that are batched together.
    – selecting mesh in hierarchy selects corresponding batches in frame debugger.
    – improvements to frame debugger batch list: option for stack view vs tree view without all the hierarchy clutter.
    – ability to know how many batches a specific light or object contributes to.
    – highlight objects that cost high amounts of batches.
    etc…
    That sort of things, cheers.

  14. Thanks for the great explanation! Can this be added into a tips and tricks video?

    1. Valentin Simonov

      April 3, 2017 at 7:51 pm

      What video do you mean?

      1. I think he is requesting the team at Unity that creates Educational Video’s to make a Video series out of these valuable blog posts on optimization (and include the posts by Kerry Turner)

        Cheers
        b

  15. Great feature and like the idea of the example project with all testcases!

  16. alright, 5.6 has some cool features, but why the frame count still doesn’t represent the real FPS?