January 13, 2014

Waterfalls and sleeping water

Hi there!

I will just write a quick article on this week's work: creating the appearance of waterfalls and water/lakes which are not the main sea.

The final look of waterfalls.

Indeed, I want a world with various (floating) islands and some waterfalls. Maybe you noticed it, but there is already water in the video game. I previously worked on the main sea of the world, and it wasn't that easy to set up a look that I found OK. I finally chose to have a purely reflective water. The big problem is that displaying the main sea is quite computationally expensive.

If I want to add other water planes (for example a lake on an island) or waterfalls, I can't use the exact same approach because it will seriously slow down the game. Plus, for a simple plane, computing the reflection is "quite" straight-forward, but for complex shapes (a waterfall), the computations are more difficult and the graphical pipeline of the GPU is not well suited for such a task. So I have to use a work around if I don't want to spend days developing an incredibly complex material that nobody will notice anyway.

I finally choose a combination of various classical techniques used in video game/real-time applications...


I - Environment(cube) map


An environment map is some kind of "spherical" texture (actually it's computed from the faces of a cube) that is applied on a mesh according to its normals. The idea is to "fake" the reflection of the environment on the object.

The environment map fakes a perfect reflection of the environment. This works well with a sphere, but it's less convincing with other mesh primitives.

Technically, it is possible to compute such a normal map in real-time to obtain a "true" reflection of the environment. However, as usual, this is quite GPU-heavy (you have to make 6 renders of the scene to create the real-time reflection texture). Furthermore, even with real-time computed reflections, the mapping itselft is still a fake one, which won't fool the careful viewer's eye.

Thus, I choose to use a pre-computed environment map: I simply use the cube map of the sky (see this post for more details).


II - Moving normal maps to create waves


Then, to break the perfect flatness of the water, I add 2 normal maps that moves at 2 different speeds. It creates a nice effect of moving waves. By the way, it's the same trick that is used to create the waves on the main sea material.

 The environment map with normal maps to simulate waves


III - Moving foam texture


This one is a simple classical moving texture added on top of the moving waves. To keep consistency with the rendering of the main sea, I use pure white for the foam, and I play with the alpha channel to modulate the visual impact.

The white foam above the water.


IV - Distortion of the foam texture


Because I want the foam not to be straight on this moving water, I add distortion to it by altering the texture coordinates with a noise texture (actually, this is the wave normal map with a different scale and speed).

Foam with distortion!


V - Day time aware material


The final step is to make the material reacting to the day time. Indeed, the sky/environment is evolving (there is a day/night cycle in the game) and I can't have a night reflection in full day, this totally breaks the visual integrity of the scene. So I need to carefully blend the day and night environment map of the sky according to the virtual time of the game.

Day reflection

 Noon reflection


VI - Tweaking and particles


The final difficulty is adjusting all the material parameters of this "fake" water, to match most closely the main sea water. Because the algorithms behind the rendering of these 2 water styles are different, it's strictly impossible, but I have to minimize the visual gap.

The main sea water material with real reflections.

The lake water material with fake reflections.

As you can see on the above screenshots, for lake and other "sleeping" water planes, the differences with the main sea water can be obvious according to the camera viewing direction. But for the moment, I can't do better.

Maybe, later, I'll modify the main water rendering shader to make it structurally closer to the fake water one, so that it can be easier to have a similar look (without losing real reflection on the main water of course). Or maybe I'll find anoter way to have real-time reflections on lakes too without hurting too much the GPU (I already tried... but failed... for now).

For waterfalls however, this fake water is quite OK, I guess because all waterfalls have the same material. By the way, I must add particles to create the splashing waters.

A waterfall with splashing water particles.

So, that's all for today! I hope this detailed water material post was interesting for you...

And, I didn't talk about it in this post, but I made a loooot of bug fixes thanks to all of you guys who tested the last demo. Thanks for your amazing feedback! I plan to release a new demo with lots of major fixes at the end of the week, so that new testers can find new bugs ;)

See you! Peace!