Noise: A Field Guide

· Computer graphics

Randomness is easy. Useful randomness is not.

Ask a computer for a random number per pixel and you get television static: every sample independent of its neighbours, no structure at any scale, nothing that looks like anything. Almost nothing in the physical world looks like that. Clouds, marble, rust, coastlines, wood grain, wind — they're all irregular, but their irregularity is correlated. Nearby parts resemble each other. Far-apart parts don't.

A noise function is a way of manufacturing that kind of randomness: a function of position that is smooth up close, unpredictable at distance, and identical every time you ask for the same point. That last property is the one that makes it useful rather than merely random. Noise isn't a bag of random numbers you draw from, it's a landscape you sample — you can walk away from a point and come back to find it unchanged, which is why the same function can drive a texture, a terrain, an animation or a force field.

This is part one of three, and it's the field guide: what the common functions look like, and what each one is for. Every field below is drawn live in the browser as ink on paper: 0 is the bare page, 1 is full ink. (In a dark colour scheme that inverts along with everything else — the fields are drawn from the same two colour tokens as this text, so 1 is always the ink and 0 is always the page.)

White noise

The baseline, and the thing to compare everything else against. One independent random value per sample.

There's no scale control here because there's no scale — no feature size to change. Zoom in and it's the same static; zoom out and it's the same static. This is what randomness without correlation looks like, and it's why "just use random()" doesn't get you clouds.

It isn't useless: film grain, dithering and anti-aliasing jitter all want exactly this. But it's a finishing texture, not a structure.

Value noise

The cheapest way to buy correlation. Put a random value at every point of an integer grid, then interpolate smoothly between them.

Scale

Drag the scale slider and you're changing the grid spacing — the feature size in pixels. Now there is a scale, which is the whole point: the function is smooth below it and unpredictable above it.

Look closely, though, and the lattice shows. Blobs line up in rows and columns, because every extreme value sits exactly on a grid point. That axis-aligned bias is value noise's tell, and it's what Perlin fixed.

Perlin noise

Ken Perlin's 1985 trick, which earned an Academy Award and became the default meaning of the word "noise": don't store a random value at each lattice point, store a random direction.

Scale

To sample a point, you take the dot product of each surrounding gradient with the offset from its lattice point, then blend the four results with a smooth curve. Because every lattice point contributes zero at its own location, the extremes fall between grid points instead of on them, and the grid stops being visible as a grid.

The remaining artefact is subtler: the lattice is still square, so features are very slightly happier along the axes and the diagonals than anywhere else. You mostly stop noticing after the next function.

Simplex noise

Perlin's own follow-up, from 2001. Same gradient idea, different grid: triangles instead of squares.

Scale

Two things fall out of that. First, a triangular grid has no preferred axis, so the directional bias goes away — simplex noise looks more isotropic, more like a natural material and less like something on a grid. Second, a 2D sample needs three corners instead of four, and in higher dimensions the gap widens fast: 4 corners instead of 8 in 3D, 5 instead of 16 in 4D. Since animated noise is usually just noise with time as an extra dimension, that scaling is the practical reason simplex won.

Worley noise

Steven Worley's 1996 cellular noise, which works on a completely different principle: scatter feature points through space, and let the value at any position be the distance to the nearest one.

Cell size

The feature points are blank — distance zero — and the ink collects along the seams where one cell gives way to the next. Nothing else in this guide gives you edges: every gradient-based function above is smooth everywhere, and Worley has creases built in. Stone, scales, cracked mud, honeycomb, foam, cell walls, the boundaries between things — this is the one to reach for. Inverted, the same field is a field of pebbles.

fBm — fractional Brownian motion

None of the above look like landscape yet. Real terrain has hills with boulders on them, and bumps on the boulders: the same kind of roughness repeating at every scale. You get it by summing the same noise function several times over, each layer at double the frequency and half the amplitude of the one before.

Octaves Scale

Pull the octaves slider down to 1 and you're back to plain Perlin. Every step up adds a finer layer of detail without changing the big shapes — which is exactly the self-similarity that makes mountains look like mountains and clouds look like clouds.

The layers are called octaves by direct analogy with music, since each one doubles the frequency. The frequency multiplier is lacunarity and the amplitude multiplier is gain; 2 and 0.5 are the defaults that give you fractional Brownian motion proper. Almost every piece of procedural terrain you've seen is fBm with something else layered on top.

Picking one

For a first pass, the short version: reach for simplex when you want smooth organic variation and don't want to think about it, Worley when you want edges and cells, fBm over either when you want natural-looking detail at every scale, and white noise when you want grain. Value and Perlin noise are mostly here for the lineage, though Perlin remains a perfectly good workhorse and is easier to write from memory than simplex.

What none of these do is look like anything specific. A field of fBm isn't marble or a coastline or a wind map; it's raw material. The interesting work is in what you do next — warping one noise field with another, cutting it at a threshold, using it to push things around rather than to colour them in.

That's part two. Part three gets to why all of this normally runs in a shader rather than in a loop over pixels like the demos above, and what changes when it does.