Suggestions for reducing draw call count

We’re writing an RTS game, in which we expect 2000+ units (the more the better, really), and many are identical. Looking at the stats window, I think our performance bottleneck right now is draw count. We are at about 10,000.

I’m not using a lot of fancy lights or anything, just one big directional for the sun.

My question is: is there something fancy I can do to reduce the draw count when drawing so many units?

Thanks!

Hi, welcome to the forum!

You may be able to get better performance using Graphics.DrawMesh to draw all the units at once.

So Graphics.DrawMesh (pro only)is for drawing meshes that are not game objects sitting in the hierarchy. ( what I read in the script ref)

If thats true and some mesh has bones for animation how does it get updated? Some other direct method in pro that updates animation?

Graphics.DrawMesh isn’t powerful enough to handle things like animation. It is really just a performance optimiser for simple meshes that don’t have scripts or otherwise get updated.

If you have lots of meshes, lets say 256 meshes where maybe 30 are on-screen at a time, is it better to try to go for less draw calls with bigger meshes, or smaller meshes and lots of draw calls?

You always want fewer draw calls.
But when you combine the meshes make sure its just the meshes that you might see at one time.

If you have a bunch of rocks in two valleys combine them into 2 meshes.

old script - CombineChildren is on the wiki
api - Mesh.CombineMeshes is new in 2.6 I suppose a new CombineChildren2 could be written.

I have no idea how much faster just drawing them with Graphics.DrawMesh would be.

What I’m thinking of is a landscape mesh(procedurally generated) taking the place of Unity’s built-in terrains, composed of square sections of land. Each section contains 64 quads in each direction (16k total). At the moment there’s about 30 draw calls based on how many meshes are visible. So the question is, do I try to make even more smaller meshes, or do I make each mesh bigger for fewer calls, bearing in mind that doubling their size means there will sometimes be even more geometry overlapping the edge of the screen and only partly visible. Is the extra overhead of not being able to cull those extra mesh parts worth trading off against fewer draw calls? I guess I’ll have to experiment more.

I think I read that meshes around 5k triangles (maybe up to 10K) is no big deal to render. So if the entire map is 16k quad / 32k tri, maybe break it up into 4x4 or 5x5 tiles.

Optimizing like this is something you need to figure out, we cant help much because we dont know what the terrain really looks like, how much is occluded.

Making the map with smaller tiles is bad. The question is how big can you make them without pushing too many triangles to the screen, while staying under 5k-10k per mesh.

I dont recall if the 5k was triangles or vertexes.

Also you have a budget of around 400 draw calls on a PC so no point in worrying about this if you dont have much stuff on the terrain. Depends on the game. The island demo is around 350-500 draw calls depending on where you are looking.

At Turbine they used:
Landblock 160m
Quad 5m
32x32 quads/landblock
1024 quads/landblock
2048 triangles/landblock

They draw 3x3 landblocks at full rez, character in the middle. Everything else at some LOD setting.

At 5m per quad you get a very rough ground.

Hmm ok thanks for the info, I’ll table with the mesh section size and see what I find. Initially it looks like doubling the mesh section size actually makes it slower, probably too many extra traingles not getting occluded off the edge of the screen.

64x64 quads is 4096 quads 8192 triangles so maybe that being at 5k-10k is best. I should have done that math the first time :slight_smile:

Well I did some testing, subdividing the meshes successively more to see what effect it had on speed.

Finding #1 was that making the mesh sections bigger - providing fewer draw calls, actually made it slower! That would be, 128x128 quads per mesh, which is 16k quads, or 32k triangles per mesh. Seems to be too many despite being only a few draw calls per frame. Plus factoring in some time lost spent drawing more triangles off screen due to the coarser culling.

So instead I tried going the other way and increasing the number of draw calls by making the individual meshes have less triangles. Here are my findings:

#2 My normal framerate was 87fps with 64x64 per mesh, ie 4096 quads, or 8192 triangles. Came out around 30 or so draw calls per frame based on my camera view. The camera view has a LOT to do with this - I have kind of a semi-overhead-behind-shoulder view which shows perspective but cannot see the horizon, so far off meshes are not on-screen.

#3 Reduced mesh size to 32x32 per mesh, ie 1024 quads or 2048 triangles per mesh, potentially quadroupled the number of draw calls. Framerate went up to 105fps, probably around 100 draw calls.

#4 Reduced mesh size to 16x16 per mesh, ie 256 quads or 512 triangles per mesh, potentially quadroupled the draw calls again. Framerate still went up to 112fps! Draw calls is around 250-300.

#5 Thought I’d try even smaller, 8x8 per mesh 64 quads or 128 triangle per mesh, again quadroupling draw calls. Framerate DROPPED this time to under 90fps. Drawcalls is over 850.

So it’s pretty interesting. It largely depends on how much is seen by the camera of course. Then it’s matter of trading off mesh size for draw calls. Once the draw calls got up to, like you said, probably in the 3-400 range, it hits a limit.

I happen to have scaled the mesh size in proportion to number of triangles but quite possibly you could get away with more triangles per mesh if you have denser meshes, and squeeze out more triangles for the number of draw calls?

I’m happy with the results and will head out with the 112fps scenario.

Thanks ImaginaryHuman, that was an informative investigation.

You’re welcome.

Just as a note I tried increasing the density of meshes, ie more triangles appear on screen, same number of draw calls. You can in fact squeeze more triangles out of it. Or to put it another way, you can increase the number of triangles faster than you can increase the number of draw calls.

I roughly doubled the number of triangles on screen and the framerate came down from 115 to about 90, rather than cutting in half as you might expect. So you get about double the number of triangles being increasable per a given number of draw calls, or so it seems.

Cool. Thanks for posting that.

I’m also making my own ground terrain, so I’ll be doing this kind of testing soon(ish).

Dont forget you still need to put stuff on the terrain with less than 400 calls total.

You may know this already each light/shadow etc… is extra calls. Doing testing with the light setup you plan to use is important. I was setting up lights/ shadows /AO today using my pro trial version.

Hey, yeah, thanks for the tip about lighting. I am going ahead with dynamic vertex lighting - it does have a penalty but nowhere near as much as using pixel shaders. Besides, because I’m using a custom shader (fixed function only) I can’t really use the per-pixel lighting. It doesn’t appear that vertex lighting does any extra draw calls because it’s built into OpenGL’s lighting equasion thingamy. I am quite happy to see that added even 8 lights still has reasonable performance.