Frustum culling strategy

Hello BJS team

Since a certain amount of time, I’m asking myself how do you handle frustum culling. I could extract some info scattered on different docs/forums, some seems up-to-date, some are maybe outdated. So I’m here to better understand what is done, what should I have to do myself, and in a general manner, what choice have been done.

Among all of my questions, here are what seem to be the more relevant
1 - Does the default culling strategy described here is still valid ? (ie: do you still check visibility by using bounding sphere by default ?) Optimizing Your Scene | Babylon.js Documentation
2 - Do you use some “smart” data structure (octree/quadtree/BVH) to check/update meshes visibility,or do you iterate on all meshes
3 - Same question for mesh instances
4 - Maybe close to question 3, do you iterate over all of the meshes at each frame, or do you use some tips depending on the previous frame to check/update just un subset of the meshes ?
5 - Same question for mesh instances
6 - In the case where you iterate over all meshes at each frame without particular optimization, and in the case I have some ideas to improve the culling strategy on my side for my particular scene, is there a way for me do to that ? If yes, I have some more questions
6.1 - Where do I should do this computing task ( onBeforeActiveMeshesEvaluationObservable, onBeforeRender, …)
6.2 - Should I just only need to call the method mesh.setEnabled(…) or mesh.isVisible, or is it more complex to be sure that all the BJS pipeline knows the mesh state (ie: physics, …)



cc @sebavan @Evgeni_Popov

Yes Optimizing Your Scene | Babylon.js Documentation is still up to date.

Not by default as it would be counter productive but you can enable it here Optimizing With Octrees | Babylon.js Documentation

we only check the main mesh by default with instances for perf purpose as webgl apps are mainly CPU bound so we prioritize savings there

Either all or nothing, or Octrees.

Same answer as 3

Culling is mostly done as the last mile before a draw occurs, not at dispatch time here. I would suggest to look into the sources on Github to see how you could fit your needs depending on the strategy you are trying to put in place.

@RaananW had ideas to improve this area as well :slight_smile:

1 Like

Regarding 6/, you could do your calculations before _evaluateActiveMeshes is called (this is where we loop over all the meshes and do the culling tests), e.g. in scene.onBeforeCameraRenderObservable then define scene.getActiveMeshCandidates with your own implementation, which returns only the visible meshes (the default implementation returns scene.meshes). For these meshes, you should set alwaysSelectAsActiveMesh=true or skipFrustumClipping=true to avoid testing them against the frustum and thus gain performance.

Note that overriding scene.getActiveMeshCandidates is what the Octree does.

1 Like