Frustum culling and sorting without increasing draw calls?

Started by
3 comments, last by primarybastard 3 years, 3 months ago

I'm writing a D3D11 renderer. My scene geometry is pretty simple and low poly so my current solution to rendering it is sorting every face by texture upon loading the scene, and then setting up the vertex/index buffers in that order. When it comes time to render it, I can iterate the array in order with minimal texture switches, and only drawing just before switching textures. This effectively limits the draw call count to the texture count.

However, if I want to implement frustum culling, or sorting the current visible geometry from front to back to reduce overdraw, I need to draw multiple times with the same texture because I'm skipping vertices.

So I either:
-Draw through the entire vertex buffer without culling to reducing draw calls
-Cull off-screen geometry, at the cost of more draw calls so I can skip vertex buffer elements

What is the optimal way to do this? To my knowledge, the only way to draw (I'm using DrawIndexed) is to specify a start index and the number of indices to draw from that point, not allowing for any “holes” to be specified in a single draw call.

And somewhat related, what is the best way to prevent rendering geometry that is inside the camera frustum, but occluded by other geometry? Is it acceptable to sort front to back (how do I do this?) and send the entire frustum to the GPU and let the depth buffer prevent the pixel shader from running? Or is there a more efficient approach that avoids sending the vertices at all?

Advertisement

In some cases you can encode the texture info into your mesh and then just have a super pixel shader that makes texture decisions. Now you can do your frustum culling without any issues.

In my case doing planet rendering in chunks, I found that there was a HUGE improvement after I implemented frustum culling so for me it was worth it but it probably depends on a lot of different things. I also sort from front to back, at least at the chunk level, but in my case everything is in an octree anyway so it's not to much extra work.

Checking for geometry hidden by other geometry is a trickier matter. I currently just let the Z-buffer handle that. I think it's a hard problem in the general case, although with terrain there might be some things you could try. I used to have a program that discarded chunks where all the geometry was facing away. The GPU will toss that stuff out anyway, but at least it saves you the CPU call and the GPU going though all the polygons in that chunk and checking normals.

primarybastard said:
This effectively limits the draw call count to the texture count… I need to draw multiple times with the same texture because I'm skipping vertices.

Draw calls where all the state is the same (i.e. the only things that change are the offsets into the vertex/index buffers) are relatively cheap. It won't hurt to issue multiple draw calls for each texture within your current sorting order.

primarybastard said:
To my knowledge, the only way to draw (I'm using DrawIndexed) is to specify a start index and the number of indices to draw from that point, not allowing for any “holes” to be specified in a single draw call.

Take a look at DrawIndexedInstancedIndirect. It will let you issue multiple draw calls together with different offsets into the index buffer.

primarybastard said:
And somewhat related, what is the best way to prevent rendering geometry that is inside the camera frustum, but occluded by other geometry?

The general term for this is “occlusion culling”. There are a variety of approaches, some more complicated than others, so it's worth doing some research on that topic.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

@swiftcoder Straightforward and answered all my questions, thanks.

This topic is closed to new replies.

Advertisement