• Advertisement
Sign in to follow this  

Problem with the concept of batching

This topic is 3478 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've read lots of articles about how batching is important rather than rendering individual meshes, and it was something I always took for granted. But now that I'm trying to implement it, I'm having a lapse in understanding how to actually implement it without stepping on my own toes. Let me give an example. Lets say I've got a group of character models running around on a small map. The map is a static mesh, the objects are all static meshes, its all good. And lets just assume for now that they're all using the same vertex format. The renderer copies each of the meshes into the vertex buffer, builds the index buffer, and then renders the whole lot in one draw call. Works great. But now lets say that one of the characters walks off the screen and out of the view frustrum. Or maybe they are removed from the world completely. Obviously we don't want to try to render what isn't on the screen. So now that object needs to be removed from the vertex buffer. Now, not only do we have an unused gap in our vertex buffer, but the index buffer has to be rebuilt yet again so that the draw call doesn't use indices that refer to the now-unused vertex data. And then, for whatever reason, a new character shows up, perhaps a player just joining or someone that was previously too far away to see. So now we have to add a new set of vertex data, and again rebuild the index buffer to include the new mesh at whatever position it ends up at in the vertex buffer. My question is, is it normal to have to redo (potentially large) parts of the index buffer every time part of the scene changes? Is this normal for batching, or am I overlooking something?

Share this post


Link to post
Share on other sites
Advertisement
This is one of the problems which we deal, and you'll have to decide what to do.
If you go for instancing, (at least, DX9.0, I heard DX10 has improved support) it's all or nothing. Draw everything, or don't draw.
This a good approach if you believe that 90% of the times your meshes will be on screen, or you won't gain much performance by clipping a couple of meshes which aren't actually shown.

But if clipping gets more important, you don't use some batching techniques increasing the CPU overhead. However, this is countered by the performance gain of clipped geometry. And remember clipped meshes don't consume Draw calls, which ironically reduces the CPU overhead.

You'll have to balance and decide.
In a perfect world, everything would be batched to the GPU, and a tiny program run in the GPU would be responsable for deciding what to show. This somewhat where SM 4.0+ wants to head to.
But if you stick to SM 3.0, you'll be making tough decisions.

Cheers
Dark Sylinc

Share this post


Link to post
Share on other sites
You don't usually want to batch geometry which isn't small enough. Characters in games are usually the most detailed objects and unless you're not aiming at visualizing crowds of low-quality characters rendering each character using separate set of draw calls should be fine. I would probably start thinking about batching if I had above 50 characters on screen, each less than 500 triangles - this of course depends very much on hardware you're targetting.

What you should consider for batching is only small objects if there's a lot of similar and simple objects (e.g. 100 chairs or stones). Particles is an extreme case where batching is a must. It doesn't make too much sense to batch things which use different render states, shaders etc. The benefit is when you can make a single draw call.

Hardware instancing (separate stream to describe instance data) is often an option as well. Depends on hardware.

Also, from my experience, some hardware (like current-gen game consoles) don't like too big batch sizes. 1024 triangles might be optimal for some of them.

To summarize, the easiest you can do is to - when instancing is not supported - have fixed size pool allocator for each mesh that is used by many objects and use that to manage your vertex buffer (constant time allocation, quick gap filling). Your index buffer should not need to change at all.

Hope that helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nairou
Let me give an example. Lets say I've got a group of character models running around on a small map. The map is a static mesh, the objects are all static meshes, its all good. And lets just assume for now that they're all using the same vertex format. The renderer copies each of the meshes into the vertex buffer, builds the index buffer, and then renders the whole lot in one draw call. Works great.

But now lets say that one of the characters walks off the screen and out of the view frustrum. Or maybe they are removed from the world completely. Obviously we don't want to try to render what isn't on the screen. So now that object needs to be removed from the vertex buffer. Now, not only do we have an unused gap in our vertex buffer, but the index buffer has to be rebuilt yet again so that the draw call doesn't use indices that refer to the now-unused vertex data.

And then, for whatever reason, a new character shows up, perhaps a player just joining or someone that was previously too far away to see. So now we have to add a new set of vertex data, and again rebuild the index buffer to include the new mesh at whatever position it ends up at in the vertex buffer.
You're not really mixing static and dynamic data aren't you?
Quote:
Original post by Nairou
My question is, is it normal to have to redo (potentially large) parts of the index buffer every time part of the scene changes? Is this normal for batching, or am I overlooking something?
As other posters pointed out, it is ok if kept under control. I clip using volumes of about 3k vertices each (I have generally easy vertex shaders, average shading complexity and lot of overdraw) and it seems to go just fine. Instead of recompacting the buffers, I break the batches. When I load the geometry, I mangle the indices so that successive batches can be merged and drawn in a single blow(n1). When I later want to clip, I run a quick estimation on the amount of batches and decide whatever or not I really want to break them.

You may be saying that this is not saving batches. Correct, but works on static data. I'm not sure if dynamic buffers would provide better performance in the first place, pretending to map a dynamic buffer which is immediatly needed always seemed overkill to me.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement