Dynamic batching total verts != batching limit?

So dynamic batching has a limit of 900 vertex attributes total. Only when items are under that, they can be dynamically batched.
How come that when you have 100 objects of 50 vertices, i can dynamically batch them in 1 batch. Which the debugger shows as 1 draw call of 5000 vertices.

The documentation then tells us that the reason for the vertex limit is due to “overhead per vertex”.
So i can combine 100 50 vertex models to a mesh of 5000 vertexes. But i am not allowed to dynamically batch 2 objects of 2500 vertexes to the same 5000 vertexes total.

This seems like misinformation, or something or someone not being honest here. Or the system does not work as the documents imply. Why can we not combine bigger objects if we want to? Is there an optimal tipping point to dynamic batching? Is there a reason we can not try and play with that limit ourselves?

I would like to have this explained to me proper. Thanks in advance!

Here’s a bit of guessing: Dynamic batching probably combines the individual meshes on the GPU in order to be drawn in a single call. That means, that the objects have to merged into one larger object which means moving stuff around in memory. The cost of moving stuff in memory is usually dependent on how much stuff you move.

The key to the answer is probably ‘time’ and the dynamic behaviour ob batching. I assume that dynamic batching works iteratively, distributing the workload over many frames, so that the framerate does not stutter, effectively distributing the overhead cost. If you want to batch larger objects, you probably have to do it yourself.

Dynamic batching is combining mesh on the cpu side to save some performance on the gpu(by reducing state changes on the gpu)
This combining is not super cheep and so if you combine to big elements it cost more time than its saving in the end.
If you know that you have a group of small objects that will move together (so static batching is not option) then you can combine them yourself once and move them all together. That a lot cheaper then unity have to recombine them every frame.

I have build a simple script for my project maybe it helping you.

using UnityEngine;
using System.Collections;

public class MeshCombiner : MonoBehaviour {

    // Use this for initialization
    void Start () {

        MeshRenderer[] allChildrender = GetComponentsInChildren<MeshRenderer>();
        GameObject[] renderObjects = new GameObject[allChildrender.Length];
        for (int i = 0; i < allChildrender.Length; i++)
        {
            renderObjects = allChildrender.gameObject;
        }

        StaticBatchingUtility.Combine(renderObjects, gameObject);
    }
 
}

This works only if the combined objects only move together.
(its called StaticBatchingUtility but it just combines the meshes together)

1 Like

Any mesh under 900 attributes is potentially batched, but if it is 901, it is not. Unless your on DX11, in which case it’s slightly less than 900 due to a bug (I suspect they may be adding an additional attribute in DX11, bloating the mesh a bit, but I’m not sure what the actual issue is).

An attribute is one float4 of vertex data; this can be a UV coordinate, position, normal, etc. So if you have position, normal, tangent, and uv, that’s 900/4 vertices allowed per mesh.

I suspect this number was chosen for a few reasons:

  1. Combining two 25,000 vertices objects into one wouldn’t provide a speedup at all (saves one draw call), and would be expensive, so a limit makes sense. Combining 500, 100 vertices objects into one is a massive savings (499 draw calls saved!). So the number needs to be small enough to always be faster than the combining.
  2. The driver overhead of submitting a new draw call is such that, on many hardware devices, drawing under a few hundred vertices is basically free. In other words, the difference between drawing a 25 vertex model and a 200 vertex one is less than the time it takes to do the next draw call, so it’s really no cost difference for the additional 175 vertices.

Keep in mind the combine is done several times per frame, depending on your rendering setup. For instance, the shadow pass is done from the direction of the light, and may have objects not in the regular scene. Additionally, the shader used during the shadow pass is shared by all objects and simpler, so more objects can be dynamically batched together. I’ve also noticed that if you do a Depth-Normal prepass, nothing is batched, where as a depth only one works fine. (Maybe MRT is breaking it? Not sure).

1 Like

When I have a mesh with vertex colors too, would that mean it’s 900/5 vertices max? Is the DX11 thing you mentioned maybe always including vertex color or is it unrelated to that? And when I use UV seams or hard edges, that further increases the vertex count, right? The default cube seems to count as 24 vertices (6 sides times 4 vertices per side). That would mean under my worst possible conditions the upper limit is ( 900 / 5 ) / 3 = 60 triangles for a dynamically batchable mesh (unless the DX 11 bug you mentioned makes the limit even lower). :-/
I’m aware that more UV channels would lower it even further but I think I’ll only ever need one.

Yes, color, an extra UV channel, each count as another attribute reducing your count further. Note that UV channels in unity can now be a float4, so you can pack 2 sets of UVs into one channel, for instance.

I think the DX11 thing is likely either a bug or the inclusion of a vertex ID of some sort- but I don’t know for sure.

Each vertex can only have one of each component- so if you have a cube with hard edges, each vertex needs to be split into three, one for each sides normal/tangent. If you smooth the edge, you could make a box with less vertices, but it wouldn’t light like a box.

1 Like

Thanks for explaining!

Sadly all our objects move separately from each other, they are just identical objects. Think like snake body parts in the classic snake game. (just not grid based)

In general i suppose the limit makes sense in that it “is always faster” But there should be other ways to do this. I will consider doing it myself in this case, as we know exactly what needs to be batched. It should make a difference, but i am not sure why Unity didn’t make it more up to the user. Maybe it would be too unstable in that case.