Tepi berisik, menghaluskan tepi antara wajah melalui fragmen shader


8

Saya memiliki medan yang dihasilkan, dengan geometri heksagonal, seperti tangkapan layar di bawah:

masukkan deskripsi gambar di sini

Saya kemudian menghasilkan bioma, tetapi seperti yang Anda lihat, perbatasan di antara mereka benar-benar jelek dan lurus. Untuk menyembunyikan asal heksagonal itu, saya perlu memuluskan perbatasan antara bioma. Beginilah tampilannya sekarang dalam bingkai gambar dengan wajah tringular asli:

masukkan deskripsi gambar di sini

Yang saya tuju adalah sesuatu yang lebih seperti ini:

masukkan deskripsi gambar di sini

Setiap dhuwur memiliki attibute yang memegang tipe bioma, saya juga dapat menambahkan atribut khusus ke simpul di tepi antara dua bioma, tapi sepertinya saya tidak bisa menemukan cara melakukan ini dalam kode shader, jelas noise terlibat di sini, tetapi bagaimana cara membuatnya terus-menerus melintasi beberapa wajah dan seluruh perbatasan beberapa bioma?

Saya melakukan rendering dengan WebGL menggunakan THREE.js


Apakah Anda mencoba MSAA?
Milo Lu

@Milo Sudahkah Anda mencoba membaca pertanyaan?
Bálint

Bagaimana Anda mengirim informasi bioma ke shader?
Bálint

@ Bálint Biome Saat ini saya sedang mengirim warna melalui atribut vertex, ketika saya akan benar-benar mengambil sampel warna dari tekstur nyata, alih-alih warna sederhana, saya akan meneruskan jenis bioma sebagai integer.
user1617735

Atribut Vertex tidak dapat digunakan seperti yang Anda inginkan, jika Anda beralih ke tekstur, ini akan menjadi jauh lebih mudah. Unggah informasi bioma sebagai tekstur, sehingga Anda bisa mendapatkan bioma terdekat
Bálint

Jawaban:


9

Jawaban lain di sini menyarankan menggunakan tekstur. Inilah teknik yang tidak menggunakan tekstur.

Anda ingin batas antara segi enam menjadi menarik. Lebih mudah untuk membuat batas-batas yang menarik ketika Anda memindahkannya ke tengah apa yang Anda gambar. Alih-alih menggambar ubin secara langsung, Anda menggambar "dual" ubin. Teknik ini disebut "ubin sudut" (di sini dan di sini dan di sini ). Ganda dari segi enam adalah segitiga, jadi kita akan menggambar segitiga ini bukannya segi enam:

dual segitiga segi enam

Batas antara segi enam sekarang di tengah segitiga yang diberikan, sehingga akan memungkinkan kita melakukan lebih banyak hal menarik dengan mereka. Bonus: Anda hanya perlu menggambar dua segitiga per segi enam, bukan enam (atau dua puluh empat seperti yang Anda lakukan sekarang).

Di dalam masing-masing segitiga itu kita ingin shader fragmen untuk menggambar segi enam. Kita bisa melakukannya dengan koordinat barycentric . Letakkan (1,0,0), (0,1,0), dan (0,0,1) di setiap sudut segitiga. Di dalam segitiga, koordinat tersebut akan diinterpolasi. Shader fragmen akan menerima (a, b, c) dan dapat melihat untuk melihat nilai mana yang terbesar - yang akan memberi tahu kita yang mana dari tiga segi enam yang harus ditarik pada titik ini.

float max_n = max(barycentric.r, max(barycentric.g, barycentric.b)); if (max_n == barycentric.r) { color = v_color0; } else if (max_n == barycentric.g) { color = v_color1; } else if (max_n == barycentric.b) { color = v_color2; }

Itu untuk garis lurus.

Jika Anda ingin tepi yang bising, Anda dapat menambahkan noise ke koordinat barycentric:

segi enam dengan tepi yang bising

Dengan bermain dengan panjang gelombang amplitudo / frekuensi noise, Anda bisa mendapatkan beberapa efek keren:

segi enam dengan bahkan tepi yang lebih ribut

Anda harus berhati-hati dengan kebisingan, memastikan itu konsisten melintasi batas segitiga. Salah satu cara untuk melakukannya adalah dengan memasukkan hex id dan menggunakannya sebagai nilai seed untuk masing-masing dari tiga nilai noise yang ditambahkan ke koordinat barycentric.

Saya membuat demo interaktif di sini . (Untuk demo saya tidak menerapkan hex id atau beberapa hal lain yang mungkin Anda perlukan jika Anda membuat ini berfungsi dalam proyek nyata - itu hanya demo cepat & kotor)


Nah, itu beberapa bahan jawaban berkualitas terkemuka. Kiat topi
Quentin

Jawaban bagus! Koreksi halus: poligon reguler, termasuk segi enam, bersifat ganda. Namun, tessellations of triangles dan hexagon adalah dual dari satu sama lain, seperti yang digambarkan oleh jawaban Anda.
Erik Foss

0

Saya yakin bahwa "bisa" diselesaikan dengan beberapa algoritma gambar tetapi jika itu saya, saya mungkin akan menyelesaikannya dengan tekstur. Saya akan membuat tekstur heksagonal, menempatkan semuanya dalam atlas tekstur, kemudian untuk setiap segi enam, saya akan melihat tetangganya dan memutuskan tekstur mana yang akan diterapkan.

Tekstur perlu memiliki versi untuk setiap jenis medan plus versi untuk setiap jenis transisi.

Ini mirip dengan berapa banyak sistem berbasis ubin yang melakukan medan. Berikut ini contoh dari game 2d .

Kemungkinan lain adalah hanya memiliki tekstur untuk berbagai jenis medan (air, salju, kotoran, rumput) dan menambahkan jumlah campuran ke setiap titik segi enam untuk memutuskan bagaimana cara mencampurnya.

Artikel ini menunjukkan ide pencampuran tekstur medan. Saya tidak menyarankan mengikuti implementasi mereka tetapi itu menunjukkan ide.


Dalam kasus saya, tidak mudah untuk membuat tekstur, karena segi enam tidak seragam, bentuk dan ukurannya berbeda di seluruh peta. Sayangnya itu harga yang harus saya bayar untuk memiliki planet, bukan hanya peta datar. Juga artikelnya terlihat sangat menarik, terima kasih. Meskipun dalam kasus saya, saya membuat medan dari atas, mungkin dari ketinggian di mana misalnya, Anda tidak dapat melihat satu pohon dan seluruh rongsokan hutan terlihat seperti satu massa greem.
user1617735

0

Pertama, render bioma Anda menjadi tekstur. Petakan segitiga untuk texcoords. Anda dapat melakukan ini menggunakan proyeksi mercator, atau, lebih baik, peta kubus . Sekarang, di shader fragmen, lakukan sesuatu seperti ini:

// frequency and magnitude of the noise in texels.
uniform float frequency;
uniform float magnitude;

// This function should just look like random smooth noise in x,y
// This one isn't great, but you can experiment.
vec2 noise(vec3 vertexPos) {
    return vec2(sin(vertexPos.x * frequency + vertexPos.y * frequency) * magnitude, 
                cos(vertexPos.y * frequency * 2 + vertexPos.z * frequency) * magnitude);
}

// Sample the texture and preturb it with noise based on the world
// position of the fragment.
vec4 frag(vec2 texCoord, vec3 fragmentPos) {
   return texture(mySampler, texCoord + noise(fragmentPos));
}

di mana noiseada beberapa fungsi pseudo-acak (menggunakan, katakanlah, sinusoid) pada posisi 3D dari vertex dalam ruang model yang mengembalikan offset berisik ke koordinat tekstur. Cicipi tekstur yang digunakan GL_NEARESTuntuk menjaga batas yang tajam.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.