Memahami Perlin Noise

31

Saya mempermainkan Perlin Noise setelah bekerja dengan Diamond Square. Saya mengikuti implementasi oleh Hugo Elias yang pada dasarnya, membuat serangkaian fungsi dengan x, y sebagai input untuk membuang setiap nilai koordinat.

Kode PHP saya ada di sini :

Saya punya dua pertanyaan:

Bagaimana cara menggunakan algoritma untuk menghasilkan peta ketinggian dalam array? Saya tidak sepenuhnya memahaminya dan hanya porting ke PHP pseudocode, tetapi melakukan fungsi terakhir (map_perlined) setelah membaca di suatu tempat bahwa algoritma "ajaib" memberi Anda nilai-nilai yang ditransisikan untuk setiap x, titik y diberikan (tampaknya, tanpa harus membaca nya nilai yang berdekatan), saya hanya mendapatkan ini ketika menggunakan fungsi acakmt_rand(-100,100)/100;

masukkan deskripsi gambar di sini

Dan ini saat menggunakan kriptografi: 1.0-(($n*($n*$n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0;(yang, BTW, dapat diimplementasikan "apa adanya" di PHP?):

masukkan deskripsi gambar di sini

Jadi, simpulkan, tiga pertanyaan:

  1. Apakah kode saya benar?
  2. Fungsi acak dapat porting ke PHP seperti yang dijelaskan dalam kode? Tidak ada kesalahan, tapi hasilnya tidak ada.
  3. Bagaimana saya benar-benar menggunakan algoritma?

MEMPERBARUI

Ok, buat port PHP dari kode yang ditunjukkan di kertas Gustavson, dan seperti kata coder lainnya, itu hanya menghasilkan satu oktaf. Punya situs / kertas / panduan lain yang bermanfaat tentang cara menggunakan ini dengan konsep multi oktaf, amplitudo, frekuensi, dll. Untuk mengontrol fungsi noise? Pada makalah Gustavson hanya menunjukkan hasilnya, bukan implementasi sebenarnya dari algoritma, mungkin saya kehilangan sesuatu?

UPDATE 2
@NATHAN

Saya membuat sesuatu seperti:

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

Dan setelah menormalkan nilai ke 0..1, saya mendapatkan peta ketinggian yang agak membosankan seperti:

masukkan deskripsi gambar di sini

Bagaimana cara saya seed seed? Mungkin yang perlu saya terapkan adalah versi 3d dengan nilai ketiga tinggi acak? Tetapi jika demikian, saya harus mencari tahu untuk mempertimbangkan nilai tetangga, yang akan saya akhiri dengan sesuatu seperti algoritma berlian persegi, persis apa yang tidak ingin saya lakukan.

PEMBARUAN 3

Lebih banyak pekerjaan Perlin. Saya belum menemukan cara untuk memandu suara ke hasil saya. Periksa oktaf ini dan hasil akhirnya:

Oktaf I ke IV

Oktaf1Oktaf2Oktaf3Oktaf4

Jumlahkan

Oktaf 1-4 disimpulkan

Setiap oktaf hampir sama. Periksa kode:

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

Hasilnya dinormalisasi. Apa yang akan Anda gunakan memiliki pengaruh kuat dalam pengembangan kebisingan? Saya melihat contoh di mana mengubah amplitudo memberikan permukaan lunak atau kasar, tetapi bahkan jika saya memberikan amplitudo besar, saya melihat sedikit perbedaan.

Gabriel A. Zorrilla
sumber
Cukup tambahkan beberapa contoh, tambahkan frekuensi dan kurangi amplitudo setiap kali, seperti: perlin (x) + 0,5 * perlin (2 * x) + 0,25 * perlin (4 * x) + ... (untuk oktaf sebanyak kamu ingin). Anda juga dapat mencoba mengubah faktor untuk mendapatkan tampilan yang berbeda; mereka tidak perlu menjadi kekuatan 2.
Nathan Reed
1
Pasca-Pembaruan, sepertinya Anda tidak menskalakan Y dengan benar - Saya terlalu lelah untuk menguasai PHP (karena saya tidak tahu PHP); tapi saya mengalami masalah serupa di bahasa rumah saya ketika menerapkan perlin pertama kalinya. Juga bunuh oktaf dan debug hanya satu tingkat perlin.
Jonathan Dickinson
Adakah yang bisa melakukan pembaruan III saya?
Gabriel A. Zorrilla

Jawaban:

28

Apa yang Anda implementasikan bukanlah Perlin noise. Saya tidak yakin mengapa Hugo Elias mengatakan itu, tapi dia bingung. Ini adalah implementasi referensi Ken Perlin. Itu tidak benar-benar memanggil generator nomor acak eksternal, tetapi menggunakan fungsi hash built-in untuk menghasilkan vektor gradien pseudorandom.

Perhatikan juga bahwa kebisingan Perlin hanya terdiri dari satu oktaf. Merangkum beberapa oktaf (contoh skala fungsi noise), seperti yang disarankan Hugo Elias, adalah teknik yang berguna, tetapi bukan bagian dari noise Perlin. Apa yang Anda dapatkan dengan melakukan itu disebut fraktal noise, kadang-kadang "fraktal Brownian noise" (karena kemiripan yang seharusnya dengan gerakan Brown).

Jika Anda ingin memahami secara geometris apa yang dilakukan algoritma, coba makalah ini . Ini tentang berbagai jenis suara yang disebut "simplex noise", tetapi juga termasuk penjelasan tentang kebisingan Perlin klasik. Kebetulan, noise simpleks juga ditemukan oleh Perlin dan seharusnya menjadi peningkatan dari noise klasiknya, jadi Anda dapat mencoba mengimplementasikannya juga jika Anda tertarik bermain dengan fungsi noise.

Nathan Reed
sumber
2
+1 untuk makalah Gustavson. Ini menjelaskan perlin dan noise simpleks dengan cara paling jelas yang pernah saya lihat sejauh ini. Jelas aturan kebisingan simpleks!
FxIII
Saya juga menemukan kertas itu beberapa waktu yang lalu tetapi Hugo terlihat lebih sederhana. Saya akan membacanya dan mencobanya! Terima kasih!
Gabriel A. Zorrilla
2
hati-hati saat mengunduh noise simplex, mungkin ada virus;)
bobobobo
Saya tahu ini adalah topik lama, tetapi mengatakan bahwa implementasi referensi tidak menggunakan nomor acak salah. Ketika pustaka diinisialisasi (atau pertama kali fungsi noise disebut) 256 gradien acak dihasilkan. Hashing yang Anda maksud hanyalah untuk memaksa set bilangan bulat tak terbatas ke dalam rentang [0, 255] yang di-cache. Pada dasarnya ini hanya optimasi tabel pencarian, dan algoritme berfungsi dengan baik jika, misalnya, Anda menyemai PRNG dengan koordinat kisi dan menggunakannya untuk menghasilkan gradien, hanya saja (lebih) lebih lambat dari itu.
bcrist
@ Christopher Saya pikir Anda mengacu pada versi Perlin noise yang lebih lama. "Peningkatan noise" Perlin, yang saya tautkan ke , menggunakan satu set tetap dari 12 vektor gradien, bukan 256 yang acak. Ini menggunakan tabel permutasi sebagai fungsi hash untuk memetakan koordinat grid ke salah satu dari 12 vektor gradien.
Nathan Reed
11

Itu kesalahpahaman umum. Apa yang disebut Hugo Elias kebisingan "Perlin" sebenarnya kebisingan fraktal, atau merah muda. Untuk lebih memahami apa itu kebisingan Perlin, Anda dapat membaca artikel Perlin yang ditautkan dalam jawaban Nathan Reed, atau libnoise docs (ada kesalahan yang sama di sana: Perlin noise adalah apa yang mereka sebut noise Gradient), atau CoherentNoise docs .

Sekarang, untuk benar-benar menjawab pertanyaan Anda: Anda tidak mendapatkan hasil yang diharapkan karena frekuensi noise terlalu tinggi. Frekuensi Anda mulai dengan 1 dan meningkat, artinya setiap piksel di peta yang dihasilkan memiliki nilai acak. Untuk melihat struktur peta yang lebih halus, Anda perlu "memperbesar" noise. Saya tidak benar-benar berbicara PHP, tapi saya kira kodenya akan terlihat seperti ini:

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

Artinya, Anda "meregangkan" satu periode kebisingan di seluruh peta Anda. Tentu saja, Anda dapat menggunakan koefisien lain - coba saja yang berbeda, lihat apa yang terjadi.

Sudahlah
sumber
Terima kasih untuk dokumen kebisingan yang koheren! Saya melihat bahwa Anda telah menulisnya :) Apa kesalahan dalam dokumen libnoise? Bukankah Perlin noise semacam noise gradien?
legends2k