How to access depth buffer in shader

I am currently working on a simple water shader. To create a foam effect I would like to read the depth from the depth buffer in the frag shader.

Is there any way to access this information?

if you need only the depth of the current fragment, in the fragment shader of your material you can use

gl_FragCoord.z

Unfortunately I need the depth of the depth buffer…

Well that would be the depth of the depth buffer for the specific fragment. If you need to access the entire depth buffer then you need to use filters. There is already a filter implementing water, maybe you can use it as starting point

Accessing the Depth Buffer from a fragment shader


float z = gl_FragCoord.z / gl_FragCoord.w;


I studied that shader, it does not do the stuff I need. No foam, no refragmentation.

i get that, you can implement your own filter


#version 330 core
out vec4 FragColor;

float near = 0.1; 
float far  = 100.0; 
  
float LinearizeDepth(float depth) 
{
    float z = depth * 2.0 - 1.0; // back to NDC 
    return (2.0 * near * far) / (far + near - z * (far - near));	
}

void main()
{             
    float depth = LinearizeDepth(gl_FragCoord.z) / far; // divide by far for demonstration
    FragColor = vec4(vec3(depth), 1.0);
}

Depth Testing

1 Like

This does not take the depth from the depth buffer. I do not need the depth of the current fragment.

Please read my previous comments: I need to know the depth of the underlying terrain. This can be acchieved by forcing the terrain to be rendered first and then reading the ZBuffer.

gl_FragCoord is just the coord of the current fragment. It does not tell me anything about the rest of the world. For refraction and foam I need to know about the rest of the world.

If it were me, I’d take the existing full screen post process water, cut and paste it into my own code, and gut it to do what I want.

As far as I can see, it does not access the depth buffer or doe the stuff I need in any other way. But I’ll check the code if I can find it.

Post process water absolutely accesses the depth buffer. That’s how it knows how to do foam at the edges of water and how much refraction to do, etc…

In the filter post processor, depth is pretty easy to get in the shader… I think you just set a flag and make sure you have the right uniform.

Ah… I 've only seen a single not too impressive example of the water post proces that did not have foam.

Where can I view the shader code?

Found it… that is to say, SimpleWater did give me some info on how to get the depthbuffer:

What it seems to be doing is to send the depthbuffer of the Framebuffer to the watershader as a texture.

What is not clear to me yet, is how to get this depthbuffer. SimpleWater java code creates a offscreen buffer and makes it share an empty texture that is also given to the SimpleWater material.

I tried to get the depthbuffer through the viewport like this:
viewPort.getOutputFrameBuffer().getDepthTarget().getTexture()

This gives me a nullPointer problem at getDepthTarget, meaning it did not get a FrameBuffer before that.

So, does anyone know how to get the actual depthbuffer used by the renderer?

SimpleWater != post process water.

Are you sure it was post process water? Post process water definitely has foam. The usual example the island in an endless ocean and it has waves, foam at the coast line, etc…

To be honest, I didn’t even know that SimpleWater used a depth buffer as that one always seemed like just a plane with reflection.

I did not find PostProcess Water code on Github. But SimpleWater has foam too - it is mentioned in both the java-class as in the shader - and the code was taking me in the right direction I think.

But what remains is how do I get the renderbuffer of the current viewport?

Whenever I have to mess with the depth buffer, I just make a post process filter because all of the ugly bits are handled for me.

mmm… this is strange: WaterFilter has a Uniform that is called heightTexture and the WaterFilter-class has a method to set it. But the test code seems to never set this texture.

However, it made me think of something that might work - I first thought it was doing that: I could make a heightmap of the terrain and use that. Since my water is on a sphere, I need to find how to map the position on the water sphere to the texture. UV coords?

Last time I’m saying this: it’s magic. The filter post processor sets it for you. It’s magic taken care of for you. That’s why it’s a good place to start because it does the hard things for you.

You don’t need to do the hard things because the filter post processor does it for you. Then you can just use the depth texture because it’s set for you and you don’t have to worry about it because the filter post processor takes care of it.

I think somehow understand how to get depth map to use in fragment shader


Texture2D depthTexture;
FrameBuffer renderFrameBuffer;
int width = getContext().getSettings().getWidth();
int height = getContext().getSettings().getHeight();
Camera reflectionCam = new Camera(width, height);
reflectionCam.setFrustumPerspective(getCamera().getFov(), getCamera().getAspect(), 0.01f, 1000);
reflectionCam.setLocation(new Vector3f(0, 0, -6.f));
ViewPort reflectionView = renderManager.createPreView("reflectionView", getCamera());
reflectionView.setEnabled(true);
reflectionView.setClearFlags(true, true, true);
reflectionView.attachScene(getRootNode());
renderFrameBuffer = new FrameBuffer(width, height, 1);
reflectionView.setOutputFrameBuffer(renderFrameBuffer);
depthTexture = new Texture2D(width, height, Format.Depth);
renderedTexture = new Texture2D(width, height, Format.RGBA8);
renderFrameBuffer.setDepthTarget(FrameBufferTarget.newTarget(depthTexture));
renderFrameBuffer.addColorTarget(FrameBufferTarget.newTarget(renderedTexture));
reflectionView.setOutputFrameBuffer(renderFrameBuffer);

Then set the depthTexture in the material
If there are any comment please reply