GLSL Procedural Noise — Perlin, Worley, FBm and Domain Warping

Noise is the fundamental building block of procedural graphics: terrain height maps, galaxy textures, turbulent fluids, and organic surfaces all start with the same handful of noise functions. This tip walks through each type in GLSL with copy-paste code and live simulation demos.

Noise Function Family Tree

Value Noise

Random values at integer lattice points, interpolated. Fast. Low quality. Good for prototyping.

Gradient (Perlin)

Random gradient vectors at lattice points, dot-producted and interpolated. Smooth, no banding.

Simplex Noise

Perlin on a simplex lattice. Fewer directional artifacts, O(n²) in n dimensions vs O(2ⁿ).

Worley (Cell) Noise

Distance to the nearest random seed point. Produces stone-tile, cell, bubble patterns.

FBm

Fractional Brownian Motion — sums of noise at increasing frequencies (octaves). Fractal detail.

Domain Warping

Feed a noise-displaced position into another noise call. Turbulence, smoke, fire.

The Hash Function — Foundation of Everything

All the noise functions above need a pseudo-random value at every integer lattice point. The hash function converts an integer coordinate into a float in [0,1). The fastest reliable option in GLSL is a single-line sine/fract trick, though for production quality a 32-bit integer Wang hash is better:

GLSL — hash functions
// Quick and dirty (sin-based, some GPUs have precision issues)
float hash11(float n) { return fract(sin(n) * 43758.5453); }
vec2  hash21(float n) { return fract(sin(vec2(n,n+1.0)) * vec2(43758.5453,22578.1459)); }

// Better: integer Wang hash (requires GLSL 3.30 / ES 3.00 with uint)
uint wangHash(uint seed) {
  seed = (seed ^ 61u) ^ (seed >> 16u);
  seed *= 9u;
  seed ^= seed >> 4u;
  seed *= 0x27d4eb2du;
  seed ^= seed >> 15u;
  return seed;
}
float hashFloat(uint seed) { return float(wangHash(seed)) / 4294967296.0; }

Perlin Noise in GLSL

Classic gradient noise. Sample at position p, find the surrounding four integer corners, assign a random gradient to each, compute the dot product with the offset vector, and interpolate with a smooth cubic or quintic fade function.

GLSL — 2D Perlin Noise
// Gradient directions (8 cardinal + diagonal, classic Perlin)
vec2 grad(vec2 p) {
  float a = hash11(dot(p, vec2(127.1, 311.7))) * 6.2832;
  return vec2(cos(a), sin(a));
}

float perlin(vec2 p) {
  vec2 i = floor(p);
  vec2 f = fract(p);
  vec2 u = f*f*f*(f*(f*6.0-15.0)+10.0); // quintic interpolation

  float a = dot(grad(i + vec2(0,0)), f - vec2(0,0));
  float b = dot(grad(i + vec2(1,0)), f - vec2(1,0));
  float c = dot(grad(i + vec2(0,1)), f - vec2(0,1));
  float d = dot(grad(i + vec2(1,1)), f - vec2(1,1));

  return mix(mix(a,b,u.x), mix(c,d,u.x), u.y);
}

Fractional Brownian Motion (FBm)

FBm is simply the sum of noise at multiple octaves — each octave doubles the frequency (lacunarity ≈ 2) and halves the amplitude (gain ≈ 0.5). This creates the self-similar fractal appearance of clouds, terrain, and turbulent fluids.

GLSL — FBm
float fbm(vec2 p, int octaves, float lacunarity, float gain) {
  float value = 0.0;
  float amplitude = 0.5;
  for (int i = 0; i < octaves; i++) {
    value += amplitude * perlin(p);
    p         *= lacunarity;   // frequency up
    amplitude *= gain;         // amplitude down
  }
  return value;
}

Domain Warping

Instead of evaluating fbm(pos), evaluate fbm(pos + fbm(pos + offset1) + fbm(pos + offset2)). Each layer displaces the sampling position of the next, creating turbulent, organic structures that are impossible with simple FBm.

Domain warping = free non-linearity. Iq (Inigo Quilez) first documented this technique in 2002. Two levels of warp produce "turbulence"; three levels approach real-looking fire and smoke. Each extra warp level costs 1 additional FBm evaluation but delivers dramatically more visual complexity.

Live Noise-Based Simulations

These simulations use noise functions at their core — explore them to see the techniques above in action:

Algorithms Used

Value Noise Gradient (Perlin) Noise Simplex Noise Worley / Cell Noise Fractional Brownian Motion Domain Warping Wang Hash IFS (Iterated Function Systems) Quintic Interpolation Voronoi Partitioning