Rendering issue: Materials with needDepthPrePass + freezeActiveMeshes render black

Hey there!

We are currently trying to optimize our project and encountered an issue: If materials with depth prepass are used in combination with scene.freezeActiveMeshes() they appear black.

Here is a playground showing the issue: https://www.babylonjs-playground.com/#1PLV5Z#28

Help would be very appreciated :slight_smile:

Freezing meshes is not really compatible with the needDepthPrePass property…

That’s because this property render the same mesh two times in a row by changing some engine states in-between. When the mesh is frozen, the resetting of the states is not performed because it is done in a method which is not called anymore when the mesh is frozen. So the mesh is still rendered two times but with the “depth pre pass” engine state each time…

You can try to call the method that handles the state changes yourself after you have frozen the meshes:

https://www.babylonjs-playground.com/#1PLV5Z#31

Or you can unfreeze the meshes that are using needDepthPrePass = true.

1 Like

Thanks for the answer Evgeni_Popov!

Your solution definitely works. I do have one more question though: You mentioned that it is possible to unfreeze the meshes with needDepthPrePass. How can we do it? There is a hidden method _unFreeze that does not work however.

What we are trying to accomplish is quite simple: Fully remove the performance impact of mesh selection which can be quite heavy and unnecessary in scenes where meshes are always visible. We are also aware that with needDepthPrepass the meshes need to be rendered twice but we believe that the freezing logic is not specific enough. We thought that freezeActiveMeshes would avoid the cost of mesh selection (frustum check, LOD selection etc). Maybe a second function would be nice which removes the mesh selection process but still handles the needDepthPrePass state correctly.

You’re right, the _freeze() / _unfreeze() methods are not meant to be called by the end user, but it’s still working for your use case (they are public). However, freezeActiveMeshes is doing its work in a deferred callback (namely in scene.executeWhenReady) so you should do the same thing else _unFreeze will be called too early:

https://www.babylonjs-playground.com/#1PLV5Z#32

Frustum check can be avoided by setting mesh.alwaysSelectAsActiveMesh = true on each mesh or simply by setting scene.skipFrustumClipping = true at the scene level.

LOD selection does literally no time if the mesh has no LOD, there is a check at the start of the function that returns early.

Things are quite interleaved and so just making freeze + needsDepthPrePass work is not really possible.

What you can do that also work in your use case is to override the _evaluateActiveMeshes function with en empty function:

https://www.babylonjs-playground.com/#1PLV5Z#33

1 Like

Thank you! We have quite a few options now. From our performance tests so far explicitly calling isReadyForSubMesh yields the best results in our case :slight_smile: