Advanced shaders · lesson 19 of 19 · Advanced · about 5 min
Water simulation 2: rain on the pond
You will build: Sum the ripples of eight drops at random places and times. Rings from different drops should cross and add up.
One drop is a wave packet. Rain is a lot of drops at different places and different moments, and the best part of water is what happens when the rings meet: they pass through each other and add up, making the bright and dark crossings you see on a real pond.
In the shader that is just a sum: the height is the sum of the heights of all drops. A for loop runs over 8 drops, and each needs its own random place and its own timing.
- Place:
hash21(float2(fi, 1.3))andhash21(float2(fi, 7.7))are two different random numbers per drop numberfi, mapped to the pond with- 0.5and a scale. - Timing: every drop repeats every 4 seconds, but with its own offset
hash21(float2(fi, 3.1)) * 4.0, so they fall out of step.
Everything else (the slope, the refraction, the sparkle) is exactly the same as the one-drop pond, because it only reads the height() function. That is the great thing about describing the surface as a function: the lighting does not care how complicated the surface is.
float h = 0.0;
for (int i = 0; i < 8; i++)
{
float fi = float(i);
float2 c = float2(hash21(float2(fi, 1.3)) - 0.5, hash21(float2(fi, 7.7)) - 0.5) * float2(1.5, 1.0);
float age = fmod(time + hash21(float2(fi, 3.1)) * 4.0, 4.0);
// ...the wave packet from last time, at distance length(p - c)...
h += wave * 0.016 * step(0.0, x + 0.12);
}The numbers you need
Everything the picture depends on is given, so the challenge is the code, not guessing.
- Drop i
fi = float(i), centre c = float2(hash21(float2(fi, 1.3)) - 0.5, hash21(float2(fi, 7.7)) - 0.5) * float2(1.5, 1.0)- Timing
age = fmod(time + hash21(float2(fi, 3.1)) * 4.0, 4.0)- Ring
r = length(p - c); x = r - age * 0.28; wave = sin(x * 55.0) * exp(-x * x * 140.0) * exp(-age * 0.75)- Sum
h += wave * 0.016 * step(0.0, x + 0.12), for 8 drops- Everything else
the shading from Water simulation 1
Try it in your own language
The lesson is written once and shown in every language. Pick yours: Unity (Built-in), Unity (URP), Unreal, Shadertoy / WebGL, OpenGL (LWJGL, raylib), three.js, GameMaker, LÖVE (Lua), Godot, Apple (iOS, macOS), WebGPU / Bevy.
Start coding