Skip to main content
gamedev.net
🔒 Locked

Batching & Culling

Started by BearishSun 7 replies 1.3k views
Original Post
BearishSun
BearishSun
Hello, I created a class that batches meshes depending on their state changes(right now only based on their materials and declaration), and that works fine. All meshes with the same material are added to a single vertex buffer, so that only one draw call is required to render them. (This only applies to static meshes, i.e. those that are never transformed) But now I'm trying to implement culling, and I'm not sure how do I do that with the batches. The vertex buffer in the batch is huge and vertices are all over the map. So making any kind of bounding volume is useless, because it will probably encompass the whole map(it will always be visible), and polygon tests are too expensive. I tought about limiting the batches not only to mesh material and vertex declarations, but also to the distance between the two meshes. But that distance would have to be relative to the size of the map and would depend what kind of game my engine is used for(Indoor distances would have to be much smaller, outdoor greater) I also tought about making these massive batches (as I have now) and then split them into smaller and smaller grids until every grid is a batch of it's own, but with much smaller vertex count. I'm not sure how any of these methods would turn out, and whether I would get any performance increase from it at all. Do you guys have any ideas? How do the pros do it? Thanks
VladR
VladR
The pros dont try to be clever about something they know nothing about - in our case its the type of game/camera/environment. You have to know the type of game that the engine will be used for, otherwise it cant be remotely optimized and youll end up with general solution that will be far from fast and optimal.

Also, you must separate between terrain rendering and objects rendering since those operate above completely different datasets, size-wise.

If you still insist on general solution, at least code separate render/culling paths for terrain, objects, indoor so that the users have at least some basic optimization within their reach.

Plus, don`t forget that with one huge vertex buffer, the gfx card transforms ALL vertices that are within the range specified by parameters in DIP call, not just those indexed. This is easily reproducible - take some old/slow card and let it render the terrain (without texturing to avoid any fillrate issues) in several amounts of detail, always getting the vertices from same VB, just with different indices (with each LOD rendering less and less triangles) and see for yourself.
BearishSun
BearishSun
Thanks for the reply,

I think I'll just limit my use of batches for now, until I get make a few different working techniques and see which works the best.

I tought however, to first split the whole world into quadtree nodes, then make the maximum batch size = one node. There would be more than one batch per node possibly, in case there are a lot of different materials used. And then cull only the entire nodes + ofc any dynamic objects.

I'm also quite concerned with LOD rendering, as I don't think it will work well with entire batches (I haven't tried to implement it anywhere yet, don't even know how it works).

For now, I'll take up a terrain rendering book and try to get some answers there before I go further.
bzroom
bzroom
I plan on implementing an automatic batching system. For each material it'll start randomly and and add neighboring meshes that are within a threshold to the current batch until the batch reaches a certain size. Then the batch's bounding box will be calculated. I'll probably run this algorithm a few times to find the most optimal result, or i'll make it so I can manually seed the search. So I'll choose a mesh on the outskirts of town and let it work it's way inward.
BearishSun
BearishSun
Quote:
Original post by Christer Ericson
Quote:
Original post by BearishSun
[...] Do you guys have any ideas? How do the pros do it?
Have you considered culling before batching?


Sadly I don't think it's possible. Batching is just to slow to be done on a per frame basis. I just do it during initialization phase for static objects. And since dynamic objects have to be updated every frame I don't even bother batching them.

Quote:
Original post by bzroom
I plan on implementing an automatic batching system. For each material it'll start randomly and and add neighboring meshes that are within a threshold to the current batch until the batch reaches a certain size. Then the batch's bounding box will be calculated. I'll probably run this algorithm a few times to find the most optimal result, or i'll make it so I can manually seed the search. So I'll choose a mesh on the outskirts of town and let it work it's way inward.


That is something like what I had in mind, but it would most definately be a very complex algorithm.
Gage64
Gage64
Quote:
The vertex buffer in the batch is huge and vertices are all over the map. So making any kind of bounding volume is useless, because it will probably encompass the whole map(it will always be visible), and polygon tests are too expensive.


It sounds like batching is at a higher priority for you then culling, which is not a good strategy. If your world is even somewhat large and you're using a spatial structure (like a quadtree), then hierarchical frustum culling will always give you the biggest performance gain.

You should first build the spatial structure for your scene. After this, you do the rendering in two stages - first, figure out which nodes are visible. Then, draw the objects at each node, sorted by render state (You'll need to implement a render queue to do this).

As far as I know, this is how most engines work. While it will split some batches compared to your current method, it should still be much more efficient.
ItsDan
ItsDan
As gage said, first cull, then batch. Use your batching system to reduce the number of changes in renderstates, textures, etc.
-----------------------------------------------“The best, most affordable way to save the most lives and improve overall health is to increase the number of trained local, primary healthcare workers.”Learn how you can help at www.ghets.org
dmatter
dmatter
Quote:
Original post by BearishSun
Sadly I don't think it's possible. Batching is just to slow to be done on a per frame basis. I just do it during initialization phase for static objects. And since dynamic objects have to be updated every frame I don't even bother batching them.

It shouldnt be too slow to do per-frame. You're probably using a sub-optimal algorithm here.

I would work on making batching fast then go for a cull before batch technique.

Quote:
I tought however, to first split the whole world into quadtree nodes, then make the maximum batch size = one node. There would be more than one batch per node possibly, in case there are a lot of different materials used. And then cull only the entire nodes + ofc any dynamic objects.

This is basically what Gage64 described. Static objects they can be pre-sorted within the nodes into batches as you describe, I personally wouldnt store dynamic objects in with the static ones though and dynamic objects can and should be quickly sorted per frame into material batches, you just need to use a faster sorting algorithm [smile].

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.