Using queries to cull objects

Would it be feasible to do this? I have a lot of objects being drawn, where many of them are hidden behind others. The algorithm would be something like:

  • Every 1s or so, use a query for GL_ANY_SAMPLES_PASSED for every object.
  • For every frame, ignore drawing of objects that failed the test above.

A drawback is that a second may pass, in worst case, before an object is drawn that should be visible.

The possible drawback, which I don’t know about, is if doing queries of this type adds much overhead or resource costs. And maybe there are other tricks to do the same thing.

I know about the obvious ways to cull objects, like testing if outside of view frustum or doing your own detection of hidden objects.

Performing occlusion query during rendering is practically free. It simply increases a hardwired atomic counter each case a fragment passes depth/stencil tests.

So I would recommend you to perform occlusion culling as often as possible but only use their results when they are available (e.g. in the next frame). This way you can both maximize performance and keep the possibility of a false occlusion very low.

Thanks for the answer!

As I understand it, I can do this culling in two ways. Either manually (reading out the query result and use it as a condition), or use the glBeginConditionalRender() that will “automatically” use the results from queries.

It looks easier to do the manual part; is there any obvious advantage of using glBeginConditionalRender()?

Yes, the CPU doesn’t need to wait for the result of the query.

This can cause considerable delays, because the query result is available only when all the draw calls issued before the glEndQuery() have been processed.

However, on the other hand glBeginConditionalRender() will simply do the rendering if the occlusion query result is not available yet even if it would turn out that the object is occluded. Anyway, if you use the previous frame’s result using conditional rendering, everything should work just fine.

Using the previous / current frame’s result is orthogonal to the manual / glBeginConditionalRender issue.

And glBeginConditionalRender can also wait for the query result if you pass GL_QUERY_WAIT mode, it can even skip rendering in just some framebuffer regions. You cannot do this manually.

Yes, but performance-wise it is usually better to do GL_QUERY_WAIT in the next frame than do GL_QUERY_NO_WAIT in the current frame.

Except that occlusion changes between frames, rendering the results inaccurate for the next frame. But maybe I’m missing something here?

Seems like the ideal would be to serialize the results of the tests into an on-GPU buffer and read directly from that buffer for conditionally rendering that frame. Then there’s no stall and no out-of-date occlusion.

Suppose you are rendering a list of complex objects. One possibility is to render a simplified version of them first (bounding box for example), with screen output disabled, and then use conditional rendering for the full objects.

This doesn’t work very well if they are “big” and can occlude each outer, I suppose?

Using the information in the next frame may indeed use invalid information if things move around. In an action game, it could mean that you do not see something when you turn around quickly that you really want to see. But on the other hand, missing one, or a few frames, may be acceptable for many applications? Could be a problem for the Counterstrike type of games, where players are optimizing milliseconds to get fastest response.

Disabling occlusion algorithms when you “turn fast” may be a bad idea, as that is the case where low frame rate is as most disturbing.