This is a physically-based simulation of water flows across a 3-D landscape. The water surface is modelled as a 2-D heightfield using the "shallow water equations". The calculations are done on the GPU and the simulation runs in real time for reasonable grid sizes.
If the video doesn't work, you can download a WMV file (49 M) or view a static screenshot.
Click here to download the demo zip file (3.2 M)
You may also download the source code (3.4M).
Note that the demo requires DirectX 10.0 level graphics hardware.
The basic idea is behind the shallow water equations is that we take a vertical average of the equations of fluid dynamics (the Navier-Stokes equations). This leads to a new set of equations which describe the fluid depth and velocity as functions of x and y (the horizontal directions) only.
The advantage of doing this is that the computational cost of solving the equations is reduced (compared to a full 3-D simulation). The flip side is that the results are less realistic, since a 2-D "height field" approach (which is essentially what this is) fundamentally cannot represent certain features, such as breaking waves, complex splash/spray patterns, etc.
The equations themselves are well known and can be found in Acheson (1990) or on Wikipedia for example.
We use the method of Kurganov and Petrova (2007) to solve the equations. The calculation is done on the GPU in three passes (per simulation timestep) using custom pixel shaders (implemented in HLSL). It runs in real time for reasonable mesh sizes.
The rendering has deliberately been kept fairly basic at the moment. The water and terrain are rendered as simple height field meshes. The water shader takes into account attenuation (deeper water appears darker), reflection (but only the sky and clouds are reflected, not the terrain), refraction (in an approximate way), and the Fresnel effect.
In my view this project has been a mixed success. On the plus side, the general "behaviour" of the water seems fairly realistic: it flows across the landscape, collects in pools and lakes, and so on, in a believable way. On the minus side, I think the quality of the graphics could be improved – particularly the texturing/shading of the water at the pixel level.
If you look at photographs of water (or indeed water rendering in modern games) you will typically see lots of high frequency details, including small turbulent wave features, glints of light from specular reflections, etc. Physically speaking, these come about because of the shape of the water surface. A real water surface (especially in fast-flowing regions) is not completely "smooth," but has lots of short-wavelength perturbations resulting from the turbulent motion. Unfortunately the shallow water model cannot reproduce these perturbations, for two reasons:
One possible solution might be to run the shallow water simulation at a relatively low resolution, but then use pixel shaders and hand-painted textures to "fill in" the missing high-frequency details. In other words, we would be simulating the general shape of the water surface using the shallow water model, but with the understanding that there are many "sub grid scale" details that the model does not capture. Instead of trying to simulate these physically, we would simply layer them in as a hand-crafted texture/shader over the top of the shallow water simulation.
I believe this would make an interesting area for future work. However, I haven't worked through the details, and there might be some implementation problems that need to be solved (I imagine there might be issues with getting the high resolution textures to "match up" with the simulation results, for example, especially in regions of converging or diverging flow).
Performance of the simulation could be improved. Currently I am using the Kurganov-Petrova method, which is highly accurate and stable, but also rather computationally intensive. It might be worth investigating other approaches to trade off speed vs. accuracy. (There are a great many methods for solving PDEs so this might involve quite a lot of work!)
Another performance improvement would be to only run the simulation in cells where the water depth is positive (or an adjacent cell has positive water depth); currently the simulation runs on all grid cells, whether they contain water or not.
Low level code optimization is also a possibility (the HLSL code I am using for the simulation is basically the first attempt at writing the code and not optimized at all).
The rendering code is also rather primitive at the moment: it just blasts out a huge triangle grid to render the heightfield, with no attempts at LOD or adaptive tesselation or anything like that. Therefore there may be some speed improvements to be gained here.
There are some rendering artifacts; most notably, a "diamond" pattern sometimes appears in areas where there is a sudden change in water depth. These should be investigated and fixed if possible.
We could investigate imposing maximum speed and/or maximum depth limits on the simulation (high speeds and/or depths are a problem because they raise the CFL number and require shorter time steps to be taken).
The friction model used in the simulation is completely ad hoc and unrealistic. A better friction model should probably be developed.
The boundary conditions might be improved (in particular, the "inflow" condition is a big hack at the moment).
Finally, as discussed above, it might be interesting to set up a low-resolution shallow water simulation and then add in custom texture maps and pixel shaders to "fill in" high resolution details.
D. J. Acheson, "Elementary Fluid Dynamics", Oxford University Press, 1990.
A. Kurganov and G. Petrova, "A Second-Order Well-Balanced Positivity Preserving Central-Upwind Scheme for the Saint-Venant System", Commun. Math. Sci., Vol. 5, No. 1, pp. 133-160, 2007. Available online at http://129.81.170.14/~kurganov/Kurganov-Petrova_CMS.pdf.
The source for the "grass" texture used in the demo is the Terrain Texture Pack created by Virtually Infinite Systems.
The skybox texture was created by Terragen (classic edition; non-commercial licence).
The Guichan open source library was used to create the sliders and other GUI elements visible in the demo.
The demo is copyright (C) Stephen Thompson, 2012.
The Shallow Water Demo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
The Demo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
The text of the GPL can be viewed here: http://www.gnu.org/copyleft/gpl.html, or alternatively a copy can be found within the demo zip files (see "Downloads" above).