Membangun dunia terbuka di browser, bagian 8: Integrasi tanpa kehilangan baseline
Oleh Oleg Sidorkin, CTO dan Co-Founder Cinevva
Baru mengikuti seri ini? Gunakan panduan seri. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.
Integrasi adalah tahap ketika proyek mulai menjadi berantakan. Anda memiliki komponen-komponen yang berfungsi secara terpisah. Begitu semuanya dihubungkan, tiba-tiba setiap bug terasa seolah bisa berasal dari mana saja.
Spike 13 dan 14 adalah jawaban kami terhadap jebakan tersebut. Spike 13 menetapkan baseline Three.js WebGPU yang bersih. Hanya sebuah renderer, scene, kamera, dan mesh sederhana. Tanpa terrain, compute, atau efek. Kami memastikan bahwa backend WebGPU milik Three.js dapat diinisialisasi dengan benar, render loop berjalan stabil, dan material node TSL (Three.js Shading Language) berfungsi sesuai harapan. Baru setelah checkpoint tersebut berhasil, kami mulai menambahkan lapisan.
Buka Spike 13 di tab baru ↗ · Lihat kode sumber
Spike 14 berfokus pada penguatan secara bertahap. Kami menambahkan satu kemampuan pada satu waktu: pertama kontrol kamera, lalu pencahayaan, kemudian mesh hasil komputasi dari pipeline marching cubes, dan setelah itu penyaluran buffer untuk memasukkan output GPU langsung ke atribut geometri Three.js. Setelah setiap penambahan, kami memastikan bahwa lapisan sebelumnya masih berfungsi dengan benar.
Buka Spike 14 di tab baru ↗ · Lihat kode sumber
Proses tersebut terdengar lambat. Memang lambat selama tepat satu hari, tetapi segera setelah itu pendekatan ini menghemat beberapa hari kerja saat logika sambungan dan peralihan kebijakan menjadi rumit.
Kategori bug tertentu yang membenarkan disiplin ini adalah artefak setipis rambut. Serpihan tipis yang tampak seperti kerusakan geometri, tetapi sebenarnya disebabkan oleh data lama. Compute shader menulis N vertex ke dalam buffer, tetapi draw call masih dikonfigurasi untuk merender N+M vertex dari frame sebelumnya. Vertex tambahan tersebut berisi data sampah dari dispatch lama. Hasil visualnya adalah segitiga sangat tipis yang berkedip, muncul dan menghilang secara tidak terduga.
Bug dalam kategori tersebut tidak bisa dikalahkan hanya dengan intuisi. Anda mengatasinya melalui perubahan terkendali, sehingga Anda tahu persis apa yang berubah antara kondisi terakhir yang berfungsi dan kondisi saat ini yang rusak.
Integrasi WebGPU juga mengajari kami tentang siklus hidup buffer. Buffer GPU di WebGPU tidak dapat diubah setelah dipetakan untuk penggunaan tertentu. Jika Anda perlu mengubah ukuran vertex buffer karena output marching cubes bertambah, Anda harus membuat buffer baru dan memperbarui binding-nya. Tidak ada realloc. Menangani siklus hidup tersebut dengan benar—menghancurkan buffer lama tanpa berbenturan dengan pekerjaan GPU yang masih berjalan—memerlukan pengelolaan fence eksplisit yang tidak ada di WebGL.
Pada bagian 9, kami beralih ke pengerjaan sambungan Transvoxel. Bab tersebut sengaja dimulai dengan sebuah kerangka dasar. Pada tahap ini, kami sudah sepenuhnya memahami bahwa integrasi yang terburu-buru menghasilkan misteri, sedangkan persiapan yang terkendali menghasilkan masalah yang dapat di-debug.
Teknologi yang dibahas dalam bab ini
WebGPU. Penerus WebGL yang menyediakan akses GPU tingkat rendah di browser, lengkap dengan compute shader dan indirect rendering. Dua fitur penting WebGPU untuk dunia terbuka: compute shader memungkinkan pembuatan terrain, penempatan vegetasi, dan culling di sisi GPU; indirect rendering memungkinkan GPU menentukan apa yang perlu digambar berdasarkan output komputasi, sehingga menghilangkan bottleneck CPU dalam scene yang padat. Tersedia di Chrome, Edge, dan Firefox pada desktop. Lihat WebGPU sebagai pembuka potensi performa.
Three.js Shading Language (TSL). Sistem shader berbasis node milik Three.js yang menggantikan GLSL/WGSL mentah dengan ekspresi JavaScript yang dapat dikomposisikan. Node TSL seperti texture(), positionWorld, smoothstep(), dan fog() membangun shader graph saat runtime, yang kemudian dikompilasi ke backend yang sesuai (GLSL untuk WebGL atau WGSL untuk WebGPU). TSL memungkinkan logika material ditulis satu kali dan digunakan pada kedua renderer. Node graph dievaluasi pada setiap frame, sehingga uniform dinamis dan percabangan kondisional dapat berfungsi secara alami.
Siklus hidup buffer GPU di WebGPU. Buffer WebGPU dibuat dengan flag penggunaan tertentu (VERTEX, STORAGE, COPY_DST, dan sebagainya) dan tidak dapat diubah ukurannya setelah dibuat. Jika dispatch marching cubes menghasilkan lebih banyak vertex daripada yang dapat ditampung buffer, Anda harus membuat buffer baru, memperbarui binding, dan menghancurkan buffer lama. Menghancurkan buffer yang masih dirujuk oleh perintah GPU yang sedang berjalan akan menyebabkan error. Pengelolaan fence eksplisit (melalui device.queue.onSubmittedWorkDone()) memastikan bahwa buffer lama tidak dihancurkan sebelum GPU selesai menggunakannya. Disiplin siklus hidup ini tidak ada di WebGL, karena driver mengelola memori secara implisit.
Penguatan bertahap. Disiplin proses untuk integrasi: tetapkan baseline yang sudah dipastikan berfungsi, tambahkan satu kemampuan pada satu waktu, lalu pastikan lapisan sebelumnya tetap berfungsi setelah setiap penambahan. Pendekatan ini lebih lambat selama satu hari, tetapi menghemat berhari-hari dalam proses debugging berikutnya karena setiap regresi dapat dilacak ke perubahan spesifik yang terkendali. Pola baseline-lalu-bertahap lazim digunakan dalam pengembangan dunia terbuka AAA, ketika sistem diintegrasikan dalam urutan tertentu untuk mengelola risiko.
Bagian 8 dari 12.
Sebelumnya: Bagian 7 - Marching cubes dan gua nyata pertama
Berikutnya: Bagian 9 - Transvoxel dimulai dengan sebuah kerangka dasar
Panduan seri: /blog/2026-02-25-open-world-browser-series-guide