This is something I played with two years ago - I posted it as a demo on gamedev.net forums (link) but later never had time to get back to it. My plan was to write a detailed article, but as it seems that will never happen and people frequently ask me for more info, I've decided to simply put it all up here with just a brief overview and full project source code.
The goal of this whole thing was to render realistic flowing water for big terrain areas on DirectX9 generation hardware.
The basic idea was to precalculate water flow over a static terrain represented by a heightfield and then use this data in the realtime application (game, simulation, etc) to do a simpler and cheaper localised wave simulation and rendering.
The process is thus split into two stages:
- Waterflow simulation (editor) stage
- Realtime 3D visualisation stage
The demo project contains both stages (modes), which can be toggled between using F5 key. See Readme.txt contained in the archive for more details.
Waterflow simulation (editor) stage
This is the 'editor' stage (it would go into a tools pipeline / editor in the case of a game engine): it takes a heightmap as input and, in my case, a list of springs which add water to the simulation. It outputs the state of the simulation - usually once it is stabilised. This simulation process can take tens of minutes or hours, based on the terrain size and other parameters. Once the user is happy with the way water is flowing across the terrain, it can save a 'snapshot' of the simulation state which exports it in a format used by the next, realtime renderer stage.
One good example of a similar algorithm that can be used for this, with more realistic simulation and terrain erosion, is described the "Interactive Terrain Modeling Using Hydraulic Erosion" (link). I am not going to explain my version as it is pretty similar, but feel free to dive into (pun not intended) source code and ask any questions.
Here is a short video of the algorithm in action:
Realtime 3D stage
The renderer stage will not further modify the base water flow, but will use simpler surface wave simulation and effects to provide the illusion of moving water. This is enough for most visualisation or game purposes and is fast and scalable.
A couple of effects are used to provide the appearance of moving water:
Simple localised surface wave simulation that affects normal map and displaces water vertices to a certain degree and can bounce from river banks or other objects. I think I based my algorithm on this article and with a little bit of tweaking made it work on the GPU. This simulation is then moved using the velocity map from the simulation stage to add the realistic water flow effect.
This simulation will only be performed on a rectangular block representing the area around the observer. When the observer moves, the simulation area is updated accordingly. Since this is a relatively fast simulation, newly added area will quickly stabilise into the regular wave pattern for the represented area, so few or no visible artifacts will be induced (unless observer moves too fast).
To allow for a distance based level of detail and add more wave frequencies, multiple simulation layers are run in a cascaded fashion, with each cascade covering the smaller one and its surroundings with the observer near the center.
Water perturbance is added to simulation cascades at real time based on the first stage (flow) simulation state, at areas of high velocity deltas. It will also be added for any other input such as wind or floating/splashing objects.
One additional channel in the simulation texture is used to store a quantity representing the amount of foam which is propagated in parallel with the simple wave simulation well using the velocity map from the flow simulation stage. This adds to the appearance of faster moving and/or splashing water areas.
The foam is rendered using foam tiled texture mapped using UVs that move along the velocity map direction. To prevent UV stretching (as the velocities are different on different areas), three overlapping layers (with slightly different UV scales and offsets) are continuously blended between in such way that the blending is always done between two textures while the third one is not visible and can have its UVs reset to prevent stretching. This is further augmented by a noise based blending mask to hide tiling details and hide blending artifacts.
Same (or very similar) technique for achieving flowing normal and colour maps was recently presented in SIGGRAPH 2010 Water Flow in Portal 2.
Finally, high frequency waves are added to areas of higher water velocity by simply adding animated normal 'noise' wave map on top using the same technique of moving UVs as for displaying the foam texture.
There you go! Of course, there are many things that can be improved and also two stages could be combined to add a completely simulated realtime flow effect. This would enable you to do something like the upcoming Ubisoft's 'From Dust' game, which looks amazing indeed!
The project with the full source code (DirectX9, C++, VisualStudio 2010) can be downloaded from here.
Just the binaries can be downloaded from here.
Datasets can be downloaded from:
hetch_half_dataset (lo-res - good for playing with simulator as it's quick)
hetch_full_dataset (hi-res - looks much better)
4k_x_2k_dataset (big one, pretty unfinished, I could've added more rivers)
If you wish to use your own heightmap, there's an explanation on how to set up a project in the readme file, and you'll need this to convert from a 16bit grayscale .tiff heightmap into .tbmp format used by RiverSim. Have fun and I'll be glad to answer any questions!