Concepts for supporting Occlusion Culling
If a tile can't be seen because it is behind other geometry or not rendered because it is off screen / the tile geometry doesn't match the bounding box well then it's not worth refining the tile to the next layers. If a parent tile is already refined and then suddenly wouldn't be visible because the camera moved then the parents occlusion visibility can be inferred from child tiles, similar to frustum culling (though this may cause similar issues to the frustum culling approach due to parent tile sets being implicitly removed resulting in cyclic loading. See #741) (Child tiles may also not be visible while a parent tile is due to geometry differences, also potentially resulting in cyclic loading if not handled correctly).
Occlusion culling could be done in the following ways and added as a plugin - it shouldn't need to be synchronous:
- Occlusion queries (may not work well with batched mesh, occlusion queries may just report if something was rendered at all during the rasterization process, not if it's visible by the end of the render pipeline - eg the first mesh rendered in a scene will always be considered visible)
- GPU id rasterization, readback (best done as part of a broader pipeline) (can be counted and returned via compute shader, rendered at lower resolution)
- CPU worker rasterization
- CPU raycasting to determine visibility (in worker?)
cc @lojjic @dbuck your comments on Twitter are what led me to thinking through this a bit more - not sure if you have any further thoughts. Though rereading the tweet it sounds more like raycasting is used to determine more precise distances for screenspace error calculation over the bounding box calculations. Is that right?
it sounds more like raycasting is used to determine more precise distances for screenspace error calculation
That would probably be smart 😉 but no, currently it's just a "downgrade if not seen" while still using bbox distance. I don't remember if we tried using the raycast distance - @dbuck do you recall?
We did experiment briefly with webgl2 occlusion queries, but it gave false positives due to render order like you hinted at.
Oh interesting! Good to know. If you have any more concrete details on the improvements (performance, number of tiles loaded / rendered, approach for determining when / how many raycasts to run, etc) or rough algorithm that would be great to know. Did you guys have to make changes to the core library to achieve this?
We did experiment briefly with webgl2 occlusion queries, but it gave false positives due to render order like you hinted at.
This is what I figured - good to have it confirmed. Occlusion queries don't sound like a viable solution in this case, then.
The other issue when we were looking into it was that at the time, safari 15 wasn't yet out! And that was a LARGE chunk of our mobile users that couldn't use gl2 at that time. All to say, we didn't give it a ton of experimentation/scrutiny when the raycast based occlusion would serve for all of our users for a couple dozen raycasts/frame accumulated.
That would probably be smart 😉 but no, currently it's just a "downgrade if not seen" while still using bbox distance. I don't remember if we tried using the raycast distance - @dbuck do you recall?
IIRC, We only used the raycast distances for the texture streaming system that was in use for the visible 3d-tiles to choose which resolution texture was needed.