Szum Perlina

20.10.2025
Szum Perlina Teoria

Prerekwizyty:

W poprzednich artykułach wspominałem czym są szumy i jak są wykorzystywane do tworzenia proceduralnych światów, a dzisiaj przyjrzymy się dokładniej konkretnemu algorytmowi z “rodziny szumów”, a mianowicie – “Szumie Perlina” (Perlin Noise). Tak więc bierz meliskę, włącz sobie swój ulubiony szum (zakładam, że masz taki!) na https://noises.online/ i lecimy!

Na wstępie warto zaznaczyć, że praktycznie każdy dostępny silnik do tworzenia gier posiada wbudowaną bibliotekę do generowania szumów lub oferuje możliwość pobrania odpowiedniego pluginu, przykładowo:

  • Unity posiada klasę Mathf.PerlinNoise oraz niezliczoną liczbę wtyczek dostępnych w Asset Store,
  • Godot posiada klasę FastNoiseLite, która zawiera w sobie wiele szumów, w tym Perlin i Simplex. 

Co ciekawe, FastNoiseLite dostępne jest jako publiczne repozytorium więc można korzystać z tej biblioteki niezależnie od silnika, którego używacie (lub nawet bez żadnego silnika). W praktyce szeroka dostępność implementacji szumów oznacza, że aby skorzystać z dobrodziejstw tych algorytmów nie musimy zagłębiać się w ich matematyczne bebechy. Jednakże znajomość parametrów algorytmu i i umiejętność dostosowywania ich do naszych potrzeb jest niezbędna do uzyskiwania satysfakcjonujących wyników, więc spieszę z wyjaśnieniami! 

Tak jak opisywałem to w poprzednim artykule, Szum Perlina to po prostu ciąg liczb losowych z zakresu -1.0 do 1.0, wygenerowanych w taki sposób, aby konkretne wartości nie różniły się drastycznie od swoich sąsiadów. Na przykład:

-0.01   0.13   0.26   0.43   0.51   0.38

Od strony programistycznej wygenerowanie takiego ciągu liczb będzie prostym zabiegiem niezależnie od użytej biblioteki – oto przykład z silnika Godot, który korzysta z FastNoiseLite:

// Tworzymy nowy szum korzystając z biblioteki FastNoiseLite

var noise = FastNoiseLite.new()

// Informujemy że chodzi nam o Szum Perlina (FastNoiseLite wspiera wiele szumów)

noise.noise_type = FastNoiseLite.TYPE_PERLIN 

// Pobieramy wartość szumu

noise.get_noise_1d(1.0)

Kluczową funkcją jest get_noise_1d czyli po prostu “Daj mi wartość szumu w danym miejscu (o danym indeksie)”. Jej nazwa może oczywiście różnić się w zależności od silnika lub biblioteki, z której korzystamy, ale zasada działania pozostaje ta sama. Jeśli szum wygeneruje taki ciąg liczb:

-0.01   0.13   0.26   0.43   0.51   0.38   0.25   0.12   0.01   -0.11 (…)

To pobieranie jego kolejnych wartości da następujące wyniki:

  • get_noise_1d(1.0) = 0.13
  • get_noise_1d(2.0) = 0.26
  • get_noise_1d(0.5) = 0.195

 Wygenerowane w ten sposób kilkanaście kolejnych liczb naniesione na wykres mogłoby wyglądać tak:

Małe frequency (100 punktów)

Wygląda dość losowo, a “wzgórza” będą wyglądać inaczej za każdym razem gdy wygenerujemy nowy szum. Analogicznie jeśli skorzystamy z get_noise_2d i wygenerujemy siatkę liczb, po naniesieniu ich na obrazek i pokolorowaniu na skalę szarości otrzymamy teksturę podobną do tej:

Dodatkowo, w kontekście szumu Perlina, w zależności od biblioteki, z której korzystamy, możemy spotkać się z parametrem Frequency, czyli częstotliwością. Wiemy już, że jedną z głównych idei Szumu Perlina jest to, że kolejne liczby nie będą się drastycznie od siebie różniły. Frequency pozwala nam jeszcze bardziej dostosować te różnice – im mniejsza wartość frequency, tym różnice między kolejnymi liczbami szumu będą również odpowiednio mniejsze.

Małe frequency (100 punktów)

Większa częstotliwość sprawi, że kolejne wartości będą bardziej „oddalone „od siebie. Wyobraź sobie, że wyższe frequency “oddala kamerę”, ponieważ zwiększenie odległości pomiędzy kolejnymi wartościami szumu pozwala nam zwizualizować szerszy obraz. Przy pobraniu dokładnie takiej samej ilości liczb szumu, co w przypadku poprzedniego wykresu, ale z większym frequency otrzymamy nieco bardziej wyboisty wynik:

Duże frequency (100 punktów)

Jeśli nie kupujesz argumentu o “oddalaniu kamery”, to pa teraz! Zwróć uwagę jak parametr frequency (w prawej górnej części ekranu) wpływa na wartości szumu. Resztą parametrów się na razie nie interesuj – dojdziemy do tego.

Wraz ze zwiększaniem parametru “frequency” widać jak istniejące “wzgórza” się zmniejszają i pojawiają się nowe. Najlepsze jest to, że “wzgórza” to nie żadna metafora  – tych danych na serio można użyć do generacji wyboistości w Twojej grze.

Analogicznie w przypadku dwuwymiarowego szumu wynik zmieni się w zależności od frequency i jeszcze bardziej będzie przypominać oddalanie lub przybliżanie “kamery”.

Ale to nie wszystko! Nie wiem jak Wam, ale mi czegoś tutaj jednak brakuje – wykresy wyglądają zbyt gładko, nie przypominają “poszarpanych” krawędzi mapy czy szczytów gór, nawet w przypadku wysokiej wartości parametru “frequency”

Dlatego też w przypadku szumów, mimo, że nie jest to ich integralną częścią, korzystamy z tzw. Fractal Brownian Motion. Ta zapożyczona z matematycznych fraktali technika polega na modyfikowaniu naszego szumu innym szumem, przez co wynik będzie mniej “gładki”. Zagmatwane, wiem, ale zwróć uwagę na poniższy rysunek, który obrazuje ten proces:

Pierwszy wykres (ten od lewej) to nasz główny szum i on będzie decydował o ogólnym kształcie wyniku. Każdą wartość tego szumu o danym indeksie modyfikujemy o wartość drugiego szumu o tym samym indeksie, przez co wynik będzie dalej przypominał ten pierwszy i najważniejszy, ale nabierze też nierówności z tego drugiego. Ten proces nie musi się kończyć na modyfikowaniu jednego szumu drugim – takich modyfikacji możemy dokonać wiele, co jest zdecydowanie najczęstszą praktyką.

Wszystkie szumy biorące udział w tym procesie – zarówno podstawowy, jak i te, które go modyfikują – nazywamy oktawami. Liczymy je od zera (jak to mają w zwyczaju informatycy), więc nasz główny wykres będzie zerową oktawą.

3 oktawy

Nie istnieje jedna „najlepsza” liczba oktaw – w moich testach najlepsze rezultaty uzyskiwałem przy wartości od 4 do 8. Oznacza to, że podstawowy szum był modyfikowany przez od 3 do 7 kolejnych szumów.

Ilość oktaw jest głównym parametrem Fractal Brownian Motion wpływającym na kształt szumu, określającym szczegółowość nierówności. Pozostałe – lacunarity oraz persistence – będą określały wygląd kolejnych oktaw i tym samym pośrednio wpływały na ilość i głębokość nierówności w wynikowym szumie.

Wcześniej opisywałem parametr frequency, który “oddala kamerę” szumu – lacunarity robi dokładnie to samo, tylko dla kolejnych oktaw. Wraz ze zwiększaniem tego parametru kolejne oktawy będą bardziej wyboiste, co z kolei sprawi, że nasz wynik będzie miał bardziej nierówną powierzchnię. Mówiąc nieco bardziej naukowo – lacunarity to modyfikator częstotliwości dla kolejnych oktaw. 

Małe lacunarity
Duże lacunarity

Zwróć uwagę na drugą oktawę (wykres w środku) – większe lacunarity sprawia, że jest bardziej nierówna. Wynik końcowy dalej przypomina pierwszą oktawę, ale większe nierówności drugiej wpływają na jego kształt w inny sposób niż w przypadku małej wartości tego parametru.

Warto zaznaczyć, że podczas używania szumów w „prawdziwym życiu” nigdzie nie widać tych oktaw – po prostu wybieramy odpowiednie parametry i otrzymujemy wynik końcowy, a wszystkie kalkulacje dzieją się „pod spodem”. Oto przykład jak zmienia się szum w zależności od parametru lacunarity:

Małe lacuranity
Średnie lacuranity
Duże lacuranity

Persistence natomiast określa jak bardzo kolejne oktawy wpływają na kształt głównego szumu. Innymi słowy lacunarity wytwarza na powierzchni wyboistości, a persistence decyduje o ich głębokości. Weźmy więc ostatni wykres z parametrem lacunarity ustawionym na 2 i spróbujmy zwiększyć persistence:

Małe persistence
Średnie persistence
Duże persistence

Przyjrzyj się dokładnie – wyboistości na powierzchni są dokładnie w tych samych miejscach co na poprzednich wykresach, ale tym razem są bardziej skrajnie wysokie lub głębokie. Zupełnie tak jakbyś każdą z oktaw modyfikujących główny szum przemnożył przez większą liczbę. Dokładnie to robi persistence – mnoży poszczególne wartości oktaw o podaną liczbę.


Dla mądralińskich z pierwszej ławki: „pod spodem” to mnożenie jest dość ciekawe i najlepiej wyjaśnić je na przykładzie;

  • Persistence = 0.5 oznacza, że do każdej wartości głównego szumu o danym indeksie dodawana jest wartość o tym samym indeksie, z pierwszej oktawy pomnożona przez 0.5, z drugiej oktawy pomnożona przez 0.25 (czyli 0.5²), z trzeciej przez 0.125 (0.5³) i tak dalej.
  • Lacunarity zwiększa częstotliwość kolejnych oktaw w sposób potęgowy – wartość 2 oznacza, że pierwsza oktawa będzie miała dwukrotnie większą częstotliwość, następna czterokrotnie, kolejna ośmiokrotnie, i tak dalej.

Może to wydawać się nieintuicyjne, ale ma sens — w ten sposób modyfikujemy szum „od ogółu do szczegółu”. Każda kolejna oktawa coraz mniej wpływa na ogólny kształt szumu, ale dodaje coraz drobniejsze detale.


Persistence można oczywiście zwiększać lub zmniejszać do woli, ale powyżej pewnego pułapu przestaje mieć to sens, ponieważ oktawy zbytnio zaburzają początkowy wynik:

Analogicznie zbyt małe persistence sprawi, że oktawy nie będą miały praktycznie żadnego wpływu na początkowy wykres, nie ważne jak duży będzie współczynnik lacunarity:

Jak w przypadku większości tego typu algorytmów musisz zastanowić się jakiego wyniku oczekujesz, pobawić się parametrami i znaleźć tzw. “sweet spot”. Skoro pytasz, to na przykład ten mi się podoba:

Reasumując (TL;DR):

  • Oktawy będą głównym parametrem decydującym o szczegółowości szumu,
  • Lacunarity określi ilość „nierówności”,
  • Persistence ich „głębokość”,
  • Frequency natomiast “oddala” lub “przybliża” “kamerę” (jeśli patrzymy na szum jak na mapę).

Dokładnie tak samo będziecie używać tych parametrów w silnikach gier, więc wiedząc, co one dokładnie oznaczają, będziecie w stanie łatwiej uzyskać pożądane wyniki. Jedna uwaga – w zależności od technologii parametry mogą się nazywać inaczej lub dodawać ekstra parametry. Przykładowo, w przypadku Godota i FastNoiseLite, parametr persistence jest zastąpiony parametrem gain – dlatego zawsze warto zajrzeć do dokumentacji biblioteki, z której korzystacie.

Uff mamy to.

Gratuluję, udało Ci się wytrwać do końca! Tak jak wspomniałem na wstępie, ta wiedza pozwoli Ci sprawniej korzystać z bibliotek do generowania szumów. Dobre zrozumienie parametrów wejściowych algorytmu zdecydowanie ułatwi tworzenie szumów, które pomogą Ci w generowaniu proceduralnych treści takich, jakich sobie wymarzyłeś. Dobra wiadomość jest taka, że wspomniane parametry Fractal Brownian Motion, czyli oktawy, persistence oraz lacunarity to wiedza uniwersalna w kontekście szumów i przydadzą się również przy innych szumach – rozwinięciu Perlina czyli Simplex Noise czy Cellular Noise, o których napiszę w kolejnych artykułach.

To ja, Kuba

To ja, Kuba

Chcesz być na bieżąco z algorytmami i śmieszkami?

Zapraszam na moje social media!

Ostatnie wpisy

Szum Perlina

W poprzednich artykułach wspominałem czym są szumy i jak są wykorzystywane do tworzenia proceduralnych światów, a dzisiaj przyjrzymy się dokładniej konkretnemu algorytmowi z “rodziny szumów”, a mianowicie - “Szumie Perlina” (Perlin Noise). Tak więc bierz meliskę, włącz sobie swój ulubiony...

20.10.2025
Czytaj więcej