Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to get Dynamic Batching to work?

Discussion in 'Editor & General Support' started by MrBurns, Aug 31, 2011.

  1. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    Hi,

    I read a bit now about dynamic batching and am pretty confident that everything is setup right so far.
    I have enabled Dynamic Batching in settings, I am batching a lot of small objects (24 verts, 12 tries each) with the same single material set with renderer.sharedMaterial... The material is not updated.

    Now I have thousands of these things on screen, all with rigidbodies, colliders, meshrenderer and stuff... But batch count stays zero and draw calls stay at a few thousands ;).

    How can this be?
    After all this is causing some trouble now even though we already doing static batching as soon as the rigid bodies go to sleep... But when they are moving it easily hits the draw call limit...

    Any help would be really appreciated!
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    there are multiple ways:

    1. you use lightmaps
    2. you don't use uniform scaling (try with no scaling at all aside of the default 1 1 1)
    3. the material is transparent which has impacts on batching
    4. they are not meshes but skinned meshes and have skinned mesh renderers which will not batch at all
    5. same goes for softbody stuff.
     
    mrtkhosravi likes this.
  3. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    Neither of this is the case...

    Here is the code generating a fragment of the kind above... That is all what's happening...

    if (SceneNode == null)
    {
    var mesh = new UnityEngine.Mesh();

    mesh.vertices = Vertices;
    mesh.uv = mesh.uv2 = UVs;
    mesh.normals = Normals;
    mesh.tangents = Tangents;
    mesh.triangles = Triangles;

    // create scene node...
    SceneNode = new GameObject();
    SceneNode.transform.parent = ParentTransform;
    SceneNode.transform.localPosition = MapRelativeBlockPos.ToVector3();

    SceneNode.name = "::DetachedFragment";
    SceneNode.layer = (int)Layers.Player;

    SceneNode.AddComponent<MeshFilter>().mesh = mesh;
    SceneNode.AddComponent<BoxCollider>();

    var rigidbody = SceneNode.AddComponent<Rigidbody>();

    rigidbody.mass = 0.1f;
    rigidbody.sleepVelocity = 1;
    rigidbody.sleepAngularVelocity = 1;
    }

    // add the expensive components we usually want to avoid...
    if (SceneNode.GetComponent<MeshRenderer>() == null)
    SceneNode.AddComponent<MeshRenderer>().sharedMaterial = Material;
     
  4. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    No sorry... Was code back a while. Parent doesn't have scaling in this version anymore. So that can't be the reason!
     
    Last edited: Aug 31, 2011
  5. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    If you're generating meshes yourself, it may be necessary to set renderer.sharedMaterial to the same material too, in order to get batching. I am assuming you're working with very low polygon meshes and aren't using different shaders or different scales between them.
     
  6. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    Yes all have scale (1,1,1) throughout the whole transform hierarchy. All the same material, set through renderer.sharedMaterial...

    Still doesn't work. Any requirements on the material? Its a non-transparent surface shader in opaque queue and some sort of detail/normal/parallax mapped shader but that shouldn't matter? It has four textures... All material parameters are static.

    I now even disabled shadow casting/receiving on these materials... Still no difference...
     
  7. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    Uhh I found something out:

    Switching to "VertexLit" rendering path enables batching...
    But it doesn't work for Forward/Deferred rendering.

    How can that be?

    Seems like UT is threading dynamic batching as an issue of mobile devices? I am not quite sure where they get this from. When destroying buildings ala APEX then there will be up to tens of thousands fragments flying around and the limit of 5000 draw calls per frame is just nothing... This truly cries for dynamic batching and this can only be performed efficiently within the rendering pipeline and not from script... But I hope that this isn't a joke that only VertexLit supports dynamic batching?
     
    Last edited: Aug 31, 2011
  8. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    Looks like it was also discussed here: http://forum.unity3d.com/threads/62714-Batching-HOWTO/page3

    But I still don't have the right answer... Is dynamic batching supported in Deferred rendering?!
    Also I don't get it why it is a problem at all... What's the difference between putting vertices into one large buffer and rendering a lot of small buffers? As long as they are order independent, which is the case if they are not transparent... I mean putting them into one buffer obviously works for us in case of our own static batching, in deferred rendering. Why can't Unity do this automatically?

    And even when there are occasions in which it leads to wrong results. Who say that dynamic batching has to be done? They could then just provide some sort of boolean value for mesh renderers making them available to dynamic batching and then the developer is responsible if something goes wrong...
     
    Last edited: Aug 31, 2011
  9. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    The material must be simple enough. as soon as the shader you use requires more than 1 pass, the batching will break.

    so for diffuse it should work for example.

    in cases where batching is not done, its not done cause doing it would cost more performance than it saves -> hence useless
    (or cause its technically not doable - alpha material batching due to depth sorting for example)
     
  10. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    At least so far there is nothing in the shader that should cause more than one pass. But maybe it is still too complicated for what reason ever, since using a simple shader solves it in some ways...

    Do you know if batching is supported at all in deferred rendering, in Unity 3.4?

    Just verified: Switching to "Mobile/VertexLit" shader, which should be quite simple enough does still not trigger batching in deferred rendering :(. It DOES work in forward rendering with such a simple shader, but who needs that? Don't really care about forward rendering anyway so I suppose I will also have to write a custom dynamic batcher for deferred rendering?! Also the batching, if it works, is not very efficient. the draw calls go down from 4000 to 1200, even though only 24 vertices are used per mesh... The main issue then is the physic engine which seems to eat up all CPU but thats because the optimizations we have are not ready right now.
     
    Last edited: Aug 31, 2011
  11. MrBurns

    MrBurns

    Joined:
    Aug 16, 2011
    Posts:
    378
    So maybe the conclusion, as for Unity 3.4, unless someone has something to add or correct ;)...

    1) Dynamic batching does work well for VertexLit rendering path
    2) It does work for Forward Rendering if the shaders are very simple, like Mobile/VertexLit
    3) It NEVER seems to work for deferred rendering
    4) Even if it does work, it seems to work "mobile" specific, which means judging by the quite disappointing draw call reduction of only a factor 3-4, which is somewhat ridicolous given the fact that we have an "optimal" setup for batching (a lot of small fragments with the same material). For PCs a much higher vertexcount per batch would be possible and urgently needed, since even with batching Unity soon hits the 5000 draw call limit... Which is a little weird since it should "know" that it is better to put more meshes into each batch instead of having a framerate of one; can't get worse so to speak...
    Besides putting more meshes into a batch on PC platforms, it could be further optimized by propagating items that have not moved during last frames into another generation (a more static batch).

    And please let us optionally enable batching in deferred rendering for individual object groups or transform hierarchies, by letting us decide if the resulting visual artifacts, if there are any, are acceptable or not...
     
    Last edited: Aug 31, 2011
  12. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    Because this is one of the first Google hits for "Unity Dynamic Batching not working" I though I would bump and add that using real-time Shadows will generally prevent dynamic batching as the objects need to be rendered again from the light's perspective as shadow casters/receivers (two separate passes) therefore they can't be batched dynamically.

    Often (in deferred rendering mode) this even prevents batching for materials/objects that are not shadow casters/recievers (vertex lit ect) or have have shadow casting/recieveing options disabled although I have no idea why. What's even more bizzare is that dynamic batching still seems to work when shadows are enabled for transparent materials in deferred mode but only if they have both cast and receive shadows options ticked in the mesh renderer options - disable just one of them and no more batching!?? I have no clue why this happens, "It just does"™.

    The dynamic batching black-box in 3.4's deferred mode seems rather wonky.
     
  13. TheCasual

    TheCasual

    Joined:
    Sep 30, 2010
    Posts:
    1,286
    Uhhh yea , this dynamic batching seems pretty messed. Im using simple planes , with a diffuse suface shader , no transparencies what so ever, and only non important SH lights , and not one thing will batch. In forward.;
     
  14. holyjewsus

    holyjewsus

    Joined:
    Mar 7, 2011
    Posts:
    624
    how many vertices do the planes have? are they the unity prefab ones, they're constructed out of many triangles, it might be over 300 verts.
     
  15. TheCasual

    TheCasual

    Joined:
    Sep 30, 2010
    Posts:
    1,286
    Nah not at all , i mean planes , out of max O.O (not quite a plane , been seg extruded once , still 16 - 20 verts a peice...
     
  16. rockysam888

    rockysam888

    Joined:
    Jul 28, 2009
    Posts:
    650
    (bookmarked)
     
  17. ImogenPoot

    ImogenPoot

    Joined:
    Jul 2, 2012
    Posts:
    214
    Batching is something totally independent of whatever you do with the rendering. As long as you don't need to preserve draw call order for some reason, say transparent shaders, rendering all objects with the same material in one call or in thousand calls makes no visual difference.

    The saying goes, "better make a few more draw calls, than having to copy geometry around in every frame". Okay, but when I hit the 4000 draw call limit, then this does not hold anymore. Because basically what we have then is "Better copy huge chunks of geometry around every frame, than having an unplayable game"... Unity definitely needs to adopt this latter philosophy, especially since copying geometry in optimized C++ is very fast compared to what you can do with the stupid UnityEngine.Mesh and C#.

    Or make it even easier. Just add a material flag "ForceBatching" which relieves Unity of any responsibility regarding visual artifacts. So if we NEED to do dynamic batching for performance reasons, then you should allow us to. Because as I said, rather some artifacts or wasted CPU performance than an unplayable game!
     
    Last edited: Jul 27, 2012
    mrtkhosravi likes this.
  18. tomworcom

    tomworcom

    Joined:
    Dec 27, 2011
    Posts:
    50
    I just stumbled over this thread searching for an answer.
    Can someone confirm this: I create a new scene and add 5 default cubes inside Unity, hit play and the stats give me 5 draw calls.
    But all cubes are using the same material, default diffuse.
    Shouldn't batching work then?

    UPDATE: I recreated the scene in a freshly created project - and there it works.
    Is something in my project settings responsible for this?
     
    Last edited: Jul 29, 2012
  19. ImogenPoot

    ImogenPoot

    Joined:
    Jul 2, 2012
    Posts:
    214
    You need to check "Dynamic Batching" in player settings. But anyway it is weird that this works. Try it with deferred rendering or more complex materials ;). I mean who has a bunch of boring cubes in his game. In real life, batching doesn't work!
     
  20. tomworcom

    tomworcom

    Joined:
    Dec 27, 2011
    Posts:
    50
    @ImogenPoot: Thank for your answer, the setting was on but I somehow missed that the "cast shadows" setting seems to break batching...
     
  21. ImogenPoot

    ImogenPoot

    Joined:
    Jul 2, 2012
    Posts:
    214
    For whatever reason. I mean okay, batched objects are not self-shadowing. But then at least UT could let us define sort of batching-groups where they always disable self-shadowing between objects in a particular group, so it won't make a difference.
     
  22. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    2,068
    Damn right.
    In Unity 3.5 it will not work with the simplest "forward rendering" diffuse provided by unity. (with 2 directional lights).
    It only worked with Vertex Lit for me.
     
  23. nerophon

    nerophon

    Joined:
    Aug 8, 2009
    Posts:
    35
    How to Make Objects Dynamically Batch in Unity

    they must share the same material

    the material must not be instanced (check material name in debug inspector)

    batching is applied only to meshes containing less than approx 900 vertex attributes in total (check mesh properties for some idea about this; for starters turn off normals tangents to reduce it)

    the textures must not include alpha

    scale breaks batching

    lightmaps break batching

    multipass shaders break batching

    layering other objects in between objects trying to batch can break batching

    if you are instantiating the object in code, you may be instancing the material; try re-applying the material asset through .sharedMaterial

    even within single-pass shaders, some can batch higher vertex attribute counts than others... in particular if you use a shader that colors vertices you’ll be adding attributes
     
  24. MrSoad

    MrSoad

    Joined:
    Dec 28, 2012
    Posts:
    7
    The "Saved by Batching" count will remain at zero even when dynamic batching is saving draw calls (Unity 4.1.2). Put 3 Unity cubes on screen all with the same material, press play and look at the stats. Draw calls 1 (Provided dynamic batching is enabled in the settings). Now scale one cube up and one cube down then press play again, draw calls will now read 3. The Saved By Batching count is always 0, I assume this is for static batching in Unity Pro but may be wrong...
     
  25. ArnoC

    ArnoC

    Joined:
    Sep 7, 2013
    Posts:
    10
    Found it !
    For me at least...

    I also had the same problem as everyone in this thread, and no answer did solve my case. I checked everything, with no luck.
    Then I played with the importance settings of my lights, and it did fix the dynamic batching issue, and the weird "verts and triangles multiplication" problem. I remembered that Unity has to draw each object once for each pixel light affecting that object.

    So:
    in addition to all the other advice given before in this thread, make sure the objects you want dynamically batched don't have too many pixel lights affecting them.
    (But you can have as many vertex lights as you want)

    Finding the right number of pixel lights on an object might be difficult, it seems to depend on too many parameters, like shaders used, light types, meshes, shadow settings etc.... plus it can change with each version of Unity.
     
    Arkade likes this.
  26. NoseKills

    NoseKills

    Joined:
    Jun 4, 2013
    Posts:
    25
    In the original code snippet there's : SceneNode.AddComponent<MeshFilter>().mesh = mesh;

    I understood that this creates a new instance of the mesh, which would increase draw calls ?

    Should be:
    SceneNode.AddComponent<MeshFilter>().sharedMesh = mesh;

    Or maybe i understood the docs wrong ...