Does static batching have undocumented vert limit requirements?

We have a large, high-poly scene (around 2-3 million verts in the frustrum from some camera positions). The vast majority of these are just static models so we are trying to ensure batching is working to reduce the draw calls to a minimum before doing further optimisation like lodding, atlasing or bump mapping which will require artist work.

Accordingly we’ve simplified all models to use a single material and marked them as static. My belief is that this should reduce draw calls to a minimum and improve performance. It does indeed reduce draw calls, but performance seems to go dramatically DOWN, instead of up, the framerate dropping to 7fps with static batching enabled, vs. about 15fps with it off.

To confirm what we were seeing I created a test scene with a single cube, a diffuse material, no lights and marked as static. As I ramped up the number of cubes in the scene, performance was exactly as expected: with static batching on, we got a single draw call and good performance; with it off we got lots of draw calls and bad performance. However, at exactly 21.9 thousand verts performance went from 500fps to 50fps. We still had a single draw call, all batched, just adding 12 verts seemed to crash the performance by a factor of 10. With static batching off, this was not the case, performance degraded linearly all the way, as you would expect.

The really strange thing is that if I leave that ‘one-too-many’ cube in the scene and just give it a different material, performance is just as good as if it isn’t there at all. In both cases Unity makes 2 draw calls, which seems to be the key thing - basically it’s the size of the size of the mesh in the batched call that Unity makes to the graphics api that seems to determine performance. Below a certain threshold, Unity goes like greased lightning. Above it, it slows to a crawl.

Could this be a cache-line-length issue? I need to get some different hardware to try this out on to see.

In the meantime, anyone with any other clever ideas gratefully accepted.

I wonder if the strange behaviour I saw is related to what you’re seeing.

We have a large roman stadium in our scene, around 200k verts total, maybe 150-200 child objects, around 10-20 materials shared by the children. We marked the whole thing as static (recursively), but at run time we were noticing the batched draw calls was exactly 0, and we were getting thousands of draw calls.

So, I created a little script to run the static batching utility on all the children of the stadium, and lo-and-behold it started batching the calls. Can you try running the script below (or something similar) in your scene at runtime and see if it gets you past this 21.9k verts limit? If so, that would explain what was going on for us and hopefully solve things for you.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CombineStaticMeshes : MonoBehaviour 
{

void Start () 
{
	List<GameObject> children = new List<GameObject>();
	foreach (Transform child in transform) {
		children.Add(child.gameObject);
	}
	StaticBatchingUtility.Combine(children.ToArray(),gameObject);
}
}

(Looking at the above, I could probably have done away with the list and created a GameObject, then used a for rather than foreach loop for assignment, and sped up the script a bit. That being said, this was just a hack I threw together.)

Good luck.

Radeon drivers on OS X have a bug where performance plummets when a single object has around 22K verts. Nothing to do with Unity, although Unity 3.4 reduced the number of verts that will be used for objects when static batching is enabled, to work around the bug.