KROKI · 4FADE · 6t⁵−15t⁴+10t³WYNIK · zweryfikowany numerycznieSERIA · Perlin 2/4
Wykład: Perlin Noise — część 2 z 4

Algorytm krok po kroku

Cztery gradienty, cztery iloczyny skalarne, jedna funkcja wygładzająca, dwie interpolacje liniowe — i jedna, konkretna liczba. Ten rozdział rozpisuje to tak, żebyś mógł policzyć własny punkt na kartce i porównać z tym, co dostał komputer.

TL;DR
Pass: Wzór

Cztery kroki algorytmu

1) nᵢⱼ = gradientᵢⱼ · (P − węzełᵢⱼ), dla i,j ∈ {0,1}
2) u = fade(Px − ⌊Px⌋), v = fade(Py − ⌊Py⌋)
3) nx₀ = lerp(n₀₀, n₁₀, u), nx₁ = lerp(n₀₁, n₁₁, u)
4) wynik = lerp(nx₀, nx₁, v)
Pass: Przykład

Pełny przykład liczbowy

Dane wejściowe
Komórka siatki: narożniki (0,0), (1,0), (0,1), (1,1). Punkt zapytania: P = (0,3; 0,6).
Gradienty (jednostkowe, po 45°): g₀₀=(0,707; 0,707), g₁₀=(−0,707; 0,707), g₀₁=(0,707; −0,707), g₁₁=(−0,707; −0,707).
Krok 1 — wektory odległości i iloczyny skalarne
d₀₀ = P−(0,0) = (0,3; 0,6). n₀₀ = 0,707·0,3 + 0,707·0,6 = 0,6364
d₁₀ = P−(1,0) = (−0,7; 0,6). n₁₀ = −0,707·(−0,7) + 0,707·0,6 = 0,9192
d₀₁ = P−(0,1) = (0,3; −0,4). n₀₁ = 0,707·0,3 + (−0,707)·(−0,4) = 0,4950
d₁₁ = P−(1,1) = (−0,7; −0,4). n₁₁ = −0,707·(−0,7) + (−0,707)·(−0,4) = 0,7778
Krok 2 — funkcja fade (kwintyczna: 6t⁵−15t⁴+10t³)
fade(0,3) = 6·(0,3)⁵ − 15·(0,3)⁴ + 10·(0,3)³ = 0,01458 − 0,1215 + 0,27 = 0,1631
fade(0,6) = 6·(0,6)⁵ − 15·(0,6)⁴ + 10·(0,6)³ = 0,46656 − 1,944 + 2,16 = 0,6826
Krok 3 i 4 — interpolacja biliniowa
nx₀ = lerp(n₀₀, n₁₀, 0,1631) = 0,6364 + 0,1631·(0,9192−0,6364) = 0,6364+0,0461 = 0,6825
nx₁ = lerp(n₀₁, n₁₁, 0,1631) = 0,4950 + 0,1631·(0,7778−0,4950) = 0,4950+0,0461 = 0,5411
wynik = lerp(nx₀, nx₁, 0,6826) = 0,6825 + 0,6826·(0,5411−0,6825) = 0,6825−0,0965 = 0,5860
Finalna wartość szumu w P=(0,3; 0,6): ≈ 0,586
Sprawdzenie: w samym narożniku (np. P→(0,0)) wynik musi wyjść 0 — wektor odległości do tego narożnika ma długość zero, więc jego iloczyn skalarny zeruje się niezależnie od gradientu.
Worked.example.geometrysame numbers as above
(0,0) (1,0) (0,1) (1,1) P (0,3; 0,6) wynik ≈ 0,586
Ten sam narożny układ co w tabeli obliczeń wyżej — sprawdź swój rysunek na kartce z tym.
Pass: Fade

Czemu fade, nie liniowa interpolacja

Gdybyś interpolował liniowo (u=Px, v=Py, bez funkcji fade), noise miałby nieciągłą pochodną na granicach komórek — widoczne jako subtelne „załamania” przy oświetlaniu powierzchni bump-mappingiem. Perlin użył w 1985 wielomianu 3t²−2t³ (klasyczny smoothstep). „Improved Perlin Noise” z 2002 zamienił go na kwintyczny 6t⁵−15t⁴+10t³ — ten ma zerową drugą pochodną na końcach, nie tylko pierwszą, co jeszcze bardziej wygładza przejścia widoczne w oświetleniu.

Fade.function.comparisonlinear vs cubic vs quintic
liniowa kubiczna (1985) kwintyczna (2002)
Wszystkie trzy zaczynają w 0 i kończą w 1 — różnią się tym, jak płasko podchodzą do końców.
Z praktyki

To dlaczego implementacja szumu Perlina w każdym silniku ma dokładnie te trzy elementy: tablicę losowych gradientów (albo permutacji, jak w oryginalnym kodzie Perlina), funkcję fade i interpolację. Jeśli piszesz własny node „Noise” w shaderze proceduralnym, te cztery kroki z tego rozdziału to cała logika — resztę (3D, więcej oktaw) dokładają kolejne części tego wykładu.

Słowniczek
Funkcja fade
Wielomian wygładzający współrzędną przed interpolacją, np. 6t⁵−15t⁴+10t³.
Interpolacja biliniowa
Ważone uśrednienie 4 wartości narożnych (Rozdział 9).
lerp(a,b,t)
a + t·(b−a) — interpolacja liniowa między a i b.