Water shader - water depth calculations - why does it need water height?

Starting to go into the interesting field of water shaders, I’m trying to understand in detail, how the translucent water shader by Epic works, which is found on marketplace and described by Alan Willard in

Here, I’m focusing on the water depth calculation. It is a more theoretical thread, but I’m not just interested in throwing ready made stuff into my level. Instead I want to understand how the nodes work and this is useful for doing own stuff later on as well, expecially all that depth based stuff.

This is the part of the Shader doing the depth - quite confusing to me at the first glance, especially that Divide node, even along with Alan’s presentation.

I made the following picture of how I would go for that - to understand the math behind the nodes arrangement

X is the depth perpendicular to the water surface down to the ground - that’s the water depth we actually want to calculate.

For the CP and AWP positions, only the Z-value is of interest to get the camera height above water CH = CP(z) - AWP(z)

So this means:

(X + CH) / SD = CH / PD

which results in:

X = (CP - AWP) * (SD/PD - 1)

There’s no extra height information involved. The shader for this looks as follows:

BTW: Not sure, which is better: first subtract vectors and then mask or first mask and then subtract scalars only?

I do not get the point, for what purpose the original shader needs the Water Height Parameter. It even requires to use a blueprint to get that parameter set to the water surface z value in the construction script to make the shader work.

EDIT: I even wondered, why passing in water height as parameter to the original shader - actually, shouldn’t this be already contained in the Absolute World Position nodes Z-component, because the water is just a horizontal plane? I tested this, and it also works perfect. So no need to pass in water height even when using the original shader logic.

I did a comparison material just to visualize the depth by color changes and switch between both versions, just feeding in results into a switch:


and there’s no visual difference, except that the orignal needs that change to the height parameter whenever moving the plane up/down. Don’t bother all that stuff in my test scene…

First image shows original version:

The modfied version

The modified version, just changed Z for the water plane - no need for height parameter changes

I believe, my version is simpler and less error prone, but I suspect, that I might be completely wrong and might have missed some important point here.

Someone with any thoughts on that?

1 Like

hey herb64, have you find anything new on this depth stuff? Cause I’m also recently working on this, confused by the same problem.
BTW, thanks for sharing your result, love it!

There’s starting the water height parameter from a baseline Z position, not always Z=0. Is yours or the original shader capable of it?

Hi herb64, thanks for the clean graph. I’m working on this too. Do you figure this out already? BTW, I think in your graph, the X should be just under the AWP like the original tutorial states. Isn’t it?

This diagram is wrong. I tried going through this tutorial as well and had a myriad of complaints about it, this being one of them. There is also a group of nodes that just cancel each other out, and this entire section of the graph could just be replaced with the built in WorldPositionBehindTranslucency function which does the same thing and if you want an example of how to implement it the right way, you should look at that function instead.

Love Ben Cloward, but this was a really bad tutorial.

Its not that its bad, it’s that it’s dated.
the worldpositionbehindtranslucency wasn’t avaliable at the time.

As a general rule of thumb this is a bad tutorial. Brucks stuff on the subject is a lot cleaner and more up to date.

The new single layer water shader makes most of it useless.

It’s best to mask before the subtract theoretically since subtracting a vector is more expensive than subtracting a float.

The issues and problems with water rendering are far from shading the depth. They all come in when you introduce proximity to other meshes and non landscape components and usually break down based on camera angle anyway when you introduce surface foam with distance to nearest surface of similar.

Simply not true. The diagram being referenced is not the one in the original post, it’s from Ben Clowards youtube tutorial which was posted earlier this year when WorldPositionBehindTranslucency was very much in the engine. Even if it weren’t, that is no excuse for the fact that the diagram does not describe what the math in the material is actually doing, or the useless nodes in the graph.

I was referring to Allan’s water shader that’s available on the marketplace for free…

@Arkiras Thanks for the node info. For anyone who wants to understand the WorldPositionBehindTranslucency node, it uses (SceneDepth divid PixelDepth) to get the ratio of whole depth v.s. above water depth, then use this ratio to multiply the distance between the camera and current rendered pixel(Absolute World Position) to get the “whole distance” as scene depth. Finally, (whole distance + camera position) equals the distance starts from the camera position to the end(Ex: underwater ground ).

That’s my understanding, and the result works great.

1 Like

How is the scene depth divided by pixel depth a ratio of whole depth to above water depth? I’m not saying it’s not. I’m trying to understand how it works. Does the scene depth correspond to whole depth, and the pixel depth correspond to above water depth?

Yes, scene depth is from the camera to underwater ground(go through transparency object) and pixel depth is from the camera to water surface(not go through transparency object)

ok, thanks

I was also confused by the original algorithm and implemented my own just like @herb64, and until saw your reply now I understand why the original algorithm works. Big thanks!

Thank you for starting the discussion!@yhs 's reply can be helpful and by the way it not uses the water height parameter :wink: