Physical Simulation of Water

creating a realistic simulation of water with refraction and caustics in Unity

Simulating water has been a nerdy hobby of mine for a long time now.

My first attempts were on the game Downstream Danger back in 1985. There were a few pre-defined animations for waterfalls and streams. In 1999 I got into DirectX and 3D games development on Windows. I started a game with the working title of Microcosm, but unfortunately I never got it completed. It had landscapes comprised of fractal mountains with simulated erosion. Between the mountains, I put lakes and seas with simulated water that would ripple up and down when random perturbations were applied.

Downstream Danger, Microcosm

More recently I was trying to get some nice renderings of 3D surfaces along the lines of a music video I enjoyed by Paul Thomas. I was using the raytracing software Cheetah3D, which has the ability to create Javascript components inside. My ability to achieve good results was limited not by the modelling or rendering capabilities of the software but the fact that you couldn’t actually see what you were doing in realtime - ray-tracing is incredibly slow.

It was around that time I discovered Unity. I had always thought that it was a toy environment for creating simple games by hooking actions up to sprites. That misconception was quickly dispelled. It is certainly simple to get started and hooking scripts to game objects is super easy. But it is a very well thought out abstraction that allows a great depth of customisation and programmability. Modern gaming hardware is pretty complex, so to get the level of abstraction it does whilst keeping usability and, as i was soon to find out, performance, is very impressive.

This tutorial is about my latest explorations of using Unity to physically simulate water. I’ve broken down the journey into three parts:

  1. Implementing the movement physics of the water surface with ripples and waves when forces are applied. The model is computed on the GPU using a compute shader and then used to render a surface mesh.
  2. Simulating refraction with a custom shader which uses physically correct reflections and refraction based upon the normals (direction surface is pointing) of the water surface.
  3. Create caustics that shine on objects under the water as though the sun was shining and refracting through the rippling water surface.

This tutorial makes extensive use of compute shaders. Compute shaders are highly parallel computations that our GPU will perform. Depending upon the graphics card you could be performing about 1000 computations in parallel. This makes them significantly faster than a CPU.

One of the final results of this work is video of Koi Pond:

A repo containing the full Unity project we are using in this tutorial is available on GitLab.

Continue with Part 2: Creating the Physics of Water Movement