Regarding Water

(Here's an internal email that Ignacio sent today that may provide some flavor on what we're doing lately.)

From: Ignacio CastaƱo
Date: 24 August 2012

I just checked in a few changes to the water shader. Note that this is still work in progress, there are some artifacts and unfinished features.

From the art point of view, the main change is that there's now a water_color_map and a water_flow_map that you can use to change the behavior of the shader.

The RGB channels of the color map control the water extinction color and the alpha controls the opacity factor. The previous underwater shading model was simply wrong, the new one works nicely and is easy to tweak. Note that I assume the water color changes very smoothly, avoid sharp color changes!

The flow_map is intended to contain additional water attributes. Right now it's only used for the stillness, but I will certainly add more in the future.

You will also notice that the shoreline now also has a foam layer:

The way it's computed is by comparing the screenspace depth difference. This is not very correct, it looks OK from some angles, but it breaks badly when the underwater geometry has screen-space depth discontinuities:

If the foam is a desirable feature, I'm considering modifying the print_map command to render a foam map, or maybe this is something that can be painted manually and added to the water_flow_map. One of my concerns is that this map may not have enough resolution.

Just Cause 2 seems to use this method to render foam, but they apply a big screenspace distortion to hide the artifacts, I found it sickening when you stare at it closely...

The way the water is shaded has also changed somewhat. First, I now approximate the specular exponent based on the position of the camera with respect to the water and the water roughness. Somewhat like the LEAN paper does, but assuming the roughness of the water is the same for the whole texture. Depending on the value of the exponent I either sample the mirrored reflection map, a filtered environment map, or blend between the two. My goal was to be able to use the mirrored reflection map only on a small subset of the lake entities. The physically based approach does not allow us to cull many, so I'll probably have to introduce some hacks. BTW, I'm doing all these work not just an optimization, but also so that we can use the light probe reflection model in the river and lakes inside the island, where the mirrored reflection map is not available.

The main problem with the filtered environment map is that it does not take local reflections and occlusion from the environment into account. I have two ideas to work around this, one is to store an ambient occlusion map in the lightmaps, this may be a bit too smooth and will lack directional information. The other is to do screenspace raycasting of the depth buffer to decide whether the environment map is occluded or not.

This is somewhat like what Crysis 2 does. Insomniac also uses a similar approach with just a single sample:

I'm hoping we can get away with a crude approximation too. I did a quick test, where the maths are not exactly right, with only 4 samples and no smoothing, and it was starting to look promising:

This won't allow us to use the filtered environment maps closer to the camera, but if the screenspace raycasting works well, I'm thinking about using non-filtered environment maps in place of the mirrored reflection map, whenever those are not available.

Finally, I've also been playing with Valve's water flow model, I have the basic implementation working, but I haven't yet been able to reproduce the workaround for the pulsing and repetition artifacts that Alex proposes.


  1. I have to say I quite enjoy the environmental storytelling you’ve done with the fort (intentional or not).

  2. I think it’s neat how the programmers in graphics create publications and share techniques with eachother. Heavy graphics programming seems like quite the adventure, thanks for this look into your developments.

  3. Your screenshots have always been impressive. But these latest ones, with the new water, seem to have taken on some new quality (is it added realism? perhaps exiting some kind of uncanny valley?) that makes them look amazing!

  4. You should check this solution where most of Vlacho’s problems were solved.
    Cool to see how you guys have approached the water implementation. :)
    Will the player be able to interact with the water? If so, how are you guys going to handle the changes done to the flow? (I’m asking because I’ve been working exactly on that)

  5. I like how you guys put a lot of time and effort into making physical phenomena and properties realistic for the game. Most games care about getting the muscles of a character right or the shininess of a gun or facial expressions with motion capture. Never seen a game that cares to be realistic where it counts: In its architecture, geography, topography and properties of elements in the world.

    And the thing is that is not bullshit! The stuff is realistic in a way that this is how things work in the real world! And its actually stuff that matters in the game and you can use and interact with.

    Capcha: harsh comment

  6. I really like these graphic progression features. Especially on water. Water simulation keeps on being something that’s hard to calculate, we cannot even fully do it, it remains approximation.

    Will the water in the witness be interactive? Or are you just modeling the surface and tweaking other visual aspects to make it look good.

    Here’s another set of lecture slides on a method of programming real-time fluid behaviour that might be interesting.
    Seen in this video:

  7. Thanks for sharing your experiences. This resource on flow maps and the repitition issue may prove to be useful:

  8. I don’t know squat about programming, but this was fun to read! Thanks for letting us readers look into your developments. :)

  9. The wet stones are a nice detail. Makes it feel less like everything has a water repellent surface as in most games.

  10. Overall an interesting read, thanks for sharing.

    I’ve worked with a water system before where screen-space depth difference was used for a few things, including blending between “deep” and “shallow” colours, fading out real time shadows, and alpha fade. I was never happy with any of this, the dependency on view angle caused it to always break down in some conditions no matter how much you tweak it. For foam in shore regions with underlying terrain I’ve found height above terrain works well with a scrolling mask texture to break it up, but for a more general solution to cope with bits like the pier in your screenshot I reckon you’re best to store it in a texture like you say, if you can afford one with sufficient resolution.

  11. @David, @Mark: Thanks for sharing these resources. I was not aware of Kyle’s example and the tiling method looks very promising!

  12. I tried my hand at implementing the Valve technique. From my understanding, the repetition issue can be addressed just by using different normal maps for each of the two samples you take.

    As for the pulsing, it is a trade-off between reduced pulsing and increased distortion. You have to tweak the values to get something that looks decent. I put my findings here:

    I’m also going to try the tiling method. My concern (other than the performance considerations for 8 texture samples per pixel) is that it requires using the same flow vector over the entire tile. This means sharp turns in water direction won’t look as good, and you won’t be able to get swirls and whirlpool-type effects (which are very easy with the Valve method). On the other hand, it will probably look better in more “open” water.

Leave a Reply

Your email address will not be published.