Proceduralny szum GLSL — Perlin, Worley, FBm i domain warping

Szum jest fundamentalnym budulcem grafiki proceduralnej: mapy wysokości terenu, tekstury galaktyk, turbulentne płyny i organiczne powierzchnie — wszystkie zaczynają się od tej samej garstki funkcji szumu. Ta wskazówka przechodzi przez każdy typ w GLSL z gotowym do skopiowania kodem i żywymi demonstracjami symulacji.

Drzewo genealogiczne funkcji szumu

Szum wartości

Losowe wartości w punktach siatki całkowitoliczbowej, interpolowane. Szybki. Niska jakość. Dobry do prototypowania.

Gradientowy (Perlin)

Losowe wektory gradientu w punktach siatki, mnożone skalarnie i interpolowane. Gładki, bez pasmowania.

Szum Simplex

Perlin na siatce sympleksowej. Mniej artefaktów kierunkowych, O(n²) w n wymiarach zamiast O(2ⁿ).

Szum Worleya (komórkowy)

Odległość do najbliższego losowego punktu zalążkowego. Tworzy wzory kamienne, komórkowe, bąbelkowe.

FBm

Fraktalny ruch Browna — sumy szumu przy rosnących częstotliwościach (oktawach). Fraktalny detal.

Domain warping

Podaj przesuniętą przez szum pozycję do kolejnego wywołania szumu. Turbulencja, dym, ogień.

Funkcja haszująca — podstawa wszystkiego

Wszystkie powyższe funkcje szumu potrzebują pseudolosowej wartości w każdym punkcie siatki całkowitoliczbowej. Funkcja haszująca przekształca współrzędną całkowitą we float z zakresu [0,1). Najszybszą niezawodną opcją w GLSL jest jednolinijkowa sztuczka sinus/fract, choć dla jakości produkcyjnej lepszy jest 32-bitowy hash Wanga:

GLSL — funkcje haszujące
// Szybkie i brudne (oparte na sin, niektóre GPU mają problemy z precyzją)
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)); }

// Lepsze: całkowitoliczbowy hash Wanga (wymaga GLSL 3.30 / ES 3.00 z 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; }

Szum Perlina w GLSL

Klasyczny szum gradientowy. Próbkuj w pozycji p, znajdź otaczające cztery rogi siatki, przypisz każdemu losowy gradient, oblicz iloczyn skalarny z wektorem przesunięcia i interpoluj gładką funkcją wygaszania — sześcienną lub kwintyczną.

GLSL — szum Perlina 2D
// Kierunki gradientu (8 kardynalnych + przekątne, klasyczny 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); // interpolacja kwintyczna

  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);
}

Fraktalny ruch Browna (FBm)

FBm to po prostu suma szumu na wielu oktawach — każda oktawa podwaja częstotliwość (lacunarity ≈ 2) i zmniejsza o połowę amplitudę (gain ≈ 0,5). To tworzy samo-podobny fraktalny wygląd chmur, terenu i turbulentnych płynów.

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;   // częstotliwość w górę
    amplitude *= gain;         // amplituda w dół
  }
  return value;
}

Domain warping

Zamiast obliczać fbm(pos), oblicz fbm(pos + fbm(pos + offset1) + fbm(pos + offset2)). Każda warstwa przesuwa pozycję próbkowania kolejnej, tworząc turbulentne, organiczne struktury niemożliwe do uzyskania przy prostym FBm.

Domain warping = darmowa nieliniowość. Iq (Inigo Quilez) po raz pierwszy udokumentował tę technikę w 2002 roku. Dwa poziomy warpu dają „turbulencję”; trzy poziomy zbliżają się do realistycznego ognia i dymu. Każdy dodatkowy poziom warpu kosztuje 1 dodatkową ewaluację FBm, ale zapewnia dramatycznie większą złożoność wizualną.

Żywe symulacje oparte na szumie

Te symulacje wykorzystują funkcje szumu jako swój rdzeń — poznaj je, by zobaczyć powyższe techniki w akcji:

Wykorzystane algorytmy

Szum wartości Szum gradientowy (Perlin) Szum Simplex Szum Worleya / komórkowy Fraktalny ruch Browna Domain warping Hash Wanga IFS (iterowane systemy funkcyjne) Interpolacja kwintyczna Podział Voronoia