Saat ini saya sedang mengerjakan sebuah program yang seharusnya menghasilkan derau acak di layar berdasarkan 'koordinat' piksel. Koordinat harus memiliki warna yang sama setiap kali Anda me-restart program. Namun, menggunakan util Java. Secara acak, hasil yang saya dapatkan tidak acak seperti yang saya inginkan:
Saya berpikir bahwa jika saya menggunakan koordinat gabungan (seperti dalam satu bilangan bulat yang terbentuk dari kedua koordinat di sebelah satu sama lain) setiap koordinat akan memiliki angka yang berbeda. Dengan menggunakan angka itu sebagai seed, saya berharap mendapatkan angka acak yang berbeda untuk setiap koordinat yang digunakan untuk nilai rgb koordinat itu.
Ini adalah kode yang saya gunakan:
public class Generate {
static Random Random;
public static int TileColor(int x, int y){
Random = new Random(Integer.valueOf(Integer.toString(x)+Integer.toString(y)));
int b = 1 + Random.nextInt(50);
int g = 1 + Random.nextInt(50);
int r = 1 + Random.nextInt(50);
int color = -Color.rgb888(r, g, b);
return color;
}
}
Apakah pola yang dibuat oleh program karena cara fungsi acak java bekerja atau apakah saya melakukan sesuatu yang salah dan haruskah saya mencoba pendekatan yang berbeda?
Pembaruan: Saya sekarang mencoba untuk menyingkirkan masalah seputar rangkaian dengan menggunakan kode berikut:
public static int TileColor(int x, int y){
Randomy = new Random(y);
Randomx = new Random(x);
Random = new Random(Integer.valueOf(Integer.toString(Randomx.nextInt(1234))+Integer.toString(Randomy.nextInt(1234))));
int b = 1 + Random.nextInt(100);
int g = 1 + Random.nextInt(100);
int r = 1 + Random.nextInt(100);
int color = -Color.rgb888(r, g, b);
return color;
}
Entah bagaimana, ini juga memberikan gambar acak (menurut saya):
Namun kode ini menghasilkan ulang tiga kali per piksel. Meskipun ini bukan masalah bagi saya saat ini, saya mempertimbangkan untuk mengubah kode ini jika saya membutuhkan kinerja yang lebih baik nantinya.
Jawaban:
java.util.Random
Kelas Java biasanya memberi Anda urutan nomor pseudorandom yang cukup baik untuk digunakan dalam gim 1 . Namun, karakteristik itu hanya berlaku untuk urutan beberapa sampel berdasarkan benih. Saat Anda menginisialisasi ulang RNG dengan nilai benih tambahan dan hanya melihat nilai pertama dari setiap urutan, karakteristik keacakan tidak akan sama baiknya.Apa yang bisa Anda lakukan sebagai gantinya:
Alih-alih menggunakan generator angka acak, gunakan fungsi intisari pesan untuk mengubah pasangan koordinat menjadi nilai warna. Hasil dari sebagian besar MDF tidak dapat diprediksi untuk memenuhi sebagian besar uji keacakan. Outputnya biasanya lebih dari 24 bit yang Anda butuhkan untuk nilai RGB, tetapi memotongnya biasanya tidak ada masalah.
Untuk meningkatkan kinerja, Anda dapat menggabungkan generasi intisari pesan dengan potongan. Hasilkan potongan kecil piksel yang hanya cukup besar untuk menggunakan panjang penuh satu output dari fungsi digest Anda.
1 ketika sangat penting bahwa tidak ada yang bisa memprediksi angka berikutnya, gunakan yang lebih lambat tetapi kurang dapat diprediksi
java.security.SecureRandom
sumber
Dalam hal ini, Anda akan ingin menggunakan fungsi noise deterministik seperti Perlin noise atau noise simplex .
( Lihat pertanyaan ini untuk informasi lebih lanjut tentang kebisingan Perlin dengan beberapa gambar cantik. )
Sebagian besar, menggunakan built-in
random()
atau fungsi serupa akan memberi Anda nilai yang berbeda setiap kali Anda menjalankan program, karena mereka dapat menggunakan jam sebagai input atau nilai pseudorandom lainnya.Pilihan lain adalah membuat "peta kebisingan" satu kali, offline, dan kemudian menggunakannya sebagai sumber angka acak Anda nanti.
Dalam implementasi Anda, Anda merangkai representasi string dari x dan
y
. Itu buruk karena tidak unik di seluruh domain. Contohnya,Semoga berhasil!
sumber
Mari kita lihat apa yang sebenarnya Anda lakukan:
Semua ini terdengar baik-baik saja, tetapi Anda menerima pola karena:
Pixel pada 1,11 dan pixel pada 11,1 keduanya diunggulkan nomor 111 sehingga mereka yakin memiliki warna yang sama.
Juga, selama Anda selalu siklus dengan cara yang sama, Anda hanya dapat menggunakan satu generator, tidak perlu menggunakan satu untuk setiap piksel. Satu untuk seluruh gambar akan dilakukan! Masih akan ada semacam pola karena pseudo-randomness. @ David Jelas benar tentang menggunakan beberapa algoritma Noise, itu akan membuatnya terlihat lebih acak.
sumber
Buat generator warna, lalu hasilkan warna Anda untuk ubin Anda. Benih hanya sekali! Anda tidak perlu menanam lebih dari itu, setidaknya per ubin.
Dan penggunaannya akan seperti berikut:
Dengan ini jika Anda tidak puas dengan hasilnya, ganti
Random
benih. Selain itu, Anda hanya perlu menyimpan / mengomunikasikan benih dan ukuran sehingga semua klien memiliki gambar yang sama.sumber
Alih-alih menggunakan Random, pertimbangkan untuk menggunakan hash digest seperti MD5. Ini memberikan sulit untuk memprediksi nilai 'acak' berdasarkan input tertentu, tetapi selalu nilai yang sama untuk input yang sama.
Contoh:
CATATAN: Saya Tidak tahu dari mana Color.rgb888 (..) berasal, jadi saya tidak tahu apa kisaran yang diizinkan. 0-255 adalah normal.
Perbaikan untuk dipertimbangkan:
sumber
Orang lain telah menunjukkan bahwa salah satu cara untuk mendapatkan perilaku yang Anda inginkan adalah menggunakan fungsi hash, alias "fungsi digest pesan." Masalahnya adalah bahwa ini sering didasarkan pada algoritma seperti MD5, yang aman secara kriptografis (yaitu benar-benar, sangat acak) tetapi sangat lambat. Jika Anda menggunakan fungsi hash kriptografis setiap kali Anda membutuhkan piksel acak, Anda akan mengalami masalah kinerja yang cukup parah.
Namun, ada fungsi hash non-kriptografi yang dapat menghasilkan nilai-nilai yang cukup acak untuk tujuan Anda dan juga cepat. Yang biasanya saya raih adalah murmurhash . Saya bukan pengguna Java tetapi tampaknya setidaknya ada satu implementasi Java yang tersedia. Jika Anda benar-benar perlu memiliki setiap piksel yang dihasilkan dari koordinatnya, daripada menghasilkannya sekaligus dan menyimpannya dalam tekstur, maka ini akan menjadi cara yang baik untuk melakukannya.
sumber
Saya akan menggunakan prime lebih dari 2000 (resolusi khas maks)
Ini akan meminimalkan (atau menghilangkan duplikat benih)
sumber
Random
cukup acak. Anda salah menggunakannya karena dua alasan utama.Integer.valueOf(Integer.toString(x)+Integer.toString(y))
antara piksel yang Anda tanam.Saya hanya menggunakan beberapa variasi dari kode berikut, di mana Anda dapat memilih fungsi hash (jangan gunakan Integer.getHashCode) dari jawaban di /programming/9624963/java-simplest-integer- hash
di mana fungsi hash bisa
sumber
Anda dapat mencoba menggunakan sistem waktu jam saat ini sebagai seed seperti ini:
Semoga ini menghasilkan nilai yang lebih acak.
sumber
Berikut ini adalah fungsi shader statis satu baris yang saya buat - poltergeist (Noisy Ghost).
Dibutuhkan koordinat 2D dan seed, dan dirender secara monoton seperti yang diminta. Ini berjalan pada fps waktu nyata, terlepas dari resolusi layar. Untuk itulah GPU digunakan.
Resolusi apa pun, tekstur apa pun, di perangkat apa pun (juga seluler) yang mendukung GL (yang hampir semuanya dengan layar).
Lihat berlari di sini, sekarang!
https://www.shadertoy.com/view/ltB3zD
Anda dapat dengan mudah memasukkan shader ini dalam program java Anda menggunakan OpenGL standar, atau di browser apa pun yang menggunakan webgl standar.
Hanya untuk bersenang-senang, saya melempar tantangan bagi siapa saja untuk mengalahkan Poltergeist dalam kualitas dan kinerja di semua perangkat. Aturan Hantu Bising! Tak terkalahkan!
sumber