Fractal Brownian motion (fBm)
Add layers of noise at rising frequency and falling strength, for detail at every scale like clouds, terrain and smoke.
How it works
One layer of noise has one size of feature: soft blobs all about as big as a grid cell. Natural shapes have detail at
many sizes at once. A coastline has bays, and the bays have coves, and the coves have rocks. Fractal Brownian motion,
fBm for short, builds that by adding several copies of a noise, each one smaller and fainter than the last. Each copy
is an octaveOne layer of noise in a fractal sum. Each octave usually has twice the frequency and half the amplitude of the one before, adding finer and fainter detail. Octave One layer of noise in a fractal sum. Each octave usually has twice the frequency and half the amplitude of the one before, adding finer and fainter detail.fbm(p) = Σ gainᵏ · noise(lacunarityᵏ · p)
The loop
float fbm(vec2 p) {
float sum = 0.0;
float amplitude = 0.5;
for (int k = 0; k < 5; k++) {
sum += amplitude * gradientNoise(p);
p = p * 2.0 + vec2(17.3, 9.1); // double the frequency, and shift
amplitude *= 0.5; // halve the strength
}
return sum;
}
The first octave sets the large shapes. The second has features half the size at half the strength, and so on. Five octaves span features from one unit down to a sixteenth of a unit. Because the amplitudes 0.5, 0.25, 0.125… add up to less than 1, the sum stays in the same range as one octave of the noise: about ±0.7 for the gradient noise used here, and usually closer to zero, since the octaves rarely all peak together.
The shift added to Matrix A grid of numbers (mat2, mat3, mat4) that maps one vector to another in a single multiplication. Rotation, scale and, with homogeneous coordinates, translation and projection are all matrices.p keeps the octaves from lining up. Without it every octave’s grid passes through the origin, and
the pattern gets visibly more regular near (0, 0). Rotating p a little between octaves (multiplying by a rotation
matrixA grid of numbers (mat2, mat3, mat4) that maps one vector to another in a single multiplication. Rotation, scale and, with homogeneous coordinates, translation and projection are all matrices.rotate(a) = [cos a −sin a; sin a cos a]
Lacunarity and gain
The two numbers in the loop have names. Lacunarity is how much the frequency grows per octave (2.0 here). Gain is how much the amplitude shrinks (0.5 here). Gain sets the roughness:
- 0.5 is the classic look, soft but detailed: clouds, hills.
- Around 0.6 to 0.7, the small octaves stay strong, and the result looks rough and gritty: rock, rust.
- Around 0.3, the fine octaves fade out quickly, and the result looks smooth and blurry.
Lacunarity slightly off 2.0 (1.9 or 2.1) is a common trick so octaves never align exactly. In the mathematical model
behind the name, the gain is pow(2.0, -H) for a lacunarity of 2, where H, the Hurst exponent, measures how rough
the signal is; terrain usually sits around H = 1, gain 0.5.
How many octaves
Each octave costs one more noise call, so cost grows linearly with the count. Octaves smaller than a pixel add nothing you can see and cause shimmering when the pattern moves, because the pixel samples fine detail it can’t show. A good rule is to stop when the features get smaller than about two pixels. At 1080 pixels across and a base feature of a quarter of the screen (270 pixels), that is about eight octaves; for a background that is mostly blurred, three or four are enough.
Ridges and turbulence
Two variants change what each octave contributes:
float n = gradientNoise(p);
float turbulence = abs(n); // sharp valleys where the noise crosses zero
float ridge = 1.0 - abs(n); // sharp crests instead
ridge *= ridge; // squaring makes the crests thinner
Summed over octaves, abs(n) (turbulence) looks like billowing smoke or fire, with creases where each octave crosses
zero. 1.0 - abs(n), squared, gives sharp ridges like mountain ranges or veins in marble. Ridged multifractals go one
step further and scale each octave by the one before, so detail grows on the ridges and fades in the valleys, the way
erosion works.
fBm is rarely the final image. It is a value to threshold into clouds, to map through a palette for fire, to use as a height for terrain, or to feed back into its own coordinates: that last one is domain warping.