- Proyek yang secara otomatis menghasilkan peta pulau bergaya abad pertengahan yang terdiri dari sekitar 4.100 ubin heksagonal menggunakan algoritme Wave Function Collapse (WFC)
- Setiap ubin memuat informasi medan seperti jalan, sungai, pesisir, tebing, hutan, desa, dan dibuat dalam sekitar 20 detik dengan Three.js WebGPU dan shader TSL
- Untuk mengatasi kegagalan yang muncul pada grid skala besar, peta dibagi menjadi 19 subgrid heksagonal, dan dengan backtracking serta sistem pemulihan local-WFC tingkat keberhasilan dijaga di atas 86%
- Dari sisi visual, proyek ini menerapkan material PBR, shader berbasis WebGPU, efek pantulan air dan ombak, serta post-processing (pencahayaan, depth of field, grain) untuk memperkuat kesan tiga dimensi
- Dengan rendering BatchedMesh dan berbagi satu material, ribuan ubin dapat dirender pada 60fps, memperlihatkan potensi gabungan antara generasi prosedural dan grafis real-time
Ikhtisar pembuatan peta prosedural
- Proyek ini terinspirasi dari metode pembuatan dadu dungeon AD&D, dengan pendekatan di mana algoritme membangun dunia sendiri tanpa perlu dirancang langsung oleh pengguna
- Peta yang dihasilkan berbentuk pulau abad pertengahan yang mencakup jalan, sungai, garis pantai, tebing, hutan, desa, dan tersusun dari sekitar 4.100 sel heksagonal
- Seluruh peta diselesaikan dalam waktu sekitar 20 detik menggunakan Three.js WebGPU dan shader TSL
Algoritme Wave Function Collapse (WFC)
- WFC membentuk medan berdasarkan batasan bahwa sisi (edge) ubin yang bersebelahan harus cocok
- Karena ubin heksagonal memiliki 6 sisi, jumlah kondisi batasannya 50% lebih banyak dibanding persegi
- Setiap ubin mendefinisikan tipe sisi 6 arah dan bobotnya; misalnya, persimpangan jalan 3 arah memiliki sisi jalan dan rumput yang berselang-seling
- Algoritme bekerja dengan langkah berikut
- Menginisialisasi semua sel dengan semua status yang mungkin
- Memilih sel yang paling terikat lalu "meruntuhkannya" ke satu status
- Menyebarkan perubahan sambil menghapus status yang tidak mungkin pada sel tetangga
- Mengulang hingga seluruh sel terselesaikan
Grid skala besar dan solusi modular
- Pada grid kecil sistem bekerja stabil, tetapi pada lebih dari 4.000 sel probabilitas gagal meningkat tajam
- Untuk mengatasinya, peta dibagi menjadi 19 subgrid heksagonal, masing-masing diselesaikan secara independen sambil mempertahankan ubin batas sebagai batasan tetap
- Jika batasan pada perbatasan saling bertabrakan, backtracking saja tidak cukup untuk menyelesaikannya
Backtracking dan sistem pemulihan
- Backtracking mengembalikan pilihan yang salah untuk mencoba ubin lain, dan dilakukan hingga maksimal 500 kali
- Namun, konflik antargrid ditangani oleh sistem pemulihan terpisah
- Tahap 1: Unfixing — sel yang bertabrakan dikembalikan ke status variabel, lalu sel di sekitarnya dijadikan batasan baru
- Tahap 2: Local-WFC — area dengan radius 2 sel (19 sel) diselesaikan ulang untuk memastikan kompatibilitas batas, hingga 5 percobaan
- Tahap 3: Drop & Hide — jika tetap gagal, sel tersebut dihapus lalu ditutupi dengan ubin pegunungan agar terlihat alami
- Dengan pemulihan berlapis ini, tingkat keberhasilan pembuatan peta mencapai sekitar 86%
Pemrosesan elevasi 3D
- Peta memiliki 5 tingkat elevasi, dan ubin lereng serta tebing menghubungkan level atas dan bawah
- Jika tersambung dengan salah, dapat muncul kesalahan seperti jalan terputus oleh tebing atau sungai mengalir ke atas
- Informasi elevasi dikodekan sebagai warna instance, sehingga shader dapat mencampur palet warna dataran rendah dan dataran tinggi
Sistem koordinat heksagonal
- Karena struktur 6 arah, heksagon membuat perhitungan ketetanggaan menjadi rumit jika memakai koordinat 2D sederhana
- Untuk itu digunakan koordinat kubus (q, r, s) agar pencarian tetangga lebih sederhana
- Karena WFC lebih berfokus pada struktur graf pencocokan sisi daripada geometri nyata, sistem koordinat terutama dipakai untuk rendering dan penempatan multigrid
Penempatan pohon dan bangunan
- WFC kuat untuk pola lokal, tetapi kurang cocok untuk distribusi skala besar
- Kepadatan pohon dan bangunan ditentukan memakai field noise Perlin agar hutan dan desa membentuk klaster yang alami
- Logika tambahan menempatkan bangunan di ujung jalan, pelabuhan dan kincir angin di pesisir, serta henge di perbukitan
Implementasi efek air
- Laut bukan sekadar bidang datar, tetapi juga mencakup kilau dan ombak pesisir
- Kilau (Sparkles) diimplementasikan dengan tekstur kecil yang bergulir + noise mask alih-alih noise Voronoi, untuk mengurangi beban GPU
- Ombak pesisir (Coast Waves) dibuat dengan mem-blur mask pesisir untuk menghasilkan pita gelombang sinus berbasis jarak
- Pada masalah teluk (Cove), perhitungan jarak berbasis blur kurang akurat, sehingga CPU memeriksa sel sekitar untuk membuat mask area dengan ombak yang dibuat lebih tipis
Pembuatan dan penyelarasan ubin
- Model dasar menggunakan KayKit Medieval Hexagon Pack, tetapi ubin koneksi yang belum tersedia seperti sungai lereng dan variasi tebing dibuat sendiri dengan Blender
- Semua ubin diseragamkan pada lebar 2 unit, dan bila terjadi kesalahan penyelarasan UV, garis batas akan terlihat sehingga pemetaan presisi sangat penting
Efek visual dan rendering
- Dibangun dengan Three.js WebGPU + shader TSL, menggunakan shader berbasis node alih-alih GLSL
- Stack post-processing
- GTAO untuk menonjolkan bayangan
- Depth of Field untuk efek miniatur
- Vignetting dan film grain untuk memberi tekstur analog
- Dynamic shadow map disesuaikan ulang setiap frame mengikuti pandangan kamera agar bayangan tetap tajam saat diperbesar
Optimasi performa
- Dengan BatchedMesh, ubin dan dekorasi pada tiap grid digabung sehingga bisa dirender dengan satu draw call
- Semua mesh berbagi satu material untuk meminimalkan pergantian status shader
- Hasilnya, proyek ini mencapai rendering 38 BatchedMesh, 4.100+ sel, dan 60fps
Angka penting dan tech stack
- 30 jenis ubin, 19 grid, ~4.100 sel, 500 kali backtracking, 5 percobaan Local-WFC, 20 detik generasi, 100% tingkat keberhasilan (500 pengujian)
- Menggunakan Three.js r183, shader TSL, Web Workers, build Vite, BatchedMesh, dan Seeded RNG
Demo dan source
- Di demo live pengguna dapat memperluas peta dan menghasilkan ulang seluruh peta
- Source code GitHub dibuka ke publik, dengan lebih dari 50 parameter untuk mengatur pencahayaan, warna, air, dan konfigurasi WFC
Ringkasan
- Proyek ini menghadirkan pengalaman di mana algoritme, bukan dadu, yang menciptakan dunia, sehingga pengguna bisa menjelajahi medan, jalan, dan koneksi sungai yang selalu berbeda setiap kali
- Sebuah eksperimen pembuatan peta berbasis WebGPU yang menggabungkan generasi prosedural, optimasi grafis, dan teknologi shader
1 komentar
Komentar Hacker News
Dalam artikel ini, backtracking katanya hanya dibatasi sampai 500 langkah, tetapi sebenarnya pemrograman kendala adalah bidang yang sangat menarik dan kompleks
Dengan Algorithm X milik Knuth dan dancing links, sepertinya area "Layer 2" yang disebut di artikel bisa diselesaikan dengan tingkat keberhasilan lebih tinggi dari 86%
Selain itu, dengan menerapkan berbagai heuristik, pencarian bisa dilakukan jauh lebih cepat daripada brute force sederhana. Siapa pun yang pernah membuat solver Sudoku pasti tahu betapa lambatnya brute force bisa menjadi
Misalnya, MiniZinc menyediakan bahasa pemodelan tingkat tinggi yang mendukung berbagai backend solver
Daripada menulis algoritma sendiri, lebih efisien memodelkan masalahnya dengan solver industri seperti ini, lalu membiarkan solver mencari solusi secara acak atau menyeluruh
Dengan begitu, alih-alih menghabiskan waktu menulis solver, kita bisa fokus menyesuaikan definisi masalah untuk membuat peta yang lebih menarik
Di laptop saya (Core i5 generasi ke-11, Iris Xe, Chrome versi terbaru), demo berjalan di 5 FPS. Sepertinya bottleneck-nya ada di GPU
Di artikel disebutkan bahwa ini berjalan di 60 FPS di mobile, jadi saya kira akan lebih efisien
Petanya indah, tetapi kendala per ubin pada WFC membuat hasilnya terasa tidak alami. Sulit merefleksikan pengaruh non-lokal
Untuk game yang menjelajahi ubin satu per satu, ini masih cocok, tetapi kurang pas untuk pembuatan peta secara keseluruhan
Pendekatan berbasis noise dari Red Blob Games menunjukkan hasil yang lebih baik. Sungai bisa ditangani lewat pelacakan kelembapan, dan jalan atau jembatan lewat pass terpisah agar lebih cepat dan tangguh
Meski begitu, WFC tetap masalah pemrograman yang menarik, jadi implementasinya pasti menyenangkan. Secara keseluruhan, artikelnya sangat bagus dan demonya mengesankan
Oskar Stålberg telah memakai Wave Function Collapse (WFC) di beberapa game. Yang paling terkenal mungkin Townscaper
Video presentasi terkait bisa dilihat di SGC21 - Beyond Townscapers
Ini mengingatkan saya pada tutorial Unity Hex Terrain dari Jasper Flick
Proyek ini mencocokkan ubin yang sudah dibuat sebelumnya lewat kondisi kendala, sedangkan tutorial Jasper membuat batas ubin secara dinamis
Kedua pendekatan sama-sama menarik dan enak dibaca
Proyek yang benar-benar keren
Sekadar catatan jika penulis melihat ini: saya penasaran apakah pernah mempertimbangkan merepresentasikan status superposition ubin, yaitu himpunan opsi yang mungkin, sebagai bitfield
Saat dulu saya mengimplementasikan WFC, beralih ke bitfield memberi peningkatan kecepatan yang luar biasa. Menghitung ulang seluruh chunk malah jadi lebih cepat daripada backtracking
Mekanismenya adalah menyimpan status ke stack secara berkala, lalu jika buntu, kembali ke status terakhir
Melihat nama variabel
tenpermembuat saya agak kesal pada diri saya di masa laluSepertinya bagian tersulit adalah menemukan susunan yang memenuhi semua kendala
Saya sempat berpikir apakah ada alternatif menggunakan SAT solver. Hanya saja, kalau begitu mungkin yang ditemukan selalu solusi yang 'mudah' dan tingkat keacakannya menurun
Beberapa SAT solver memang bisa mengacak nilai awal variabel, tetapi itu tidak otomatis berarti solusi akhirnya acak. Saya penasaran apakah ada yang pernah mencoba hal serupa
Sementara itu, WFC adalah pendekatan brute force yang sederhana sehingga mudah diimplementasikan, dan biaya komputasinya rendah selama jumlah jalan buntu tidak terlalu banyak
Dalam game, hasil yang 'cukup bagus' sering kali sudah memadai dibanding solusi sempurna, jadi WFC bisa lebih praktis
Proyek yang menginspirasi. Referensinya juga bagus dan source code-nya dibuka
Akan menarik kalau dipadukan dengan gaya visual dari Here Dragons Abound
Mungkin OP sudah tahu, tetapi halaman matematika Hexagon dari Red Blob Games punya banyak contoh dan kode yang sangat bagus
Menarik melihat eksplorasi WFC pada grid non-square
Kompleksitas propagasi kendalanya tampaknya jauh lebih tinggi daripada contoh-contoh yang biasa
Pada topologi serumit ini, solver kendala lain seperti Constraint Logic Programming mungkin lebih unggul dari sisi ekspresivitas dan performa
Ini mengingatkan saya pada Dorfromantik. Tautan Steam