Ripples appear everywhere in computer graphics.
Drop a stone into water and circles spread outward.
A magical spell creates an expanding energy wave.
A radar sends pulses across a screen.
Although these effects look complicated, they all begin with one simple idea.
Instead of measuring distance once, we repeatedly measure it while animation changes over time.
Imagine standing at the center of a pond.
Every point around you is a different distance away.
If that distance changes over time, the bright areas appear to move outward.
Instead of moving the pixels themselves, we animate the values produced by distance().
As before, everything starts by measuring the distance from the center.
vec2 center = vec2(0.5);
float d = distance(vUv, center);
This gives every pixel a number representing how far it is from the center.
Now we can animate that number.
Instead of displaying the distance directly, pass it into sin().
float ripple = sin(d * 25.0 - uTime * 4.0);
Let's understand each part.
d * 25.0
Creates many repeating waves across the radius.
The larger the number, the more ripples appear.
-uTime * 4.0
Moves those waves outward over time.
Together they create animated circular waves.
The sine wave ranges from -1.0 to 1.0.
Convert it into a colour value.
ripple = ripple * 0.5 + 0.5;
gl_FragColor = vec4(vec3(ripple), 1.0);
Instead of a single circle, you'll see bright and dark rings travelling away from the centre.
#ifdef GL_ES
precision mediump float;
#endif
uniform float uTime;
varying vec2 vUv;
void main(){
vec2 center = vec2(0.5);
float d = distance(vUv, center);
float ripple = sin(d * 25.0 - uTime * 4.0);
ripple = ripple * 0.5 + 0.5;
gl_FragColor = vec4(vec3(ripple), 1.0);
}
With only a few lines of code, we've created animated waves without using a single texture.
Multiply the distance by a different number.
d * 10.0
Creates only a few large rings.
d * 40.0
Creates many tightly packed rings.
This value controls the ripple frequency.
Adjust the time multiplier.
uTime * 2.0
Slow animation.
uTime * 8.0
Fast animation.
Small changes dramatically affect the movement.
Instead of using the sine wave directly, soften it.
float ripple = smoothstep(
0.4,
0.6,
sin(d * 20.0 - uTime * 4.0) * 0.5 + 0.5
);
The rings become softer and cleaner.
This technique is often used for water effects and magical energy.
Ripples become much more interesting with colour.
vec3 color = vec3(0.2, 0.7, 1.0) * ripple;
gl_FragColor = vec4(color, 1.0);
Try experimenting with different colour combinations.
Blue creates water.
Orange creates heat.
Purple creates magical energy.
Green creates a sci fi radar effect.
Let's reuse the glow from the previous lesson.
float glow = 1.0 - smoothstep(0.0, 0.15, d);
float finalColor = ripple + glow;
The center becomes brighter while the waves continue moving outward.
Simple combinations like this quickly produce impressive effects.
Ripple effects appear throughout games and visual effects.
Some common examples include
Many professional shaders begin with exactly the same technique.
Create fewer ripples.
d * 10.0
Create many ripples.
d * 35.0
Slow the animation.
uTime * 2.0
Speed up the animation.
uTime * 7.0
Add a glowing center.
1.0 - smoothstep(0.0, 0.15, d)
Combine several of these ideas together and observe how the effect changes.
Can you create these effects?
These exercises combine nearly every concept you've learned throughout this series.
Today we animated the output of distance() using sin() and uTime to create expanding ripples and shockwaves.
Instead of drawing static procedural shapes, we learned how to make them move naturally across the screen.
By combining techniques from previous tutorials, we created effects that are commonly found in games, user interfaces, and procedural art.