Teknik Kuas 3D dan Pemahatan Dunia di Dalam Game
Kami ingin pemain dapat memahat dunia. Bukan menempatkan prefab pada grid. Bukan mengaktifkan dan menonaktifkan blok. Melainkan benar-benar membentuk ulang medan: mengukir sungai, meninggikan gunung, menghaluskan sisi tebing, dan menggali gua. Seperti yang dilakukan ZBrush dan mode sculpt Blender untuk seniman, tetapi berjalan pada 60fps di dalam game browser multipemain.
Itu adalah masalah rekayasa sulit yang mencakup representasi data, ekstraksi mesh, komputasi GPU, matematika kuas, dan sinkronisasi jaringan. Panduan ini mendokumentasikan semua yang kami temukan.
Dua Dunia Representasi Medan
Setiap sistem pemahatan dimulai dengan pilihan tentang cara menyimpan data medan. Pilihan tersebut menentukan jenis pengeditan yang dapat dilakukan, seberapa cepat prosesnya berjalan, dan berapa banyak memori yang diperlukan.
Heightmap
Heightmap menyimpan satu nilai ketinggian untuk setiap titik grid. Anda dapat membayangkannya sebagai gambar skala abu-abu dengan tingkat kecerahan yang mewakili elevasi. Medan world/client kami saat ini bekerja tepat seperti ini: noise.ts menghasilkan ketinggian melalui FBM value noise, dan setiap Chunk menyimpan heightmap Float32Array yang diproyeksikan ke PlaneGeometry.
Heightmap itu cepat. Pengambilan sampel hanya memerlukan satu pencarian array dengan interpolasi bilinear. LOD sangat mudah karena Anda cukup mengurangi resolusi grid. Pencampuran tekstur berbasis splat dipetakan langsung ke grid UV. Tabrakan fisika dapat disederhanakan menjadi kueri ketinggian.
Keterbatasannya adalah topologi. Heightmap hanya dapat merepresentasikan satu ketinggian untuk setiap koordinat (x, z). Tidak ada gua. Tidak ada bagian yang menggantung. Tidak ada lengkungan. Tidak ada terowongan. Jika pemain memahat tebing yang melipat kembali ke arahnya sendiri, heightmap tidak dapat menyimpannya. Untuk medan yang sebagian besar berupa perbukitan dan pegunungan, ini tidak menjadi masalah. Namun, untuk pemahatan bentuk bebas yang memungkinkan pemain menggali ke dalam tanah, pendekatan ini menemui jalan buntu.
Volumetrik (Medan Skalar 3D)
Alternatifnya adalah menyimpan nilai pada setiap titik dalam ruang 3D. Jika nilainya negatif di dalam material padat dan positif di luarnya (atau sebaliknya), Anda memiliki Signed Distance Field (SDF). Jika nilainya hanya berupa densitas (di atas ambang tertentu berarti padat, sedangkan di bawahnya berarti kosong), Anda memiliki medan densitas.
Representasi volumetrik dapat menangani topologi apa pun. Gua, bagian yang menggantung, pulau terapung, dan terowongan yang menembus gunung. Konsekuensinya adalah penggunaan memori dan kompleksitas. Grid 256^3 dengan float 32-bit membutuhkan 64 MB. Grid 512^3 membutuhkan 512 MB. Dan itu baru untuk satu chunk. Anda membutuhkan struktur data sparse (octree, brick map) agar pendekatan ini praktis.
Langkah ekstraksi mesh juga tidak sederhana. Anda tidak dapat sekadar menetapkan posisi Y vertex lalu selesai. Anda memerlukan algoritma yang membaca medan skalar dan menghasilkan mesh segitiga yang mendekati permukaan tempat medan melewati nilai nol.
Ekstraksi Mesh: Marching Cubes, Surface Nets, dan Dual Contouring
Marching Cubes
Marching Cubes adalah algoritma ekstraksi isosurface tertua dan yang paling banyak diimplementasikan. Dipublikasikan oleh Lorensen dan Cline pada 1987, algoritma ini bekerja dengan memeriksa setiap kubus dalam grid voxel yang setiap sudutnya memiliki nilai skalar. Jika sebagian sudut berada di dalam permukaan (negatif) dan sebagian lainnya berada di luar (positif), sebuah bagian mesh segitiga ditempatkan di dalam kubus tersebut.
Setiap kubus memiliki 8 sudut yang masing-masing dapat berada di dalam atau di luar, sehingga menghasilkan 256 kemungkinan konfigurasi (2^8). Melalui simetri, konfigurasi tersebut dapat disederhanakan menjadi 15 kasus unik. Sebuah tabel pencarian memetakan setiap kasus ke sekumpulan segitiga. Titik perpotongan edge ditemukan melalui interpolasi linear di sepanjang edge tempat tanda nilainya berubah.
Implementasi GPU terbaru telah membuat Marching Cubes cukup cepat untuk pemahatan real-time. Implementasi UE5 dari 2025 menetapkan setiap thread GPU ke satu kubus sehingga ribuan kubus dapat diproses secara bersamaan. Inti pendekatannya adalah bahwa triangulasi setiap kubus tidak bergantung pada tetangganya, sehingga algoritma ini sangat mudah diparalelkan.
MCHex (arxiv 2511.02064, 2025) memperluas Marching Cubes untuk menghasilkan mesh heksahedral adaptif dengan nilai Jacobian positif yang dijamin, sehingga meningkatkan pendekatan batas untuk mesh simulasi.
rupMC menghasilkan performa puluhan kali lebih cepat daripada implementasi serial dan 4x lebih cepat daripada varian DMC paralel dengan menggunakan arsitektur heterogen CPU/GPU.
Keterbatasan utamanya: Marching Cubes kesulitan menangani fitur tajam. Edge 90 derajat akan dibulatkan menjadi kurva halus. Untuk pemahatan medan, hal ini biasanya dapat diterima (medan alami sebagian besar berbentuk halus), tetapi akan menjadi masalah untuk fitur arsitektural.
Surface Nets
Surface Nets adalah keluarga algoritma yang lebih baru dan menghasilkan mesh lebih halus dari medan skalar diskret. Alih-alih menempatkan vertex pada edge kubus (seperti Marching Cubes), Surface Nets menempatkan satu vertex untuk setiap kubus yang berisi permukaan, lalu menghubungkan vertex yang berdekatan untuk membentuk quad.
Hasilnya secara alami lebih halus. Makalah tahun 2024 (arxiv 2401.14906) mendemonstrasikan implementasi Surface Nets paralel berperforma tinggi yang berjalan satu hingga dua orde magnitudo lebih cepat daripada algoritma sekuensial. Crate Rust fast-surface-nets menghasilkan sekitar 20 juta segitiga per detik pada satu core 2,5 GHz dengan menggunakan tabel pencarian kecil dan akselerasi SIMD.
bevy-sculpter (v0.18.0, Januari 2026) menggunakan Surface Nets sebagai strategi meshing utamanya. Crate tersebut menyediakan pemahatan volumetrik berbasis SDF dengan empat jenis kuas: CSG keras (langsung menambah/menghapus), kontinu halus (untuk input yang ditahan), blur (menghaluskan permukaan), dan flatten (menetapkan ke ketinggian target). Crate ini juga menyertakan redistancing SDF melalui Fast Sweeping Method untuk memulihkan properti signed distance field yang semestinya setelah pengeditan.
Surface Nets merupakan jalan tengah yang baik antara Marching Cubes (sederhana dan cepat, tetapi menghasilkan mesh bergerigi pada data biner) dan Dual Contouring (mempertahankan fitur tetapi kompleks).
Dual Contouring
Dual Contouring mempertahankan fitur tajam yang tidak dapat dipertahankan oleh Marching Cubes dan Surface Nets. Algoritma ini tidak hanya menggunakan tanda medan pada setiap sudut, tetapi juga gradien (normal) pada perpotongan edge. Minimisasi QEF (Quadratic Error Function) menempatkan vertex di dalam setiap sel pada posisi yang paling memenuhi semua batasan perpotongan edge.
Hasilnya: edge dan sudut tajam tetap dipertahankan dalam mesh yang diekstrak. Kubus dengan sisi-sisi tegak lurus tetap berbentuk kubus.
Konsekuensinya adalah kompleksitas. Penyelesaian QEF memiliki dependensi antarsel yang menyulitkan paralelisasi GPU. Algoritma ini dapat menghasilkan mesh non-manifold (edge yang digunakan bersama oleh lebih dari dua poligon). Implementasinya juga lebih rumit daripada Marching Cubes, meskipun Johannes Jendersie menyatakan bahwa implementasi Dual Contouring yang berfungsi membutuhkan sekitar 200 baris kode, dibandingkan dengan lebih dari 500 baris untuk implementasi Marching Cubes yang tangguh.
Cubical Marching Squares (CMS) telah diusulkan sebagai jalan tengah: independen antarsel (ramah GPU), tetapi tetap mampu mempertahankan sebagian fitur.
Mana yang Sebaiknya Digunakan
Untuk pemahatan medan oleh pemain di browser:
Surface Nets adalah kandidat terkuat. Algoritma ini menghasilkan mesh halus (medan yang tampak alami) tanpa artefak bergerigi yang muncul pada Marching Cubes ketika memproses data biner. Performanya cukup cepat untuk melakukan meshing ulang secara real-time. Implementasinya juga lebih sederhana daripada Dual Contouring.
Marching Cubes tetap menjadi pilihan solid ketika paralelisme GPU menjadi prioritas (setiap kubus bersifat independen) atau ketika Anda memerlukan dukungan library terluas. WebGPU SDF Editor karya Reinder Nijhoff (Januari 2026) mengimplementasikan Marching Cubes dan Surface Nets dalam pipeline ekstraksinya, yang sepenuhnya berjalan pada GPU.
Dual Contouring sebaiknya digunakan untuk kasus ketika presisi arsitektural lebih penting daripada performa. Pendekatan ini kurang ideal untuk pemahatan medan real-time dalam konteks browser.
Algoritma Transvoxel: Mengatasi Penyambungan LOD
Ketika medan voxel dibuat menjadi mesh dengan resolusi yang berbeda (LOD0 di dekat pemain, LOD2 di kejauhan), retakan akan terbentuk pada batasnya. Untuk heightmap, ini adalah masalah sederhana: interpolasikan vertex pada edge agar cocok dengan tetangga beresolusi lebih rendah. chunk.ts kami saat ini melakukan hal tersebut dalam stitchEdge().
Untuk medan volumetrik, masalahnya jauh lebih sulit. Mulut gua pada LOD0 mungkin menghasilkan 30 segitiga pada batas. Area yang sama pada LOD1 mungkin menghasilkan 8 segitiga dengan topologi yang sepenuhnya berbeda. Tidak ada cara sederhana untuk melakukan interpolasi linear di antara keduanya.
Transvoxel Algorithm karya Eric Lengyel (2009) mengatasi masalah ini dengan "sel transisi". Pada batas antara dua level LOD, algoritma mempertimbangkan 9 sampel beresolusi tinggi (bukan 8 sudut kubus), sehingga menghasilkan 512 kemungkinan konfigurasi yang terbagi menjadi 73 kelas ekuivalensi. Setiap kelas dipetakan ke pola segitiga yang telah ditentukan sebelumnya dan mengisi celah antara kedua resolusi dengan sempurna.
Algoritma ini beroperasi pada data voxel lokal, sehingga proses triangulasi ulang wilayah yang dimodifikasi berlangsung cepat. Hal ini sangat penting untuk pemahatan real-time: ketika pemain mengedit medan di dekat batas LOD, hanya sel transisi yang perlu dibangun ulang.
Implementasi Rust tersedia sebagai crate transvoxel. Tabel pencarian aslinya tersedia di transvoxel.org.
Matematika Kuas
Kuas pemahat adalah fungsi yang memodifikasi nilai medan skalar dalam radius di sekitar titik target. Matematikanya ternyata sangat mirip di berbagai implementasi, mulai dari Blender dan Unreal Engine hingga sistem game runtime.
Fungsi Falloff
Falloff kuas menentukan bagaimana kekuatan pengeditan berkurang dari pusat ke tepi. Blender 5.1 mendefinisikan profil standar berikut:
Halus: f(d) = 3d^2 - 2d^3 (interpolasi Hermite, smoothstep yang sama seperti dalam noise.ts kami)
Bola: Kuat di pusat dengan falloff curam di dekat batas. Diaproksimasi sebagai f(d) = sqrt(1 - d^2).
Tajam: f(d) = (1 - d)^n dengan n > 2. Menghasilkan ujung yang runcing.
Linear: f(d) = 1 - d, dengan d sebagai jarak ternormalisasi dari pusat (0 di pusat, 1 di tepi).
Konstan: f(d) = 1 untuk d < 1, dengan pemutusan tegas pada batas kuas.
Kuadrat Terbalik: Gabungan antara halus dan bola untuk menghasilkan nuansa alami seperti tanah liat.
Dalam semua kasus, d = distance_to_center / brush_radius, dibatasi ke [0, 1]. Nilai falloff dikalikan dengan kekuatan kuas untuk menghasilkan modifikasi medan yang sebenarnya pada setiap titik.
Ruang Falloff
Blender membedakan antara falloff bola (jarak dihitung dalam ruang dunia 3D) dan falloff terproyeksi (jarak dihitung dalam ruang layar 2D). Falloff terproyeksi berarti dua titik yang tampak berdekatan di layar akan saling memengaruhi dengan kekuatan yang sama, meskipun keduanya berada pada kedalaman yang sangat berbeda dalam ruang dunia. Untuk pemahatan medan, falloff dalam ruang dunia 3D biasanya terasa lebih intuitif.
Operasi Inti Kuas
Naikkan/Turunkan (Displacement): Tambahkan atau kurangi nilai medan skalar dalam radius kuas, dengan pembobotan berdasarkan falloff. Untuk heightmap: height[i] += strength * falloff(d). Untuk SDF: sdf[i] -= strength * falloff(d) (pengurangan membuat material lebih padat dan menaikkan permukaan).
Haluskan (Laplacian): Ganti setiap nilai dengan rata-rata nilai tetangganya, dengan pembobotan berdasarkan falloff. Operasi ini menghapus detail dan mengurangi noise. Filter Laplacian mengambil sampel kernel kecil (3x3 untuk heightmap, 3x3x3 untuk volume) dan memadukannya menuju nilai rata-rata. Penghalusan HC (Humphrey's Classes) adalah varian yang mempertahankan volume lebih baik daripada Laplacian mentah.
Ratakan: Tetapkan nilai medan ke ketinggian target (atau jarak dalam ruang SDF), yang dipadukan berdasarkan falloff. Target biasanya diambil sampelnya dari pusat kuas ketika goresan dimulai, lalu dipertahankan konstan. Operasi ini menghasilkan dataran tinggi yang rata.
Cubit/Gembungkan: Gerakkan vertex menuju atau menjauhi normal permukaan. Dalam ruang SDF, operasi ini setara dengan displacement sepanjang arah gradien.
Tarik: Translasi suatu wilayah pada medan, seolah-olah Anda sedang menarik tanah liat. Vektor displacement berasal dari delta mouse yang diproyeksikan ke ruang dunia, lalu diterapkan pada nilai medan dalam radius.
Noise: Tambahkan noise prosedural pada medan dalam radius kuas. Berguna untuk membuat permukaan halus menjadi lebih kasar.
Stempel: Terapkan gambar skala abu-abu 2D sebagai displacement dengan memproyeksikannya ke permukaan di bawah kursor. Alat Landscape Unreal Engine mendukung teknik ini untuk kuas medan.
Teselasi Adaptif
sculpt-3D (pemahatan berbasis React + Three.js di browser) mengimplementasikan teselasi adaptif: saat kuas bergerak melintasi mesh, segitiga di dekat pusat kuas dibagi lagi untuk menyediakan lebih banyak vertex bagi deformasi. Hal ini mencegah masalah "peregangan low-poly" ketika mesh kasar terdistorsi akibat pemahatan. Pembagian tersebut menggunakan pemisahan simetris agar kualitas segitiga tetap seragam.
Untuk sistem volumetrik, teselasi adaptif tidak diperlukan dengan cara yang sama karena mesh dibuat ulang dari medan. Sebagai gantinya, Anda dapat meningkatkan resolusi voxel secara lokal di dekat area pengeditan (octree adaptif) untuk memperoleh efek yang sama.
Pemahatan SDF: Pendekatan Dreams
Dreams dari Media Molecule (PS4, 2020) adalah sistem pemahatan di dalam game paling ambisius yang pernah dirilis. Alex Evans mempresentasikan pendekatan teknisnya pada SIGGRAPH 2015.
Representasi
Dreams menyimpan geometri sebagai fungsi SDF gabungan dalam blok tekstur volume fp16 berukuran 83^3. Setiap pahatan merupakan daftar berisi 1 hingga 100.000 "pengeditan", dengan setiap pengeditan berupa operasi CSG (tambah, kurangi, warna) yang memiliki bentuk primitif (bola, kubus, silinder, kerucut, elipsoid, torus, dan sebagainya) serta mode blend. Mode perpaduan menggunakan fungsi soft-max dan soft-min. Perpaduan "lunak" menghasilkan transisi membulat antarprimitif (seperti tanah liat yang ditekan hingga menyatu). Perpaduan "keras" menghasilkan potongan boolean yang tegas. Radius perpaduan dapat dikendalikan pengguna.
Rendering
Dreams tidak mengekstrak mesh segitiga. Sebaliknya, Dreams merender langsung dari SDF menggunakan perender point-cloud khusus ("flecks"). Setiap fleck adalah cakram kecil yang diorientasikan mengikuti normal permukaan. SDF diambil sampelnya untuk menemukan permukaan, lalu fleck disebarkan di atasnya. Hal ini sepenuhnya menghindari hambatan kinerja ekstraksi mesh, tetapi membutuhkan perender khusus.
Untuk dunia Three.js/WebGL, pendekatan ini tidak dapat diterapkan secara langsung. Kita perlu mengekstrak mesh. Namun, konsep daftar pengeditan CSG sangat relevan untuk urungkan/ulangi dan sinkronisasi jaringan.
Mesin SDF Dinamis Mike Turitzin (2026)
Sebuah mesin game yang saat ini sedang dikembangkan oleh Mike Turitzin menggunakan SDF dinamis sebagai representasi intinya. Mesin ini mendukung:
Modifikasi mendetail selama permainan: Menambahkan dan menghilangkan materi secara halus atau dengan tepian tajam. Perubahan nondestruktif seperti memindahkan lubang atau membuat terowongan sementara yang menghilang di belakang pemain.
Peta brick dan atlas brick untuk caching renggang. Alih-alih menyimpan seluruh medan SDF dalam grid 3D padat, medan dibagi menjadi "brick" (ubin 3D kecil). Hanya brick yang memuat batas permukaan yang dialokasikan. Hal ini secara drastis mengurangi penggunaan memori untuk adegan yang sebagian besar ruangnya kosong atau padat.
Geometry clipmap (Losasso & Hoppe, SIGGRAPH 2004) untuk LOD. Grid reguler bertingkat dengan resolusi yang makin tinggi mengelilingi posisi kamera. Grid terdalam memiliki resolusi paling tinggi; grid luar menjadi semakin kasar. Pendekatan ini sangat mengurangi penggunaan memori sekaligus mendukung ruang yang sangat luas. Clipmap diperbarui secara inkremental saat kamera bergerak, sehingga efisien untuk streaming dunia terbuka.
Fisika dan tabrakan bekerja langsung terhadap SDF. Sphere-tracing (ray marching dengan jarak SDF sebagai ukuran langkah) memungkinkan raycasting yang efisien. Deteksi tabrakan menggunakan gradien SDF sebagai normal permukaan dan nilai jarak sebagai kedalaman penetrasi.
Teardown: Destruksi Voxel dalam Skala Besar
Teardown (Voxagon) mewakili ujung spektrum yang lain: setiap objek di dunia merupakan volume voxel yang dapat dihancurkan sedikit demi sedikit.
Arsitektur
Objek disimpan sebagai grid voxel dengan jarak teratur. Mesin ini tidak menggunakan Marching Cubes atau SDF untuk rendering. Sebaliknya, mesin melakukan ray tracing langsung pada voxel menggunakan algoritma DDA (Digital Differential Analyzer) yang dimodifikasi dalam fragment shader, dibangun di atas OpenGL 3.3. Mipmap membentuk struktur octree padat untuk mempercepat penelusuran ruang kosong selama perpotongan sinar.
Untuk setiap objek, mesin merasterisasi oriented bounding box (OBB) miliknya dan menelusurkan sinar melaluinya untuk menemukan perpotongan voxel. Hanya sisi belakang OBB yang dirender, sehingga kamera dapat masuk ke dalam volume pembatas.
Sinkronisasi Destruksi (Multipemain)
Pembaruan multipemain Teardown pada Maret 2026 menggunakan pendekatan semideterministik. Destruksi struktural (memotong lubang, mengubah kepemilikan, menyambungkan kembali joint) ditangani melalui matematika bilangan bulat fixed-point pada aliran jaringan yang andal. Semua klien menjalankan perintah deterministik yang sama dan mencapai keadaan dunia yang sama. Perubahan nonstruktural (serpihan, partikel) menggunakan sinkronisasi keadaan yang tidak andal.
Ini merupakan wawasan penting bagi dunia multipemain kita: pengeditan medan harus deterministik. Jika Pemain A memahat gunung, semua klien harus menghasilkan mesh yang sama dari data medan yang sama. Perintah pengeditan (posisi kuas, radius, kekuatan, jenis operasi) harus menjadi data otoritatif, bukan mesh yang dihasilkan.
ALICE-SDF: Kompresi dan Pohon CSG
ALICE-SDF (Adaptive Lightweight Implicit Compression Engine, v1.3.0 Maret 2026) menyediakan implementasi data spasial berbasis SDF dalam Rust dengan kompresi 10–1.000x dibandingkan mesh poligon. ALICE-SDF mendukung:
126 blok pembangun: 72 primitif, 24 operasi, 7 transformasi, dan 23 modifier. Operasi perpaduan halus (union, subtraction, intersection), serta perpaduan chamfer dan tangga untuk bevel bertepi keras dan transisi CSG bertingkat.
Diff/patch pohon CSG untuk urungkan/ulangi dan sinkronisasi jaringan. Inilah fitur utama untuk pemahatan multipemain: alih-alih mengirim seluruh keadaan medan, Anda mengirim diff struktural antara dua pohon CSG. Klien menerapkan patch untuk merekonstruksi keadaan baru. Pendekatan ini jauh lebih hemat bandwidth dibandingkan mengompresi delta data voxel mentah.
Optimalisasi pohon CSG yang mencakup penghapusan transformasi identitas, penggabungan transformasi bertingkat, dan demosi modifier. Hal ini menjaga pohon tetap ringkas seiring menumpuknya pengeditan.
Pembuatan mesh melalui Marching Cubes dan Dual Contouring. Deteksi tabrakan fisika bekerja langsung terhadap SDF.
Dukungan WebAssembly memungkinkan integrasi browser. Mesin ini ditulis dalam Rust dengan binding WASM, sehingga menjadi opsi yang realistis untuk aplikasi Three.js.
Komputasi WebGPU untuk Medan
WebGPU kini tersedia di semua browser utama sejak akhir 2025. Chrome 113+, Edge 113+, Firefox 141+, dan Safari 26+ semuanya menyertakannya dalam keadaan aktif. Hal ini membuka pipeline compute shader yang sebelumnya hanya tersedia di GPU.
Performa
Compute shader WebGPU menghasilkan medan sekitar 100x lebih cepat daripada metode CPU berkat paralelisasi masif. GPU menjalankan ribuan kalkulasi secara bersamaan, dan pembuatan medan hampir sepenuhnya paralel (setiap vertex/voxel bersifat independen).
Pekerjaan diatur dalam tiga tingkatan: Dispatch Level (distribusi beban kerja di seluruh GPU), Workgroup Level (memori bersama dalam unit pemrosesan), dan Thread Level (kalkulasi individual). WGSL (WebGPU Shading Language) adalah bahasa shader yang digunakan.
Pipeline Pemahatan Medan Real-Time
Pipeline pemahatan WebGPU akan terlihat seperti ini:
Penerapan kuas (compute shader): Perbarui nilai medan skalar dalam radius kuas. Setiap thread menangani satu voxel. Baca parameter kuas (posisi, radius, kekuatan, jenis falloff, operasi) dari uniform buffer dan terapkan modifikasi.
Ekstraksi mesh (compute shader): Jalankan Surface Nets atau Marching Cubes pada wilayah yang dimodifikasi. WebGPU SDF Editor karya Nijhoff mengimplementasikannya sebagai pipeline multistage: partisi ruang di 16.384 sel, pemisahan sel berbasis octree, lalu ekstraksi permukaan.
Pembaruan vertex buffer (di sisi GPU): Tulis vertex yang diekstrak langsung ke render buffer tanpa perlu bolak-balik melalui memori CPU.
Penghitungan normal (compute shader): Hitung normal vertex dari mesh atau gradien SDF.
Render (pipeline standar): Gambar mesh dengan material PBR standar.
Langkah 1–4 seluruhnya dapat berjalan di GPU tanpa mengembalikan data apa pun ke JavaScript. CPU hanya perlu mengirim parameter kuas pada setiap frame.
WebGPU SDF Editor
WebGPU SDF Editor karya Reinder Nijhoff (Januari 2026) mendemonstrasikan pendekatan ini berjalan di Chrome. Editor ini mendukung enam primitif (kerucut, silinder, kapsul, torus, kotak, bola), tiga operasi perpaduan (union, subtraction, intersection) dengan perpaduan halus yang dapat dikonfigurasi, serta scene graph hierarkis. Setiap primitif menempati 112 byte dalam satu buffer GPU.
Pipeline rendering menggunakan 1.024 shadow map untuk ambient occlusion dan temporal anti-aliasing. Pipeline ini berjalan pada frame rate interaktif di GPU kelas atas.
Pemahatan Heightmap: Jalur yang Lebih Sederhana
Jika dukungan gua dan bagian yang menjorok tidak diperlukan, pemahatan heightmap dapat menghindari seluruh pipeline volumetrik. Inilah cara sebagian besar game yang telah dirilis menangani pengeditan medan.
Pola Implementasi Runtime
Unity Runtime Terrain (JohannHotzel, Januari 2026) mendemonstrasikan pola standar:
- Lakukan raycast dari kamera melalui posisi mouse untuk menemukan titik perkenaan pada medan.
- Petakan titik perkenaan ke koordinat heightmap.
- Terapkan kuas ke nilai heightmap di sekitarnya, dengan bobot berdasarkan falloff.
- Perbarui mesh dengan mengatur posisi Y vertex berdasarkan heightmap yang telah dimodifikasi.
- Bangun ulang collider fisika agar sesuai dengan mesh baru.
Untuk medan Three.js kita, langkah 1–4 dapat dipetakan langsung ke arsitektur yang ada. Kelas Chunk sudah menyimpan heightmap dan membangun mesh darinya. Menambahkan pemahatan berarti menyediakan:
- Sistem raycasting terhadap mesh chunk (Three.js
Raycaster) - Fungsi penerapan kuas yang memodifikasi nilai
chunk.heightmap - Pembaruan vertex mesh (atur posisi Y, hitung ulang normal)
- Penghitungan ulang splat map untuk wilayah yang terdampak (agar perpaduan tekstur mencerminkan kemiringan/ketinggian baru)
- Broadcast pengeditan melalui jaringan (posisi kuas, radius, kekuatan, operasi) ke klien lain melalui protokol WebSocket yang sudah ada
Pendekatan Clipmap
Landow.dev menjelaskan "wandering clipmap" untuk medan heightmap: satu mesh dengan kepadatan subdivisi bervariasi yang mengikuti pemain. Alih-alih membagi heightmap menjadi mesh terpisah dengan tingkat LOD berbeda (seperti yang kita lakukan sekarang), clipmap merupakan mesh kontinu yang rapat di dekat kamera dan kasar di bagian tepi.
Hal ini sepenuhnya menghilangkan penyambungan LOD. Mesh hanya memiliki lebih banyak segitiga di tempat yang membutuhkannya dan lebih sedikit di tempat yang tidak. Konsekuensinya, pemahatan perlu memperbarui satu mesh besar, bukan masing-masing chunk, yang dapat memakan biaya besar untuk pengeditan berskala luas.
Heightmap SDF Nondestruktif
Landow.dev juga menjelaskan teknik yang menghasilkan heightmap itu sendiri dari komposisi SDF. Instans bentuk (bola, kotak, fungsi noise) dikomposisikan dalam compute shader menggunakan operasi CSG, lalu output-nya diambil sampelnya sebagai heightmap. Pendekatan ini menyediakan pengeditan nondestruktif (Anda dapat memindahkan atau menghapus instans bentuk apa pun kapan saja) sekaligus mempertahankan kesederhanaan rendering heightmap.
Ini merupakan pendekatan hibrida yang menarik: representasi datanya bersifat volumetrik (pohon CSG SDF), tetapi jalur rendering-nya menggunakan mesh heightmap standar. Anda memperoleh fitur urungkan/ulangi dan operasi pengeditan yang ramah jaringan dari sisi SDF, serta rendering dan fisika sederhana dari sisi heightmap. Keterbatasannya tetap sama: tidak ada gua atau bagian yang menjorok.
Sparse Voxel Octree untuk Dunia Luas
Grid 3D padat tidak dapat diskalakan dengan baik. Dunia berukuran 1 km pada setiap sisinya dengan resolusi 0,5 m akan membutuhkan 8 miliar voxel. Sparse Voxel Octree (SVO) mengatasi hal ini dengan membagi ruang secara rekursif dan hanya mengalokasikan penyimpanan untuk oktan yang memuat batas permukaan.
SVO secara alami menyediakan LOD hierarkis: kedalaman pohon di titik mana pun menentukan resolusi efektif. Di dekat pemain, pohon dikembangkan sepenuhnya (detail maksimum). Di kejauhan, pohon dipangkas pada tingkat yang lebih kasar.
Untuk rendering, SVO dapat di-ray-trace secara langsung (tidak memerlukan ekstraksi mesh). GPU ray marcher memotongkan sinar dengan kotak yang sejajar sumbu pada setiap tingkat pohon, sambil sepenuhnya melewati subtree kosong. Hal ini menghilangkan masalah overdraw pada rendering berbasis chunk dan menghindari artefak greedy meshing.
Pembangun SVO berbasis Vulkan karya AdamYuan menunjukkan performa yang signifikan: waktu pembangunan 19 md untuk Crytek Sponza pada resolusi 2^10 di GTX 1660 Ti.
Untuk pemahatan, modifikasi SVO berlangsung efisien: hanya node daun di dalam radius kuas yang perlu diperbarui, dan struktur pohon secara alami menangani resolusi yang bervariasi. Penambahan detail di tempat pemain memahat (membagi node ke resolusi yang lebih tinggi) dan pengurangan detail di tempat yang dihaluskan (menggabungkan node ke resolusi yang lebih rendah) muncul secara alami dari struktur data tersebut.
Tantangan untuk deployment di browser adalah WebGL tidak mendukung compute shader. Meskipun WebGPU mendukungnya, algoritma konstruksi dan penelusuran SVO rumit untuk diimplementasikan dalam WGSL.
Sinkronisasi Jaringan untuk Pemahatan Multipemain
Dunia kita sudah memiliki fitur multipemain melalui Cloudflare Durable Objects (world-chunk-do.ts). Menambahkan pemahatan berarti menyinkronkan modifikasi medan di antara semua klien yang terhubung.
Kompresi Delta
Mengirim data voxel mentah membutuhkan biaya besar. Studi tahun 2024 dari Universitas Oulu mencapai peningkatan payload 2–8x dengan menggabungkan delta-encoding dan kompresi DEFLATE, mengemas pembaruan voxel menjadi kurang dari satu byte per voxel. Codec SDEC mendemonstrasikan delta encoding yang dikemas dalam bit, dengan paket rata-rata 259 byte dibandingkan 1.114 byte menggunakan serialisasi generik.
Sinkronisasi Berbasis Operasi (Direkomendasikan)
Alih-alih menyinkronkan keadaan medan, sinkronkan operasinya. Setiap tindakan pemahatan menjadi pesan:
interface TerrainEditMsg {
t: MsgType.TerrainEdit
brush: {
position: [number, number, number]
radius: number
strength: number
falloff: 'smooth' | 'linear' | 'sharp' | 'constant'
operation: 'raise' | 'lower' | 'smooth' | 'flatten' | 'noise'
targetHeight?: number
}
}Server menyiarkan pesan ini ke semua klien, lalu setiap klien menerapkan operasi kuas deterministik yang sama pada data medan lokalnya. Ini adalah pendekatan yang sama dengan yang digunakan Teardown untuk destruksi struktural: perintah deterministik pada aliran yang andal.
Diff/patch pohon CSG ALICE-SDF membawa pendekatan ini lebih jauh: alih-alih goresan kuas individual, diff merepresentasikan perubahan struktural pada seluruh pohon CSG. Hal ini memungkinkan urungkan/ulangi secara efisien melalui jaringan (kirim patch invers) dan klien yang terlambat bergabung dapat merekonstruksi keadaan dunia secara penuh dengan memutar ulang log operasi.
Prioritas dan Pembatasan Laju
Pengeditan medan di dekat pemain yang terhubung harus berprioritas tinggi (langsung disiarkan). Pengeditan yang jauh dari pemain mana pun dapat dikelompokkan dan dikirim dengan frekuensi lebih rendah. Jaringan voxel Enshrouded menggunakan pola ini: pembaruan 60 Hz untuk medan di dekat pemain dan 10 Hz untuk wilayah latar belakang.
Kompresi ZSTD pada transmisi jaringan mengurangi ukuran paket hingga 60% untuk pesan pembaruan medan.
Pemahatan Kolaboratif: Pengeditan Bersamaan
Saat beberapa pemain memahat wilayah yang sama secara bersamaan, Anda memerlukan penyelesaian konflik. cSculpt (CNR Visual Computing Lab, 2016) mengatasinya dengan algoritma penggabungan multiresolusi. Setiap pengeditan direpresentasikan pada beberapa skala, lalu pengeditan bersamaan yang tumpang tindih digabungkan dengan memadukan representasi multiresolusinya. Untuk kebutuhan kita, pendekatan yang lebih sederhana sudah memadai: penulisan terakhir yang menang dengan pengurutan oleh server. Durable Object memberi stempel waktu pada setiap pengeditan dan menyiarkannya secara berurutan. Semua klien menerapkan pengeditan dalam urutan yang sama. Karena sapuan kuas berukuran kecil, terlokalisasi, dan bersifat menambah/mengurangi, hasil visual dari pengeditan bersamaan yang urutannya sedikit berubah biasanya tidak dapat dibedakan dari urutan yang "benar".
INST-Sculpt: Pengeditan SDF Neural (Garda Depan Riset)
INST-Sculpt (arxiv 2502.02891, Februari 2025) memungkinkan pengeditan SDF neural berbasis sapuan. Pengguna menggambar sapuan pada permukaan, lalu sistem mendeformasi medan neural yang mendasarinya di sepanjang area tubular di sekitar jalur sapuan. Profil kuas khusus (penampang lintang yang dapat dikonfigurasi) mengendalikan bentuk deformasi.
Hal ini menarik untuk medan yang dihasilkan AI: jika dunia dasar direpresentasikan sebagai SDF neural (jaringan neural kecil yang memetakan koordinat 3D ke jarak bertanda), pemahatan memodifikasi bobot jaringan alih-alih data voxel eksplisit. Representasinya sangat ringkas (beberapa MB untuk seluruh dunia), tetapi evaluasinya lebih mahal daripada tabel pencarian.
Teknologi ini masih berada pada tahap riset. Biaya inferensi SDF neural pada perangkat konsumen saat ini terlalu tinggi untuk penggunaan gim waktu nyata. Namun, teknologi ini patut dipantau, terutama seiring meningkatnya kemampuan shader WebGPU dan semakin cepatnya inferensi model.
World Creator 2026.3: Mutakhir dalam Medan Komersial
World Creator (BiteTheBytes, Maret 2026) merepresentasikan teknologi mutakhir komersial untuk alat pembuatan medan. Versi 2026.3 menambahkan pembuatan medan berbasis GPU dengan adaptasi medan otomatis (medan menyesuaikan diri dengan objek yang ditempatkan), distribusi objek yang berfokus pada kamera untuk pengoptimalan LOD, dan impor data elevasi dunia nyata (GeoTIFF, HGT, DTED).
Sejak itu, World Creator 2026.4 (28 April 2026) menambahkan ekspresi matematis dalam kolom numerik, pencampuran normal medan untuk menyatukan objek utama dengan permukaan, dukungan penuh untuk decal, dan penskalaan VRAM yang menyesuaikan jumlah maksimum objek dengan memori GPU yang tersedia. BiteTheBytes juga merilis Community Edition gratis yang memiliki fitur lengkap tetapi ekspornya dinonaktifkan, sehingga secara efektif menjadi versi uji coba tanpa batas waktu.
Pendekatan mereka menggunakan komputasi GPU untuk semua operasi medan: simulasi erosi, pengukiran sungai, dan pengecatan tekstur. Alat kuasnya diakselerasi GPU dengan umpan balik viewport waktu nyata. Ini sesuai dengan pipeline komputasi WebGPU yang dijelaskan di atas, yang dijalankan pada GPU desktop.
Yang Telah Kita Bangun: 24 Spike dan Sebuah Dunia Produksi
Direktori world/spikes/ berisi 24 prototipe mandiri. Ini bukan demo mainan. Semuanya merupakan pipeline R&D progresif, dengan setiap spike menyelesaikan masalah tertentu, mengukur performanya terhadap target, dan menjadi dasar untuk spike berikutnya. Sistem pemahatan dibangun di atas semuanya, bukan hanya spike volumetrik yang lebih baru.
Medan Heightmap Produksi (world/client/)
Dunia aktif menggunakan sistem heightmap berbasis chunk di Three.js WebGL:
noise.tsmenghasilkan ketinggian medan melalui FBM value noise (5 oktaf untuk perbukitan, 4 untuk punggung bukit, 3 untuk detail mikro) dengan fungsiterrainHeight(wx, wz)yang deterministikchunk.tsmembuat meshPlaneGeometrydari heightmapFloat32Arraydengan 3 tingkat LOD (32/8/4 segmen per chunk berukuran 64 unit), serta menempatkan pohon/billboard terinstansiasi menggunakan penempatan acak berbasis seed dan collider per objekchunk-manager.tsmelakukan streaming chunk dalam bentuk cincin di sekitar pemain (radius 1 pada LOD0, radius 3 pada LOD1, radius 6 pada LOD2) dengan penyambungan tepi melalui interpolasi linear distitchEdge(), serta menyediakangetHeight(),getNormal(), danresolveCollisions()untuk lapisan fisikaterrain-material.tsmelakukan pencampuran tekstur berbasis splat dengan 4 lapisan (rumput/batu/pasir/tanah) melaluiMeshStandardMaterial.onBeforeCompile, menggunakan bobot berdasarkan kemiringan dan ketinggian, ditambah pencampuran normal map per lapisancharacter-controller.tsmengambil sampel ketinggian medan setiap frame untuk gravitasi, pijakan, dan penolakan lereng (kosinus kemiringan maksimum 50 derajat). Pemahatan harus segera memasukkan ketinggian yang telah dimodifikasi ke sistem ini atau pemain akan jatuh menembus medan yang dieditplacement.tssudah memilikiRaycasteryang mengenai mesh chunk untuk alat penempatan objek. Alat kuas harus mengikuti pola yang sama persis, alih-alih membangun raycasting dari awalprotocol.tsmendefinisikan pesan berkode MessagePack untuk sinkronisasi multipemain melalui Durable Objectworld-chunk-do.ts, yang saat ini menangani pesanPlayerState,PlaceObject,RemoveObject, danSnapshot. Pengeditan medan akan memerlukan jenis pesan baruworld-chunk-do.ts(Cloudflare Worker) menyimpan objek yang ditempatkan ke penyimpanan Durable Object dan menyiarkannya kepada pemain yang terhubung dalam interval 50 md. Saat ini sistem tersebut belum memiliki konsep modifikasi medan
Spike 01-11: Lapisan Fondasi
Spike-spike ini memvalidasi sistem inti yang akan menjadi tumpuan pemahatan. Melewatinya berarti mengabaikan batasan yang harus dipatuhi oleh sistem pemahatan.
Spike 01 (Medan + Instancing): Prototipe medan pertama di Three.js. Menetapkan pola PlaneGeometry + heightmap dan penempatan objek terinstansiasi yang masih digunakan oleh chunk.ts.
Spike 02 (Worker Fisika Rapier): Rapier 3D berjalan di dalam Web Worker dengan collider ColliderDesc.heightfield(). Spike ini membangun pengontrol karakter kinematik dengan langkah otomatis, batas kemiringan, dan penempelan ke permukaan tanah. Spike ini membuktikan bahwa fisika dapat berjalan di luar thread utama terhadap sebuah heightfield. Jika kita memahat medan, heightfield fisika harus dibuat ulang atau diganti dengan collider trimesh untuk chunk MC.
Spike 05 (Perilaku LLM): Tidak berkaitan langsung dengan medan, tetapi menetapkan skema perilaku JSON untuk objek gim. Ini relevan karena fitur medan hasil pahatan dapat memicu perilaku (misalnya, sungai yang diukir memunculkan efek air).
Spike 06 (Streaming Chunk): Sistem pemuatan/pertukaran chunk pertama dengan pemuatan dinamis saat pemain bergerak. Menetapkan pola yang digunakan oleh chunk-manager.ts: wilayah berwarna yang dimuat dan dibongkar. Pemahatan harus mempertahankan status pengeditan ketika chunk dibongkar dan dimuat kembali.
Spike 07 (Vegetasi GPU dari Peta Kepadatan): Rumput dan pohon terinstansiasi yang ditempatkan melalui peta kepadatan dengan mengambil sampel ketinggian dan kemiringan medan. Pemahatan membuat penempatan vegetasi tidak lagi valid: jika ketinggian medan berubah, pohon dapat berakhir melayang atau terkubur. Peta kepadatan harus dibuat ulang untuk chunk yang diedit.
Spike 08 (Biaya Shader Material Medan): Mengukur performa proyeksi triplanar, normal map, dan pencampuran 4 lapisan. Mengukur biaya setiap fitur secara presisi dalam milidetik. Ditemukan bahwa triplanar + normal + 4 lapisan tetap sesuai anggaran pada 45+ FPS. Anggaran ini penting bagi medan terpahat: jika kita menambahkan lapisan ke-5 untuk "tanah yang diedit" atau mengubah pencampuran untuk permukaan yang diukir, kita tahu persis berapa banyak ruang performa yang tersedia.
Spike 09 (Anggaran Bayangan CSM): Cascaded shadow map dengan 3 cascade pada resolusi 1024^2. Biaya bayangan terukur sekitar 1,5 md. Medan terpahat mengubah shadow map, tetapi biayanya tetap konstan terlepas dari bentuk medan.
Spike 10 (Clipmap Geometri + Geomorphing): Cincin clipmap bertingkat dengan geomorphing di antara tingkat LOD untuk menghilangkan kemunculan mendadak. Jumlah segitiga yang konstan menghasilkan biaya GPU yang dapat diprediksi. Geomorphing penting bagi pemahatan: ketika pemain memahat di dekat batas LOD, transisi morf di antara tingkat LOD harus mencerminkan pengeditan tersebut. Jika pengeditan hanya ada di cincin beresolusi tinggi, target geomorph akan salah.
Spike 11 (Streaming Chunk Heightmap): Streaming chunk yang lebih canggih dengan kisi visual yang menunjukkan status dimuat/sedang dimuat/tidak dimuat pada setiap tingkat LOD. Menetapkan anggaran streaming: jumlah maksimum chunk yang dimuat per frame dan prioritas chunk yang memerlukan peningkatan LOD. Pemahatan menambahkan sinyal prioritas baru: chunk yang sedang aktif diedit oleh pemain tidak boleh dibongkar.
Spike 12-14: Integrasi WebGPU + Three.js
Spike 12 (Marching Cubes WebGPU): Spike volumetrik pertama. Empat chunk SDF berukuran 64^3 dengan gua berbentuk bola yang dianimasikan, berjalan sepenuhnya di GPU. Menggunakan WebGPU mentah: pipeline komputasi untuk evaluasi SDF, ekstraksi MC dengan tabel kasus Twinklebear (256 konfigurasi, masing-masing 16 entri), penghitung vertex atomik, dan indirect draw. Target performanya adalah <4 md per chunk, <12 md untuk keempatnya. Ini memvalidasi bahwa MC GPU cukup cepat untuk remeshing waktu nyata di browser. Setiap spike volumetrik berikutnya menggunakan kembali tabel kasus MC dan shader WGSL yang didefinisikan di sini.
Spike 13 (Reset Baseline dari Spike 12): Memindahkan jalur penggambaran WebGPU mentah milik Spike 12 agar berjalan di dalam WebGPURenderer Three.js, dengan mengakses device backend secara langsung. Pipeline rendering tetap menggunakan WebGPU mentah (drawIndirect dengan struct Vertex vec4+vec4). Ini membuktikan bahwa komputasi khusus dan rendering scene Three.js dapat berjalan berdampingan pada perangkat GPU yang sama.
Spike 14 (Penguatan Inkremental WebGPU Three.js): Mengganti pipeline rendering mentah dengan StorageBufferAttribute Three.js untuk posisi dan normal. Komputasi MC menulis langsung ke buffer yang berada di GPU ini. Buffer drawIndirect mengendalikan jumlah vertex yang digambar Three.js. Ini adalah pola yang digunakan semua spike berikutnya: komputasi tetap menggunakan WebGPU mentah, sedangkan rendering dilakukan melalui scene graph Three.js. Versi Three.js di seluruh spike ini berkembang dari 0.170.0 menjadi 0.172.0 seiring stabilnya backend WebGPU.
Spike 15-17: Penyambungan LOD Transvoxel
Spike 15 (Kerangka Seam Transvoxel): Menambahkan arsitektur tiga zona: chunk MC (pusat volumetrik), strip transisi (seam antara batas MC dan heightmap), serta cincin medan (heightmap di sekelilingnya). Ketiganya menggunakan pass material yang sama. Pada tahap ini, strip transisi masih berupa mesh pengganti, bukan sel Transvoxel yang sebenarnya.
Spike 16 (Sisi +X Transvoxel dengan Heightmap Bersama): Dua terobosan penting dalam satu spike. Pertama, mengganti bidang medan datar di SDF dengan heightmap Perlin bersama: sebuah Float32Array 257x257 yang diunggah ke GPU sebagai buffer penyimpanan dan diambil sampelnya melalui interpolasi bilinear di shader komputasi SDF. Permukaan MC dan mesh heightmap kini menyepakati sumber data kebenaran yang sama. Kedua, mengimplementasikan sel transisi Transvoxel sebenarnya untuk sisi +X dengan mengambil tabel data referensi Eric Lengyel dari GitHub (transitionCellClass, transitionVertexData, transitionCellData) dan paket npm transvoxel-data. CPU mengevaluasi sel transisi 9 sampel (512 konfigurasi, 73 kelas ekuivalensi), menempatkan vertex dengan menginterpolasi nilai SDF pada titik kisi, dan menangani pembalikan winding untuk kasus yang dicerminkan.
Spike 17 (LOD MC Ganda 1x/2x): Dua chunk MC berdampingan dengan resolusi berbeda. Resolusi tinggi: 62 sel dengan cell_scale=1.0. Resolusi rendah: 31 sel dengan cell_scale=2.0. Shader MC mendapatkan uniform cell_scale dan grid_points. Memperkenalkan transition_shrink: vertex batas face-0 pada chunk beresolusi rendah ditarik ke dalam sebesar 15% dari cell_scale, sehingga menciptakan celah tipis yang diisi oleh sel transisi Transvoxel tanpa z-fighting. Inilah model LOD yang dibutuhkan sistem produksi: chunk dekat menggunakan resolusi penuh, chunk jauh menggunakan separuh resolusi, dan Transvoxel pada setiap batas.
Spike 18-21: Kasus Sudut Transvoxel dan Akselerasi GPU
Keempat spike ini masing-masing menyelesaikan kasus kegagalan tertentu dalam implementasi Transvoxel. Mengelompokkannya akan mengaburkan perbedaan masalah yang diselesaikan.
Spike 18 (Seam Heightmap 2:1): Menerapkan Transvoxel pada batas heightmap murni, dengan satu sisi memiliki resolusi dua kali sisi lainnya. Tidak ada MC yang terlibat. Seam antara chunk heightmap 62 sel dan 31 sel dihasilkan dari tabel transisi Transvoxel dengan penyusutan sisi beresolusi rendah sebesar 15%. Ini memvalidasi bahwa Transvoxel berfungsi untuk kasus yang hanya menggunakan heightmap, bukan hanya MC.
Spike 19 (Kisi Sudut 64/32/32/16): Kasus penyambungan tersulit: empat chunk dengan resolusi berbeda bertemu di satu titik sudut (64, 32, 32, dan 16 sel). Sistem seam harus menghasilkan sel transisi di sepanjang empat tepi (A-B, A-C, B-D, C-D) dengan winding yang benar untuk setiap arah. Spike ini membuktikan bahwa tabel Transvoxel menangani sudut multiresolusi tanpa logika kasus khusus.
Spike 20 (Sudut Transvoxel GPU): Memindahkan pembuatan sel transisi Transvoxel ke GPU untuk tata letak sudut 64/32/32/16. CPU menjadi bottleneck ketika membuat ulang sel transisi setiap frame untuk medan yang dianimasikan. Komputasi GPU menghasilkan vertex seam dalam pass yang sama dengan ekstraksi MC.
Spike 21 (Sudut GPU MC + Transvoxel): Menggabungkan ekstraksi MC GPU penuh dengan pembuatan seam Transvoxel GPU dalam satu rangkaian dispatch komputasi. Chunk MC dan keempat seam dihasilkan di GPU, dengan jumlah vertex dikelola melalui penghitung atomik dan digambar menggunakan drawIndirect. Ini adalah pipeline GPU lengkap untuk medan volumetrik multiresolusi dengan transisi LOD tanpa celah.
Spike 22-24: Arsitektur Hibrida
Spike 22 (Kebijakan Hibrida MC/Heightmap): Spike arsitektur utama. Secara default, chunk menggunakan heightmap. Ketika bola deformasi yang dianimasikan beririsan dengan AABB sebuah chunk, chunk tersebut beralih ke mode MC. Chunk lainnya tetap berupa mesh heightmap statis. Tata letak: chunk 64, 32/32, dan 16 sel pada resolusi berbeda. Seam Transvoxel menangani setiap batas, termasuk transisi MC-ke-heightmap. Spike ini melacak jumlah chunk MC dibandingkan chunk HM dan luapan vertex per frame.
Spike 23 (Mode Chunk Berbasis Kebijakan): Dimuat sebagai patch di atas Spike 22. Menambahkan histeresis berdasarkan jarak kamera (chunk tidak berubah-ubah cepat di antara mode ketika kamera berada dekat ambang batas) dan mask pengeditan (chunk yang telah dideformasi tetap berada dalam mode MC meskipun sumber deformasi berpindah menjauh). Inilah perilaku "pengeditan persisten" yang dibutuhkan pemahatan: setelah pemain mengukir gua, chunk tersebut tetap volumetrik selamanya.
Spike 24 (Kebijakan + Cincin Clipmap): Spike tercanggih. Menggabungkan sistem kebijakan medan dekat dari Spike 23 dengan cincin clipmap geometri medan jauh dari Spike 10. Ditingkatkan ke Three.js 0.183.1. Medan dekat menggunakan hibrida HM/MC dengan seam Transvoxel pada resolusi 64/32/16. Medan jauh menggunakan cincin clipmap berpusat statis yang mengikuti kamera. Ini adalah arsitektur rendering medan lengkap: pemahatan volumetrik berbasis chunk di tempat yang dibutuhkan dan medan clipmap murah di area lainnya.
Mengapa Marching Cubes, Bukan Surface Nets
Bagian riset eksternal dalam panduan ini menyarankan Surface Nets sebagai kandidat terkuat untuk pemahatan medan di browser. Namun, setiap spike dalam pipeline menggunakan Marching Cubes. Itu bukan kebetulan.
Keunggulan utama MC adalah paralelisme yang sangat mudah: setiap kubus sepenuhnya independen. Shader komputasi WGSL dalam Spike 12-24 menjalankan satu thread per kubus tanpa komunikasi antarsel. Penghitung atomik menangani alokasi verteks. Pendekatan ini sangat cocok dengan workgroup GPU.
Surface Nets menempatkan satu verteks per sel yang mengandung permukaan, lalu menghubungkannya dengan sel tetangga. Konektivitas tetangga tersebut merupakan dependensi antarsel. Crate fast-surface-nets menanganinya di CPU dengan urutan iterasi yang cermat. Di GPU, metode ini memerlukan pendekatan dua tahap (menemukan verteks, lalu menghubungkannya) atau memori bersama di dalam workgroup. Keduanya dapat dilakukan di WebGPU, tetapi menambah kompleksitas.
Rekomendasi praktisnya: tetap gunakan Marching Cubes untuk pipeline pemahatan. Metode ini telah terbukti di codebase kami, shader WGSL-nya sudah tersedia dan telah di-benchmark, serta sistem sambungan Transvoxel dibangun berdasarkan penempatan verteks berbasis sisi milik MC. Surface Nets layak dipertimbangkan kembali jika aliasing MC pada data biner menjadi masalah yang terlihat, tetapi untuk medan SDF dengan nilai berupa gradien halus, MC menghasilkan permukaan yang bersih.
Arsitektur Praktis untuk Pemahatan
Rangkaian spike telah menyelesaikan pipeline rendering. Yang tersisa adalah sistem kuas, efek samping berantai di seluruh sistem game, dan sinkronisasi multipemain. Berikut rencananya, yang dibangun berdasarkan setiap spike.
Fase 1: Pemahatan Heightmap (Perubahan Minimal, Jangkauan Maksimal)
Tambahkan alat kuas yang memodifikasi heightmap chunk dalam kode produksi world/client/. Pendekatan ini bekerja dengan renderer WebGL yang sudah ada dan tidak memerlukan WebGPU.
Input kuas: Ikuti pola PlacementTool dalam placement.ts. Pola tersebut sudah memiliki Raycaster yang mengenai chunkManager.getChunkMeshes() dan melacak mesh bayangan pada titik tumbukan. TerrainBrushTool akan melakukan raycast yang sama, tetapi memodifikasi heightmap chunk alih-alih menempatkan objek. Handler World.onMouseDown sudah meneruskan tindakan berdasarkan status alat.
Modifikasi chunk (Chunk.applyBrush): Petakan posisi kuas di dunia ke koordinat kisi heightmap. Untuk setiap titik kisi di dalam radius kuas, hitung perpindahan berbobot falloff, lalu tambahkan atau kurangi nilainya dari heightmap. Setelah itu, perbarui mesh: atur posisi Y verteks dari heightmap yang telah dimodifikasi, hitung ulang normal melalui diferensiasi terpusat (pola terrainHeight(wx +/- eps, wz) yang sama seperti yang sudah digunakan dalam chunk.ts baris 155-158), lalu buat ulang splat map melalui createSplatMap() dalam terrain-material.ts untuk area terdampak agar perpaduan tekstur berbasis kemiringan ikut diperbarui.
Pengontrol karakter: CharacterController.update() memanggil getHeight() pada setiap frame untuk menentukan pijakan. ChunkManager.getHeight() mendelegasikan ke Chunk.sampleHeight(), yang membaca dari Float32Array heightmap milik chunk. Karena kita memodifikasi array tersebut secara langsung, pengontrol karakter akan mendeteksi perubahan pada frame berikutnya tanpa wiring tambahan.
Invalidasi objek: Instance pohon dalam chunk.ts ditempatkan dengan mengambil sampel terrainHeight() saat spawn. Setelah pemahatan, pohon di area terdampak mungkin berada pada ketinggian yang salah. Fase 1 dapat menunda penanganan ini (pohon hanya sedikit melayang pada edit kecil). Fase 2 memerlukan chunk.invalidateObjects() yang mengambil ulang sampel ketinggian dan membangun kembali matriks instance. Hal yang sama berlaku untuk collider yang digunakan dalam resolveCollisions().
Fisika Rapier (jika terintegrasi): Spike 02 membuktikan bahwa collider heightfield berfungsi. Jika Rapier aktif, collider heightfield harus dibangun ulang atau di-patch untuk chunk yang dimodifikasi. ColliderDesc.heightfield() milik Rapier menerima Float32Array datar, sehingga collider dapat langsung diganti.
Sinkronisasi jaringan: Tambahkan MsgType.TerrainEdit = 10 ke protocol.ts:
interface TerrainEditMsg {
t: MsgType.TerrainEdit
cx: number
cz: number
brush: {
wx: number
wz: number
radius: number
strength: number
falloff: number
operation: number
}
}WorldChunkDO menyiarkannya kepada semua klien dan menambahkannya ke log edit per chunk yang disimpan dalam penyimpanan Durable Object. Klien yang bergabung belakangan menerima log edit dalam pesan Snapshot dan memutarnya kembali untuk merekonstruksi status medan. Semua klien menerapkan fungsi kuas deterministik yang sama, sehingga semuanya menghasilkan heightmap yang sama.
Pelepasan/pemuatan ulang chunk: Spike 06 dan Spike 11 menetapkan pola streaming. Saat sebuah chunk dilepas lalu dimuat ulang, log edit untuk chunk tersebut harus diputar kembali pada heightmap prosedural dasar. Log edit disimpan di sisi server (Durable Object) dan disertakan dalam pesan Snapshot.
Fase 2: Pemahatan Volumetrik dengan Arsitektur Spike 22-24
Port pipeline Spike 24 ke dunia produksi. Saat pemain memahat di bawah permukaan (membentuk gua atau menggali terowongan), chunk terdampak beralih dari mode heightmap ke mode MC.
Migrasi renderer WebGPU: Spike 13-14 membuktikan bahwa WebGPURenderer milik Three.js dapat menjalankan komputasi kustom bersama scene graph. Dunia produksi beralih dari WebGLRenderer ke WebGPURenderer dengan StorageBufferAttribute untuk chunk MC. Gunakan jalur fallback khusus heightmap dari Fase 1 saat WebGPU tidak tersedia.
Alokasi SDF per chunk: Ikuti pola hibrida Spike 22. Setiap chunk dimulai sebagai heightmap. Pada sapuan kuas volumetrik pertama, alokasikan Float32Array 64^3, inisialisasikan dengan mengambil sampel heightmap (nilai SDF pada setiap titik adalah world.y - heightmap_value), lalu beralih ke rendering MC. Sistem kebijakan dari Spike 23 memastikan chunk tetap berada dalam mode MC secara permanen (perilaku "edit melekat" dari edit mask).
Heightmap bersama dalam shader SDF: Fungsi height_at() dari Spike 16. Unggah heightmap chunk ke buffer penyimpanan GPU. Shader komputasi SDF mengevaluasi max(height_sdf, edit_sdf), dengan height_sdf = world.y - height_at(world.xz) dan edit_sdf berisi modifikasi kuas. Chunk MC dan heightmap menggunakan acuan permukaan yang sama pada batas-batasnya.
Sambungan Transvoxel: Gunakan stack lengkap dari Spike 15-21. Batas MC-ke-heightmap menggunakan sel transisi dengan celah penyusutan. Batas MC-ke-MC pada resolusi berbeda menggunakan pola LOD ganda dari Spike 17. Kasus sudut dari Spike 19 menangani persimpangan empat arah. Komputasi GPU Spike 21 menghasilkan semua geometri sambungan dalam dispatch yang sama.
Medan jauh clipmap: Gunakan cincin clipmap dari Spike 24 untuk medan di luar jangkauan pemahatan. Pemahatan tidak pernah memengaruhi cincin ini; cincin tersebut mengambil sampel heightmap prosedural dasar.
Geomorphing: Geomorphing dari Spike 10 menghilangkan kemunculan mendadak pada transisi LOD. Untuk chunk yang diedit, target geomorph harus menyertakan edit tersebut. Jika sebuah chunk menggunakan MC pada LOD0 dan tetangga LOD1-nya menggunakan heightmap, geomorph memadukan kedua representasi tersebut. Hal ini memerlukan pengambilan sampel log edit bahkan pada LOD yang lebih rendah.
Anggaran material: Spike 08 menguji 4 lapisan triplanar + normal pada 45+ FPS. Chunk MC memerlukan material yang sama. Splat map dapat dibuat dari gradien SDF (curam = batu, datar = rumput), bukan dari kemiringan heightmap. Pendekatan ini tetap berada dalam anggaran empat lapisan.
Invalidasi vegetasi: Vegetasi berbasis density map dari Spike 07 bergantung pada ketinggian dan kemiringan medan. Saat sebuah chunk beralih ke mode MC, instance pohon harus dibuat ulang dengan mengambil sampel permukaan SDF. Pohon pada bagian menggantung atau di dalam gua harus disingkirkan. Matriks instanced mesh dari chunk.ts dibangun ulang berdasarkan permukaan baru.
Fase 3: Pohon Edit CSG untuk Urungkan/Ulangi dan Sinkronisasi Jaringan
Ganti mutasi SDF mentah dengan pohon operasi CSG. Setiap sapuan kuas menambahkan bentuk primitif (bola, kapsul, kotak) beserta operasinya (tambah, kurangi, perpaduan halus). SDF dihitung ulang dari pohon tersebut.
Manfaat:
- Nondestruktif: edit apa pun dapat dihapus dari pohon untuk mengurungkannya
- Efisien untuk jaringan: siarkan operasi CSG, bukan nilai field mentah
- Deterministik: semua klien membangun SDF yang sama dari urutan operasi yang sama
- Diff/patch pohon CSG milik ALICE-SDF menyediakan sinkronisasi serta urungkan/ulangi lintas jaringan yang hemat bandwidth
Penyimpanan Durable Object: Pohon edit per chunk menggantikan log edit datar dari Fase 1. WorldChunkDO menyimpan struktur pohon CSG, bukan delta heightmap mentah. Pesan Snapshot menyertakan pohon tersebut, dan klien yang bergabung belakangan mengevaluasinya untuk menghasilkan SDF lokal.
Fase 4: Pemahatan Kolaboratif
Tambahkan dukungan edit serentak dengan pemutaran ulang operasi yang diurutkan server. Durable Object memberi timestamp pada setiap edit dan menyiarkannya secara berurutan. Klien yang bergabung belakangan menerima log operasi dan merekonstruksi status dunia. Tipe pesan Snapshot yang ada diperluas agar menyertakan riwayat edit medan per chunk.
Karena sapuan kuas berukuran kecil, terlokalisasi, serta bersifat aditif atau subtraktif, hasil visual dari edit serentak yang urutannya sedikit berbeda biasanya tidak dapat dibedakan dari urutan yang "benar". Strategi last-write-wins dengan pengurutan server sudah memadai. Fungsi tick() milik Durable Object (saat ini berjalan setiap interval 50 ms untuk status pemain) menambahkan siaran edit medan ke loop yang sama.
Referensi Utama
Algoritma:
- Lorensen & Cline, "Marching Cubes" (1987)
- Eric Lengyel, "Transvoxel Algorithm" (2009), transvoxel.org
- Losasso & Hoppe, "Geometry Clipmaps" (SIGGRAPH 2004)
- "A High-Performance SurfaceNets Discrete Isocontouring Algorithm" (arxiv 2401.14906, 2024)
- MCHex (arxiv 2511.02064, 2025)
Implementasi:
- bevy-sculpter v0.18.0 (Rust, Surface Nets + kuas SDF)
- fast-surface-nets (Rust, 20 juta segitiga/detik)
- ALICE-SDF v1.3.0 (Rust + WASM, diff/patch pohon CSG)
- Editor SDF WebGPU (Nijhoff, Januari 2026)
- SculptingPro (API pemahatan runtime Unity)
- TerraBrush (GDExtension pemahatan medan Godot)
Game:
- Dreams (Media Molecule, SDF + rendering point cloud, SIGGRAPH 2015)
- Teardown (Voxagon, ray tracing DDA voxel, penghancuran multipemain deterministik)
- Engine SDF Mike Turitzin (brick map + geometry clipmap, Januari 2026)
Jaringan:
- "Optimizing payload size for voxel state synchronization" (Oulu, 2024)
- Multipemain Teardown (sinkronisasi penghancuran semideterministik, Maret 2026)
- cSculpt (pemahatan mesh kolaboratif dengan penggabungan multiresolusi)
Buat game berbasis medan tanpa menyentuh kuas.