Water depth visibility

Started by
10 comments, last by D3DXVECTOR3 15 years, 8 months ago
http://images.gamedev.net/gallery/57bb6e0484924ccfb511f3caf38b2154_water_shot1_big.jpg I'm struggling to achieve a similar effect as in the picture above. the visibility decreases as the the terrain goes deeper underwater. I need a good tutorial/example.
Advertisement
Vary the transparency of your water based on the depth difference between the water fragment and the screen Z-buffer entry at that screen-space position. You should be able to fetch that easily enough. Remember that depth is usually stored in logarithmic space, so you'll need to convert the number you read from the depth buffer into a linear-space figure.
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
I know the principle but not the exact implementation.

get depth value
do something with it
lerp reflection, refraction
In my engine Typhoon I simulate refractions with an additional render pass, by rendering the underwater scene to a texture from the current point of view. The shaders used for this pass take into account water attenuation.
Let's call C the color of an underwater point P, before attenuation. C is attenuated exponentially according to the optical length travelled underwater by a ray from the viewer V to P. In addition, light is scattered along the viewing path by underwater particles. A simplified formula for the final color is:

l = uw(|V-P|)
fex = exp(- a*l)
C' = fex*C + (1-fex)*D

C' is the final attenuated color, l is the underwater distance between the viewer and the point P, fex is the total light attenuation, a is a wavelength-dependent coefficient and D is a diffuse radiance term representing the in-scattered light.

In short, the further the point P is from the viewer, the more its color tends to D.
The formula is a simplification because it does not take into account visibility terms and the phase function and other subtle phenomena, but it should suffice for your purpose.
You can find a physical derivation for the parameters a and D in the reference paper Rendering Natural Waters

When you render water, you fetch the reflected and refracted scene from the respective textures. Then you have to blend them according to the Fresnel term, evaluated per pixel. This is described in many articles about water rendering (including my article in ShaderX 3 ;) )

Do not hesitate to write me back for further clarifications if needed.

Stefano Lanza




Doing depth transparency with the methods discussed can be superficially acceptable in some situations, but is really quite fake.

A more correct approximation will also use a depth buffer, but will instead reconstruct the x,y,z worldspace position of each below-water pixel (as described many times on this forum, usually in contex of deffered rendering).

Then depth is calculated by biasing the y distance of the pixel from the water surface.

This way opens the doors to a much more optically correct water surface, becasue water depth should affect transparency equally at *any* distance from the camera. This means the fresnel effect will have more and proper influence at arbitrary distances.

That is, if viewed directly overhead the fresnel effect will be minimize reflection, allowing more transparency in shallow water at any camera height (imagin looking down on the ocean from an airplane).

So to sum up, depth transparency should not be view-dependent..only fresnel is view-dependent. Obviously this isn't exactly correct but it works.
..............................................................................

A more specific implementation:

1) render a depth-pass to a floating-point texture before rendering the water

2) use a method to reconstruct the xyz world position

3) calcuate water depth as the distance form worldspace.y to waterlevel

4) bias or "normalize" this value to give you a greyscale gradient...it should be black at the water level and fading to white at the deepest parts (it doesnt matter which is black and which is white, can just reverse the lerp order)

5) Then use the depth value to create the "base" water color..that is: choose a water color based on a macro-texture or a set variable...lerp this color with the refraction texture.

6) Then lerp in the reflection texture using the fresnel value. Fresnel can be easily approximated by dotting the water surface normals with the view position.

Many tweaks will be needed, and I assume you know how to make and project the reflection and refraction textures, and do the waves and stuff..

hope this helps, realistic water is a big deal and and can make a scene look awesome. It took me many tries to get water i am mostly happy with..
Quote:Original post by Matt Aufderheide

A more specific implementation:

1) render a depth-pass to a floating-point texture before rendering the water

2) use a method to reconstruct the xyz world position

3) calcuate water depth as the distance form worldspace.y to waterlevel

4) bias or "normalize" this value to give you a greyscale gradient...it should be black at the water level and fading to white at the deepest parts (it doesnt matter which is black and which is white, can just reverse the lerp order)

5) Then use the depth value to create the "base" water color..that is: choose a water color based on a macro-texture or a set variable...lerp this color with the refraction texture.

6) Then lerp in the reflection texture using the fresnel value. Fresnel can be easily approximated by dotting the water surface normals with the view position.

Many tweaks will be needed, and I assume you know how to make and project the reflection and refraction textures, and do the waves and stuff..

hope this helps, realistic water is a big deal and and can make a scene look awesome. It took me many tries to get water i am mostly happy with..


You could alternatively do steps 1-4 in the refraction pass, storing the normalized lerp value in the alpha channel, and eliminate the extra pass. This is one way that I have done it.
Quote:Original post by glaeken
You could alternatively do steps 1-4 in the refraction pass, storing the normalized lerp value in the alpha channel, and eliminate the extra pass. This is one way that I have done it.


However, the way i do it, I dont do a refraction pass as a seperate pass..I just grab the back buffer (before rendering the water) to a texture, then project that using a bumpy offset in the final water pass. Since I use a deferred pipeline, there is no extra pass to eliminate that is not already neccessary.
I may be missing the point, but it seems by looking at the picture that volumetic fog could achive a similar effect.
Quote:So to sum up, depth transparency should not be view-dependent..only fresnel is view-dependent. Obviously this isn't exactly correct but it works.


Wrong. Water transparency depends on the optical length between the viewer and the observed point, so it IS view-dependent. This is obvious when the viewer is underwater, less above.

The correct approach to handle water attenuation for underwater objects, actually consists of two different steps:

1) Attenuate the incoming light (usually sun, sky and caustics) travelling from the water surface to the illuminated point; add a depth-dependent term to account for the in-scattered radiance too.

2) Attenuate the light reflected by the point in the direction of the viewer, as I described in my previous post.

These concepts apply to the lightning of underwater objects seen both from above and underwater.
Above, and especially for a game, you can cheat by considering only the depth underwater and ignoring the dependency on the viewer and the light attenuation, but it is not physically correct (although it might look acceptable).

You can use a refraction pass or a deferred pass, depending on your rendering pipeline. With a refraction pass you can have interesting effects like stretching the scene (to simulate the bending of viewing rays due to refraction) and a modified field of view. A deferred rendering on the other side has other advantages, in fact I'm gonna try it for my new water renderer.

Ciao

Stefano Lanza
I still cant get the job done, I need some examples. simple shader perhaps?

This topic is closed to new replies.

Advertisement