If you've been playing a hugely popular game involving pirate battles on the high seas, you've seen what a realistic depiction of the ocean can do to enhance immersion. As the author of Sundog Software's Triton Ocean SDK, I can break down the components of a good water simulation, so you'll know what to look for when designing your own system, or evaluating third-party water middleware to integrate into your engine.
3D or Not 3D?
Most game engines include some sort of water shader, and for many titles this is totally sufficient. These shaders typically create the illusion of 3D waves at a distance by shading a flat plane to reflect and refract incoming light using some pre-defined wave patterns. This approach is fast, simple, and looks good from a distance for low to moderate wave conditions. If your player will just be on land where docks or a coastline is visible in the background, or if you know your waves will always be small, this is a good approach.
However, if your game involves high seas or players that actually get into the water - either physically or on a vessel of some sort - you need something more. Not only is a true 3D representation of ocean waves needed visually, it's also needed to power the proper motion of floating ships, debris, etc. on the water surface.
Fast 3D Wave Generation
There are basically three approaches to creating 3D water waves. One is the sum-of-sines approach, where some number of waves are added together and used to displace a water mesh. But, computing individual waves like this and adding them all together each frame can be expensive and burn up GPU resources, so you end up being very limited with the number of waves you can simulate at once. Not having enough waves will result in a lack of detail on the water - you really need thousands of them before your brain says "yeah, that looks like a real ocean." This problem can be mitigated somewhat through the use of normal and displacement maps to add high-frequency detail over the lower-frequency procedural waves, but there's still only so far you can go.
A second approach is real-time computational fluid dynamics (CFD.) While this approach lets you simulate pretty much any interaction water can have with its environment, it is complex and generally limited to very small areas for real-time usage on today's hardware. It's something to keep an eye out for as hardware and research improves. Hybrid approaches that blend CFD for effects near the camera with other larger-scale techniques could prove interesting.
The best approach today is using a mathematical technique called an inverse Fast-Fourier Transform (FFT). Basically you pre-compute a 2D array of individual waves, defined by their amplitudes, directions, and wavelengths. Each frame, the FFT transform is applied to this array to convert it into animated 3D wave displacements. An array of 256x256 waves will result in 65,536 individual waves being simulated at once! FFT's may be accelerated using GPGPU technologies such as CUDA, OpenCL, or DirectX11 compute shaders. In our tests, waves created in this manner can cost less than one millisecond per frame - but this depends a lot on proper implementation.
Of course, it's not quite that simple. You also need to displace the final waves to make them look pointy and "choppy", and this involves further FFT computations. Another complication is that fast FFT transforms may not be available on every platform you plan to support, or different platforms may require different techniques. If you can assume DirectX11 graphics hardware, DX11 has very fast FFT functions built into it. But if you need to target DX9-level hardware, or platforms such as iOS, you may need to implement and support multiple approaches to generating these waves depending on the platform they are running on. However, we've still found FFT to be the best tradeoff between performance and visual quality available today, and we're rendering infinite oceans in 1-4 milliseconds with this technique.
A good place to start on FFT-powered waves from a mathematical perspective is Jerry Tessendorf's seminal paper on the topic. His techniques are more than sufficient for entertainment purposes, but serious games used for maritime training may need to implement more realistic wave patterns, such as those defined by the JONSWAP or Pierson-Moskowitz functions. It's also possible to simulate those functions with FFT's (we did it), but research on that is very hard to find.
Proper Water Lighting and Reflections
Lighting water can be complex. It involves reflections of the environment, refraction into the water, and specular highlights from the sun or moon - and properly combining these components involves a function called the Fresnel equation. There are plenty of resources online describing in detail how to write a water shader, but the devil's in the details. How do you hide tiling of your waves from high viewpoints? How do you prevent aliasing resulting from distant waves? How do you adjust the overall color of the water if you need, for example, a tropical look? Do you need shadows on the water, for example from clouds? How do you generate the textures needed for reflections at runtime? The latter in particular can be a performance hog if not thought through sufficiently. These are all questions to ask when designing or evaluating a water solution.
Interactions with Coastlines
Unless your game takes place only on open ocean, you'll also need to think about how the water interacts with coastlines. Your terrain will need to slope below sea level in order to allow the water to smoothly blend with it near the shore.
Generally this blending requires a height map of the coastal area or some sort of depth information, so the water shaders will know how much alpha blending to apply to the water surface as a function of the water depth. This depth can also be used to affect the shapes of the waves as they approach the coastline. While it's fairly easy to dampen the waves inside a bay or marina, or build up the amplitude of a few waves and the intensity of foam as they approach the shore, real breaking waves at the shore that curl over themselves is a very tough problem and generally isn't implemented. If you need to portray a surfer inside the "green room", that is a tall order!
Spray and Foam
A smooth shaded water surface won't look very realistic - real ocean water has foam and spray that are critical for realism. The FFT process described above can be done in such a way to tell you where the peaks of the waves are, and this information can be used to spawn spray particle systems at the peaks of rough waves. Doing this in a performant manner, however, can be challenging. Typically the wave information resides on the GPU, and particle systems are usually set up initially on the CPU. There is a GPU to CPU transfer of information that must either be highly optimized, or eliminated entirely through clever means.
A good foam texture makes a big difference in the final result, but its animation is equally important. The water system should automatically generate foam from behind the peaks of rough waves, and have that foam dissipate rather quickly over time.
The topic of proper physics on ships and other floating objects is a whole other paper, but suffice to say it's not easy to get right. If you need floating ships that react to different wave conditions, at a minimum you need to ensure your 3D wave system gives you the ability to query the height of the water surface at a given point. The usual approach is to sample the height of the water at a few control points along the hull of your ship, and use this information to compute the buoyant force at various sections of the hull.
As with spray particles, intersection tests also typically require synchronizing wave information from the GPU to the CPU, and the intersection tests themselves can also be expensive if not highly optimized. Measuring the performance of a water system when conducting large numbers of intersection queries is a must, if many ships or pieces of debris will be floating on it.
Ship Wakes, Rotor Wash, Impacts
Speaking of ships - they won't look right without proper ship wake effects. Ships leave behind a "Kelvin wake" which is the V-shaped wave that follows behind it, they generate spray at the bow of the ship, they leave a trail of propeller backwash, and they generate foam and spray surrounding the hull of the ship. Much of this can be accomplished with the clever use of particle effects, but things like 3D wave displacement of the Kelvin wake and application of a propeller backwash texture to the dynamic ocean surface must be features of the water engine itself. Another thing to check is how ship wakes look on ships moving on a curved path - doing this right is particularly challenging.
Other effects you may need are helicopter rotor wash on the water, or impact waves kicked up by things like cannonballs hitting the water. I've managed to implement these effects in real time, but not all water systems can do this.
There are really three distinct kinds of waves, and so far we've only talked about wind waves. These waves travel more or less in the direction of the wind, and their height depends on the wind speed and how far that wind has been travelling over the water.
A complete water simulation will also include swell waves. These are waves generated by distant storms, which may have entirely different directions and amplitudes from the local wind waves. They can also make a big difference in the look and feel of high seas when applied judiciously. It's possible to hack the input of FFT waves to include specific swells, or they may be added in to the final water mesh within the vertex shaders.
A third wave type is capillary waves - very small waves that just add an extra level of visual detail to the final result. Typically this can be sufficiently faked with a good normal map on the final shading, but I've also seen people solve multiple FFT's at different resolutions for this purpose.
One last thing to consider is applying decal textures on the water surface. Perhaps you want a bed of kelp floating on the water, an oil slick, fine-grained debris, or even (gasp) blood starting to mix into the water. Since the water surface is always moving dynamically, traditional decal texture effects won't work on it. Instead, decal techniques from deferred renderers using 3D volumes are required. Your deferred engine may already have this capability, but if not, it's another feature to look for in your water solution.
Build or Buy?
I didn't write this blog post with the intent to scare you off, but depending on your requirements, real-time 3D water really is a big project. Recent AAA work has shown that it can be a great investment that differentiates your game from the rest, but don't underestimate the effort involved. I've been working on my 3D water system pretty much full time for two years, and I'm still coming up with ways to make it better.
There are commercial solutions (such as my Triton Ocean SDK for Unity, OpenGL, and DirectX-based engines) and open-source solutions for specific engines (such as Hydrax for Ogre.) They very well may meet your needs out of the box, and if not, they include source code so you can build upon them and make them your own. Investing your precious developer time recreating the wheel is never a good idea; instead, build on the work of others, and focus your efforts on adding the new features that will differentiate your title.