Depth Buffer in material shader

I seem to have stumbled onto this issue as well, playing around with the demo project from a water tutorial:
https://playcanvas.com/project/533435/overview/toon-water--tuts-tutorial

The project uses the depth map to generate a foam line around objects in the water, but that doesn’t work in the editor with the current version of PlayCanvas, only in the published project.
I tried forking the project, adding Will’s RenderDepth script to the scene, but to no avail. Any ideas what else is missing to get the foam line to work again? It appears that accessing the depth map has become a real hazzle – do we have any updated documentation that explains how this is supposed to work?

The GitHub issue posted above, although still open, provides a resolution for the WebGL1 bug.

Here is a sample project implementing that fix:

https://playcanvas.com/editor/scene/813310

I may have misunderstood something here, but the sample project you’re linking to simply renders a white screen when I press play. I tried in both Chrome and Firefox, both updated to the latest version on a PC running Windows 10.

Yes, because the depth map isn’t linearized and is “unpacked” differently in WebGL2. So don’t test it visually but inside your shader operations.

Here are the methods you should be using on each case:

Hmm… the water tutorial project already appears to include these methods in the fragment shader.
https://playcanvas.com/editor/code/657274?tabs=26543414

This is the project I forked, adding the renderDepth script. I made sure to move it to the top of the script loading order and I tried attaching it to the camera, but nothing appears to make any difference. The foam lines are still not rendering.
https://playcanvas.com/editor/scene/853908

Could you post a link of what is the expected output of this project?

Sure, the tutorial project has a compiled version:

From what I see the shaders of that project have been built taking into account only WebGL1 deployment (check how the depth map is unpacked in the DepthVisualize.js script).

To use this project in WebGL2 you will have to update that part definitely. The depth fix definitely works, change the initialize method in the DepthVisualize.js script to this (and also make sure you add the WebGL1 fix from the Github issue to your project):

DepthVisualize.prototype.initialize = function() {
    //this.entity.camera.camera.requestDepthMap();
    var depthLayer = this.app.scene.layers.getLayerById(pc.LAYERID_DEPTH);
    depthLayer.incrementCounter();    
    
    this.antiCacheCount = 0; // To prevent the engine from caching our shader so we can live-update it 
    
    this.SetupDepthViz();
};

And launch the project in WebGL1 and you will see the foam rendering:

Yes, you’re right. I added the depth fix to water.js and the foam is rendering in WebGL1.

Also, I turned off the depthVisualize script that’s used on the camera. In the tutorial, that script just illustrates what the depth render looks like, it’s not used for the actual water.

So, the water fragment shader does include the methods you posted above. I thought they were supposed to fix the depth render under WebGL2 since they have GL2 defines?
Shouldn’t this work?

#ifdef GL2
    float linearizeDepth(float z) {
        z = z * 2.0 - 1.0;
        return 1.0 / (camera_params.z * z + camera_params.w);
    }
#else
    #ifndef UNPACKFLOAT
    #define UNPACKFLOAT
    float unpackFloat(vec4 rgbaDepth) {
        const vec4 bitShift = vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0);
        return dot(rgbaDepth, bitShift);
    }
    #endif
#endif

// Retrieves rendered linear camera depth by UV
float getLinearScreenDepth(vec2 uv) {
    #ifdef GL2
        return linearizeDepth(texture2D(uDepthMap, uv).r) * camera_params.y;
    #else
        return unpackFloat(texture2D(uDepthMap, uv)) * camera_params.y;
    #endif
}

From what I see when this project compiles its shaders on runtime the GL2 flag isn’t respected. Even though it runs on a WebGL2 context the shaders always fallback on the else branch of the GL2 defines.

I am not sure why, don’t see anything wrong on the project settings with a first glance, nor something I’ve encountered before. Try submitting an issue about this on the engine repo in case it is a bug to be investigated.

As a temporary workaround you could write two versions of the shader, one for WebGL1 and one for WebGL2 and load the correct file based on this property:

this.app.graphicsDevice.webgl2
1 Like

Ah, thank you very much – that workaround did the trick for now.
I’ll submit a bug report. Seems very strange that the defines aren’t working as intended.

1 Like

I’m back at work now and back on a Mac. Unfortunately, the Mac reports that it’s running Web GL 2, but the shader doesn’t work :frowning: I tested on both Firefox and Chrome. The shader does work if I force it to run Web GL 1.

I guess Macs have general issues with Web GL 2, it’s not just a Safari thing…

Hi @Excess, sadly I don’t have access to a Mac right now to help you debug that.

Maybe try a number of other WebGL2 samples like After the Flood to check if it is indeed a generic WebGL2 issue on the Mac.

Hi @Excess, I just stumbled on this thread while trying to figure out how get the depth buffer and realizing my toon water tutorial doesn’t work with the latest PlayCanvas editor anymore. It sounds like you and Leonidas have found a number of issues here! If you have a forked version that’s updated with some of these fixes for the depth map I’d appreciate a link here so I can update the source version.

The engine-only source code is in this repo and I welcome any PRs there too: https://github.com/OmarShehata/tutsplus-toon-water.

It sounds like perhaps this is thread is a good reference on the latest correct way of obtaining the depth buffer: Accessing Depth Buffer of a Render Target?

1 Like

@ray probably knows most about it.

We have an engine example that shows how to use the depth buffer with both WebGL1 and 2 in the bokeh DOF post process: https://playcanvas.github.io/#graphics/post-effects.html - however, the bokeh DOF post process script only works in WebGL2 in a PlayCanvas project - I am looking into why it isn’t working for WebGL1.

Requires a small engine change to fix WebGL1 depth access in editor projects: https://github.com/playcanvas/engine/pull/2657 - the editor project I used for testing is here: https://playcanvas.com/project/751022/overview/bokeh-dof

2 Likes

Hey,
found out how to access the camera depth and implement it. Mainly used code from this example.

Made a simple project with only the depth-feature here.

It uses a bit of shader chunk code, but it should be fairly simple to re-write it to only use custom shaders (basically just copy over the code from the “pc.shaderChunks.screenDepthPS” script).

2 Likes