ShaderMaterial and Logarithmic Depth Buffer

Hi there,

I want to use a logarithmic depth buffer for one of my projects and i went to the official documentation Logarithmic Depth Buffer | Babylon.js Documentation

The thing is I can enable it on StandardMaterial but how do I use it on a ShaderMaterial ? I’m using a depth renderer (DepthRenderer | Babylon.js Documentation) maybe there is something I can do with it to convert the linear depth buffer to a logarithmic one ?

I don’t really know where to start, if someone knows I would appreciate greatly :)

Thanks in advance !

So for log to work you need to add this to your fragment:
Babylon.js/logDepthFragment.fx at master · BabylonJS/Babylon.js (github.com)

This to your vertex shader:
Babylon.js/logDepthVertex.fx at master · BabylonJS/Babylon.js (github.com)

And then declare these uniforms and varyings:
Babylon.js/logDepthDeclaration.fx at master · BabylonJS/Babylon.js (github.com)

then on before render of your material:

BABYLON.MaterialHelper.BindLogDepth(defines, effect, scene);
2 Likes

Thank you so much for your help !
I have added the fragment and vertex code yet I’m unsure I understand “before render” for the BindLogDepth.
Should I write this ?

let material = new ShaderMaterial(a lot of cool arguments such as samplers uniforms and defines);
MaterialHelper.BindLogDepth(material.getEffect()!.defines, material.getEffect()!, scene);

When I do that it tells me getEffect() returns null for some reason, am I doing this wrong ?
Also how would it work for post-processes, because I probably can’t use the MaterialHelper in that case ?

I used this in my ShaderMaterial declaration

defines: ["#define LOGARITHMICDEPTH"]

and I figured I could bind it after compilation with :

material.onCompiled = (effect: Effect) => {
    MaterialHelper.BindLogDepth(effect.defines, effect, scene);
};

Yet I don’t get the desired result, I will try to replicate it in the playground if this is the correct syntax.

Yes please :slight_smile:

I have reproduced it ! Please take a look at https://playground.babylonjs.com/#JJC8AJ#9
So basically I have 2 spheres the size of planets (they are the same size) and applying the log depth buffer is messing up occlusion : the farthest sphere is rendered on top of the closest one :confused:
At least something is happening so I guess I am not far from the solution :slight_smile:

Here we are:
Logarithmic depth buffer issue | Babylon.js Playground (babylonjs.com)

The main issue was not using the onBindObservable as the log depth data need to be bound per frame

1 Like

Thank you ! It works ! :heart: But how do I transpose this to post-processes ? I can’t use the MaterialHelper and the depth is acquired thanks to a depth renderer using this :

let depthRenderer = new DepthRenderer(scene);
scene.renderTargetsEnabled = true;
scene.customRenderTargets.push(depthRenderer.getDepthMap());

myPostProcess.setTexture("depthSampler", scene.customRenderTargets[0]);

Is there a way to implement the log depth buffer in this context too ?

That would required far more work as so far the DepthRenderer shader does not store log data

It would require to update it to take it in account and store the value.

I see, that’s not going to stop me though :slight_smile:
Can I make it work with a super-class of DepthRenderer ? Or should I create my own DepthRenderer from scratch ?

You can totally replace the DepthRenderer shader code to store the log version of the depth

Even better we can think about you doing a PR to add the log support on the depthrenderer !

That sounds like a great idea ! I will make a PR when it’s working, for now I will mark this topic as solved thank you :slight_smile:

Starting from 5.0 you can use your own material to render a mesh with the depth renderer.

So, simply call depthRenderer.setMaterialForRendering(yourMesh, yourMesh.material) and you should be good.

You could also optimize things by providing a specific material instead of the true one of the mesh, where only the logarithmic depth is enabled, because the depth renderer is only interested in generating a depth value - the color value computed by the fragment shader is not used.