Skip to content

Conversation

@nipmarsh
Copy link

Implement WEBGL2 occlusion queries in WEBGLRenderer for occlusion culling

@Mugen87
Copy link
Collaborator

Mugen87 commented Oct 23, 2020

Is this a duplicate of #15450?

@nipmarsh
Copy link
Author

nipmarsh commented Oct 23, 2020

@Mugen87 not really as it is done internally as a feature of WEBGLRenderer and very user friendly with a simple boolean for activation

@gkjohnson
Copy link
Collaborator

This would be a nice feature but I think I agree with @Mugen87 in #15450 (comment) -- I prefer Babylon's more selective API. It's also worth noting that getQueryParameter waits for any necessary queued GPU rendering to occur before returning so it's not great to call immediately after issuing the render commands. The MDN docs on getQueryParameter are a bit sparse but an equivelant opengl function glGetQueryObjectuiv notes that calling the function with GL_QUERY_RESULT will flush the render pipeline leaving the main thread idle until the rendering is done. It seems a common approach to avoid this is to use the previous frames query results which would also mean you don't have to render the full scene ahead of time -- you can just render bounding boxes to query as you render the scene front to back. It sounds like this is more or less what Babylonjs does from looking at their docs. Of course I think this complicates things with the way three.js manages rendering multiple scenes.

If something like a depth prepass is used though (#8676) where you have to render the full scene ahead of time anyway this type of more precise occlusion culling could probably come for (almost) free aside from the reading the query results back.

It's a bit long but this GPUGems article has some nice information about how use occlusion queries to speed up rendering. It get's into a lot of extra optimizations we probably can't add and don't really need here but was still useful to dig in to.

@simon-paris
Copy link

simon-paris commented Feb 25, 2021

Hi, I'm the author of the other PR #15450.

I found a few issues here:

  • You don't provide a way to enable/disable querys per-object. Querys aren't cheap and enabling them on every object is a huge performance drain on the CPU side. And often you'd want to query objects and use the result in application logic. i.e. if the door is visible, load the contents of the room, but you don't make the results available to users.

  • Not calling gl.deleteQuery. Query objects need to be manually disposed or it'll create a memory leak.

  • Your design renders the entire scene twice. Including high-poly meshes in occlusion queries is slow, normally you'd want to do the query on a bounding box instead of the high-poly mesh.

  • You're only making one query at a time, which means users will only get results every 2-3 frames

  • Multi-materials will only cause one query to be done on the first material in the group

@gkjohnson

getQueryParameter waits for any necessary queued GPU rendering to occur before returning so it's not great to call immediately after issuing the render commands

It doesn't seem to do this in WebGL

If something like a depth prepass is used though (#8676) where you have to render the full scene ahead of time anyway this type of more precise occlusion culling could probably come for (almost) free aside from the reading the query results back.

It's actually very expensive to do it like this, and it would cause flickering. The CPU cost of dispatching and reading the queries is suprisingly large. And the results of the queries is guarenteed not to return until at least the next frame. (Both of these problems are WebGL specific).

@gkjohnson
Copy link
Collaborator

It doesn't seem to do this in WebGL

I didn't realize this was the case. For those interested it's outlined in the WebGL2 spec page.

It's actually very expensive to do it like this, and it would cause flickering.

By flickering do you mean full display flickering from missing a frame because queries are taking a long time?

The CPU cost of dispatching and reading the queries is suprisingly large. And the results of the queries is guarenteed not to return until at least the next frame.

I only meant to say there wouldn't be extra incurred draw calls or rasterization (unless a bounding box was used for a query) because the depth buffer would already be finished and the color pass could be used for the query provided the depth prepass is performed for the full scene before drawing to the color buffer. The query results would still have to be read the next frame. I think occlusion settings for objects should still be individually controllable as they are in the Babylon API. And if queries are expensive I'd expect you'd only want to enable them for complex meshes / shaders.

@Mugen87
Copy link
Collaborator

Mugen87 commented Oct 24, 2024

Closing, see #15450 (comment).

@Mugen87 Mugen87 closed this Oct 24, 2024
@Mugen87 Mugen87 added this to the r170 milestone Oct 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants