I set out to create a water rendering system for Gradient, my DirectX 11 renderer project. As someone new to graphics programming, diving into water rendering has been both exciting and challenging. This blog post shares my experience building my first water rendering system, from understanding the basics at first to refining and achieving visually appealing results.
One of the most important components of water rendering is deforming a mesh to simulate waves convincingly. A water surface is typically modeled as a height field, where the height of the mesh at any given point is a periodic function of position and time. Acerola has an excellent video on the subject here. I decided to follow one of his references, Effective Water Simulation from Physical Models by Mark Finch. These techniques would be considered a bit dated by today’s standards, but I wanted to start from the basics.
In GPU Gems, Finch starts with modelling waves as simple sums of sine waves and eventually goes on to discuss Gerstner waves. The problem with Gerstner waves, however, is that a poor choice of parameters can cause loops to form above the wave crests. To keep things simple, I chose to use sine waves where the sine function is offset to be non-negative and is raised to an exponent. This exponent can be used to control the sharpness of the peaks of the waves. In the interest of brevity, I’ll simply list the formulae here. A more complete treatment can be found in GPU Gems.