Zrozumieć hałas Perlina

31

Zabawiam się Perlin Noise po pracy z Diamond Square. Śledziłem implementację Hugo Eliasa, która w zasadzie tworzy serię funkcji z x, y jako danymi wejściowymi, aby wyrzucić każdą wartość współrzędnej.

Mój kod PHP jest tutaj :

Mam dwa pytania:

Jak użyć algorytmu do wygenerowania mapy wysokości w tablicy? Nie w pełni go zrozumiałem i po prostu przeniosłem na PHP pseudokod, ale wykonuję ostatnią funkcję (map_perlined) po przeczytaniu gdzieś, że algorytm „magicznie” daje wartości przejściowe dla każdego podanego punktu x, y (najwyraźniej bez konieczności czytania jego sąsiednie wartości), po prostu otrzymuję to, gdy używam jako funkcji losowejmt_rand(-100,100)/100;

wprowadź opis zdjęcia tutaj

A to podczas korzystania z kryptografii: 1.0-(($n*($n*$n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0;(która, BTW, może być zaimplementowana w obecnej postaci w PHP?):

wprowadź opis zdjęcia tutaj

Podsumowując, trzy pytania:

  1. Czy mój kod jest poprawny?
  2. Funkcja losowa może być przeniesiona do PHP zgodnie z opisem w kodzie? Nie zgłasza błędów, ale wyników nie ma.
  3. Jak faktycznie korzystać z algorytmu?

AKTUALIZACJA

Ok, stworzyłem port PHP kodu pokazanego w artykule Gustavsona i, jak powiedział inny programista, generuje tylko jedną oktawę. Czy masz jakąkolwiek inną przydatną stronę / artykuł / przewodnik na temat tego, jak używać tego z pojęciami wielu oktaw, amplitudy, częstotliwości itp. W celu sterowania funkcją szumu? Na papierze Gustavsona pokazano tylko wyniki, a nie faktyczną implementację algorytmu, może coś mi brakuje?

AKTUALIZACJA 2
@NATHAN

Zrobiłem coś takiego:

$persistence = 0.5;

for ($j = 0; $j < $size; $j++) {
    for ($i = 0; $i < $size; $i++) {

        for ($o = 0; $o < 8; $o++) {
            $frequency = pow(2,$o);
            $amplitude = pow($persistence, $o);
            $value += SimplexNoise($i*$frequency, $j * $frequency) * $amplitude;
            }

            //$value = SimplexNoise($i, $j) + 0.5 * SimplexNoise($i, $j) + 0.25 * SimplexNoise($i, $j);
            $this->mapArray[$i][$j] = new Cell($value);

Po normalizacji wartości do 0..1 otrzymuję raczej nudną mapę wysokości, taką jak:

wprowadź opis zdjęcia tutaj

Jak zaliczyć mapę? Być może muszę wdrożyć wersję 3d z trzecią wartością o losowej wysokości? Ale jeśli tak, musiałbym dowiedzieć się, aby wziąć pod uwagę wartości sąsiadów, które kończyłbym czymś w rodzaju algorytmu kwadratu diamentowego, dokładnie tego, czego nie chcę robić.

AKTUALIZACJA 3

Więcej pracy Perlina. Muszę jeszcze znaleźć sposób, aby kierować hałas do moich wyników. Sprawdź te oktawy i wynik końcowy:

Oktawa I do IV

Oktawa 1Oktawa2Oktawa 3Oktawa 4

Podsumował

Zsumowane oktawy 1-4

Każda oktawa jest prawie taka sama. Sprawdź kod:

$persistence = 0.5;

    for ($j = 0; $j < $size; $j++) {
      for ($i = 0; $i < $size; $i++) {
        $value = 0;

        for ($o = 0; $o < 4; $o++) {
          $frequency = pow(2,$o);
          $amplitude = pow($persistence, $o);
          $value += improved_noise($i*$frequency, $j*$frequency, 0.5)*$amplitude;

        }
        $this->map[$i][$j] = new Cell($value);

Wyniki są znormalizowane. Co byś zastosował, miałby silny wpływ na rozwój hałasu? Widzę przykłady, w których zmiana amplitudy daje miękkie lub szorstkie powierzchnie, ale nawet jeśli dam ogromną amplitudę, nie widzę różnicy.

Gabriel A. Zorrilla
źródło
Po prostu dodaj razem wiele wystąpień, zwiększając częstotliwość i zmniejszając amplitudę za każdym razem, np .: perlin (x) + 0,5 * perlin (2 * x) + 0,25 * perlin (4 * x) + ... (dla tylu oktaw chcesz). Możesz także spróbować zmienić czynniki, aby uzyskać inny wygląd; nie muszą być potęgami 2.
Nathan Reed
1
Po aktualizacji wygląda na to, że nie skalujesz poprawnie Y - jestem zbyt zmęczony, aby przeszukiwać PHP (ponieważ nie znam PHP); ale po raz pierwszy natrafiłem na podobny problem w moim języku ojczystym. Zabij także oktawy i po prostu debuguj jeden poziom perlina.
Jonathan Dickinson
Ktoś na moją aktualizację III?
Gabriel A. Zorrilla

Odpowiedzi:

28

To, co wdrożyłeś, nie jest hałasem Perlina. Nie jestem pewien, dlaczego Hugo Elias twierdzi, że tak, ale jest zdezorientowany. Oto referencyjna implementacja Kena Perlina. W rzeczywistości nie wywołuje żadnego zewnętrznego generatora liczb losowych, ale używa wbudowanej funkcji skrótu do tworzenia pseudolosowych wektorów gradientu.

Zauważ też, że hałas Perlina składa się tylko z jednej oktawy. Podsumowanie wielu oktaw (skalowane przypadki funkcji szumu), jak sugeruje Hugo Elias, jest użyteczną techniką, ale nie jest częścią szumu Perlina. To, co otrzymujesz, nazywa się hałasem fraktalnym, czasami „fraktalnym hałasem Browna” (z powodu rzekomej podobieństwa do ruchu Browna).

Jeśli chcesz zrozumieć geometrycznie, co robi algorytm, spróbuj tego artykułu . Chodzi o inny rodzaj hałasu zwany „hałasem jednostronnym”, ale zawiera także wyjaśnienie klasycznego hałasu Perlina. Nawiasem mówiąc, hałas simpleksowy został również wynaleziony przez Perlina i ma być poprawą w stosunku do jego klasycznego hałasu, więc możesz spróbować go wdrożyć, jeśli chcesz grać funkcjami szumu.

Nathan Reed
źródło
2
+1 za artykuł Gustavsona. Wyjaśnia zarówno hałas perlinowy, jak i simpleks w najczystszy sposób, jaki do tej pory widziałem. Oczywiście zasady simpleksowe!
FxIII,
Znalazłem też ten papier jakiś czas temu, ale Hugo wyglądał na prostszy. Przeczytam i spróbuję! Dzięki!
Gabriel A. Zorrilla,
2
zachowaj
Wiem, że to stary temat, ale stwierdzenie, że implementacja referencyjna nie używa liczby losowej, jest niepoprawne. Podczas inicjalizacji biblioteki (lub przy pierwszym wywołaniu funkcji szumu) generowanych jest 256 losowych gradientów. Haszowanie, o którym mówisz, służy jedynie przymusowi nieskończonego zestawu liczb całkowitych do zakresu [0, 255], który jest buforowany. Zasadniczo jest to tylko optymalizacja tabeli przeglądowej, a algorytm działa równie dobrze, jeśli na przykład wysiejesz PRNG ze współrzędną siatki i użyjesz go do wygenerowania gradientu, jest to (znacznie) wolniejsze.
bcrist
@bcrist Myślę, że masz na myśli starszą wersję hałasu Perlina. „Poprawiony szum” Perlina, z którym się połączyłem , wykorzystuje stały zestaw 12 wektorów gradientowych, a nie 256 losowych. Używa tabeli permutacji jako funkcji skrótu do mapowania współrzędnych siatki na jeden z tych 12 wektorów gradientu.
Nathan Reed
11

To powszechne nieporozumienie. To, co Hugo Elias nazywa hałasem „Perlina”, to tak naprawdę hałas fraktalny lub różowy. Aby lepiej zrozumieć, czym jest hałas Perlina, możesz przeczytać artykuł Perlina, do którego link znajduje się w odpowiedzi Nathana Reeda, lub libnoise docs (tam jest ten sam błąd: hałas Perlina to, co nazywają hałasem Gradientu) lub dokumenty CoherentNoise .

Teraz, aby odpowiedzieć na twoje pytanie: nie uzyskałeś oczekiwanego rezultatu, ponieważ częstotliwość hałasu jest zbyt wysoka. Częstotliwości zaczynają się od 1 i rosną, co oznacza, że ​​każdy piksel na wynikowej mapie ma losową wartość. Aby zobaczyć dokładniejszą strukturę mapy, musisz „powiększyć” hałas. Tak naprawdę nie mówię w PHP, ale przypuszczam, że kod powinien wyglądać tak:

$arrayMap[$i][$j] = PerlinNoise_2D($i/$width, $j/$height, $p, $octaves);

Oznacza to, że „rozciągasz” jeden okres hałasu na całej mapie. Oczywiście możesz użyć innych współczynników - po prostu wypróbuj inne, zobacz, co się stanie.

Nieważne
źródło
Dzięki za spójne dokumenty hałasu! Widzę, że to napisałeś :) Jaki jest błąd w dokumentach libnoise? Czy hałas Perlina nie jest rodzajem szumu gradientowego?
legends2k