This topic is 556 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi everyone,

I have a planar water shader which I've been using for quite a while. It follows the standard format of interpolating between refraction/reflection maps to create the overall colour and using normal maps to perturb the texture coordinates and create specular reflection. It produces decent results but I'd like to add some depth-based effects such as weighting towards a 'murky' colour for pixels in the refraction map which have a larger volume of water between them and the camera. Something a bit like this:

https://i.ytimg.com/vi/UkskiSza4p0/maxresdefault.jpg

I tried the following approach to determine the water depth for each pixel of the refraction map:

- As I'm rendering terrain under the water, the alpha channel is not going to be used (i.e. I won't have translucent terrain). So, in the terrain pixel shader, I used the alpha channel to return the screen-space depth, i.e:

// ...pixel shader code to calculate the terrain colour here...
return float4(finalTerrainColour.rgb, psInput.ScreenPos.z/psInput.ScreenPos.w);

- Then in the water shader, when I sample my refraction map containing the terrain rendered below the water, I find the difference between the alpha channel (where the terrain depth is stored) and the depth of the current pixel on the water plane, i.e:

// ...pixel shader code to sample refraction map colour...
refractionMapColour = lerp(refractionMapColour, murkyWaterColour, saturate(depthDropoffScale*(refractionMapColour.a - psInput.ScreenPos.z/psInput.ScreenPos.w)));

This didn't seem to work and produced some strange results, for example when the camera was just above the water plane, it would show the 'murky' colour only, even though the terrain was quite a way below the water (and hence refractionMapColour.a should have been much larger than the depth of the pixel on the water plane).

So, can anyone spot an obvious problem with the way I tried above, and are there any better ways of going about such depth-based effects?

Thanks for the help :)

Edited by george7378

##### Share on other sites

The thing that stands out to me is your use of the z-coordinate.  NDC coordinates range from -1 to +1, so you are probably getting negative values creeping into your lerp function.  You'll also notice that there is a range of 2 (-1 to +1), so you might also be getting some values greater than 1.

##### Share on other sites

The thing that stands out to me is your use of the z-coordinate. NDC coordinates range from -1 to +1, so you are probably getting negative values creeping into your lerp function. You'll also notice that there is a range of 2 (-1 to +1), so you might also be getting some values greater than 1.

Thanks for the reply. I think for XNA the projection gives a z-coordinate from 0 to 1, with 0 being the near plane (?):

https://msdn.microsoft.com/en-us/library/bb195672.aspx

##### Share on other sites

when the camera was just above the water plane, it would show the 'murky' colour only, even though the terrain was quite a way below the water (and hence refractionMapColour.a should have been much larger than the depth of the pixel on the water plane).

If as you say: refractionMapColour.a is much larger than the depth of the water plane.

So your shader does (largeValue - smallValue). Which could still yield a large value.

You then multiply that large value by depthDropoffScale - If this value is >1 then you'll be making the resultant value even larger!

Next you clamp it at max 1.0 using saturate(). So let's say the result was clamped at 1.0

That means your lerp call is effectively this: lerp(refractionMapColour, murkyWaterColour, 1.0)

Which will contribute 100% weight to murkyWaterColour and the result will be exactly equal to that.

Edited by dmatter

##### Share on other sites

I think the issue is that the depth doesn't have enough resolution when stored in the alpha channel. The effect seems to be working when the camera is right next to the water plane, but since my far clip plane is pretty distant, it causes problems when the camera is not close to the water. Not sure of the best way to continue with this - perhaps I should calculate the 'fog factor' in the terrain shader based on actual world positions, but then I'd have to add a ray-plane intersection to calculate the distance to the water.

EDIT: I was already doing clipping when drawing the refraction map so I just decided to use the distance below the clip plane and pass that through in the alpha channel (after dividing by a scale factor to get it in a reasonable range). Produces a decent result:

##### Share on other sites

You're using Z/W. You should be using either linear depth, or depthDropoffScale should be proportionate (getting smaller with distance) to account for the non-linear distribution of your depth values.

I.e. use W/FarDist.

1. 1
2. 2
Rutin
19
3. 3
4. 4
khawk
14
5. 5
A4L
13

• 13
• 26
• 10
• 11
• 44
• ### Forum Statistics

• Total Topics
633743
• Total Posts
3013643
×