04 / JUST ADD LIGHTA SMALL STUDY OF SOMETHING VAST
WHAT TO NOTICE
The shape is the same as the mesh. Fine ripples scatter the glints, while depth changes the colour. Pause the waves, then move the sun.
colour = transmitted light + reflected sky + sun
THE IDEA / SIMPLE RULES, COMPLEX BEAUTY
You don’t draw every drop.
In a game, convincing water can begin as a flat surface. A function gives every point a height, time moves the pattern, and light makes the result feel wet. Let’s build that illusion, one small decision at a time.
This is an art-directed wave model: a useful starting point for a pond or ocean surface. It does not simulate flowing liquid, splashes or breaking waves.
01 / THE RHYTHM
Start with a sine.
A sine wave smoothly repeats between −1 and 1. Multiply it by A to decide how high it rises. Stretch it across space with a wavelength, λ, then subtract time to make its crests travel.
h(x, t) = A sin(2πx / λ − ωt)
A · amplitude
Height above the resting surface. Crest to trough is 2A.
λ · wavelength
Distance between neighbouring crests.
ω · angular frequency
How quickly the phase changes, in radians per second.
The travelling shape is not a stream of water moving forward. Watch the dot: in this height-field model, one fixed position simply moves up and down as crests pass.
02 / THE VARIATION
Let waves meet.
One wave looks a little too tidy. Add smaller waves with different spacings, directions and speeds. Where crests meet, they reinforce each other; where a crest meets a trough, they can cancel. A complicated shape emerges from a few simple rules.
H(x, z, t) = h₁ + h₂ + h₃ + h₄
Our recipe uses four waves. Each follows the same sine rule, but samples distance along its own direction: dxx + dzz, where the two direction components form a unit vector. In the demo, the smaller amplitudes are 45%, 22% and 10% of the main wave.
03 / THE SHAPE
Give the line a surface.
Imagine a flat sheet made of tiny triangles. For each vertex, read its horizontal coordinates, calculate H, and use that value as its vertical position. The vertices stay fixed horizontally while their heights change.
position = (x, H(x, z, t), z)
The mesh view reveals the construction. Long waves define the silhouette. Short waves add detail, but they need enough vertices to remain smooth. This study uses a 128 × 128 grid of cells; the mesh view displays every fourth grid line to keep the structure readable.
04 / THE ILLUSION
Light makes it water.
Blue alone gives us a blue sheet. The crucial clue is the surface normal: the direction each tiny patch faces. We calculate it from the wave’s slopes, so the light responds to the same maths that makes the shape.
n = normalise(−∂H/∂x, 1, −∂H/∂z)
We add fine ripples to the lighting normals, then combine a reflected sky, a tight sun highlight and light transmitted through the water. The four large waves still define the shape. A Fresnel approximation increases reflection at grazing viewing angles. The highlight travels when you turn the sun, even if the waves are paused.
Refraction offsets our view of a procedural sandy bottom with small pebbles. Depth absorbs warm colours faster than blue, while animated bright patterns suggest caustics: light focused by the moving surface. Open Water finish to compare clarity, ripples and depth. Clarity changes absorption along the refracted light path, including through the sides. The visible sides are an illustrative cutaway, and the caustics are a procedural approximation. Shore foam, breaking waves and object interactions would be further layers in a fuller renderer.
YOUR TURN / TWO MOODS, ONE EQUATION
Make a pond. Then change the weather.
Start with low amplitude and wide spacing for a quiet pond. Raise the amplitude and bring the crests closer for a busier surface. Pause both versions and look at how the slopes change.
Then set wave height to zero. The surface becomes flat, but it can still reflect the sky. Which part of “water” came from shape, and which part came from light?
This is the core height calculation. Our renderer also calculates its derivatives for lighting. The demo uses arbitrary scene units; the motion slider scales time.
function wave(x, z, time, A, wavelength, omega, direction) {
const distance = direction.x * x + direction.z * z;
const phase = 2 * Math.PI * distance / wavelength - omega * time;
return A * Math.sin(phase);
}
// Add waves with different amplitudes, wavelengths and directions.
const height = waves.reduce((sum, w) =>
sum + wave(x, z, time, w.A, w.wavelength, w.omega, w.direction), 0);
// Move the vertex to (x, height, z).
In physical deep-water waves, angular frequency and wavelength are linked by ω² = gk, where k = 2π/λ. Here, frequencies are chosen for a readable visual study; the sliders are creative controls.