Browser में open world बनाना, भाग 8: अपनी baseline खोए बिना integration
लेखक Oleg Sidorkin, Cinevva के CTO और सह-संस्थापक
यहां नए हैं? series guide का इस्तेमाल करें। यह बताती है कि spike क्या होता है और सभी भागों को जोड़ती है।
Integration वही जगह है जहां projects उलझ जाते हैं। आपके पास अलग-अलग चलते हुए हिस्से होते हैं। आप उन्हें जोड़ते हैं और अचानक हर bug ऐसा लगता है जैसे वह कहीं भी हो सकता है।
Spikes 13 और 14 इसी जाल का हमारा जवाब थे। Spike 13 ने एक साफ Three.js WebGPU baseline तैयार की। बस एक renderer, एक scene, एक camera, और एक सरल mesh। न terrain, न compute, न effects। हमने पक्का किया कि Three.js का WebGPU backend सही तरह से initialize हुआ, कि render loop स्थिर था, और कि TSL (Three.js Shading Language) node materials उम्मीद के मुताबिक काम कर रहे थे। यह checkpoint पास होने के बाद ही हमने layers जोड़ना शुरू किया।
Spike 13 को नए tab में खोलें ↗ · Source देखें
Spike 14 क्रमिक रूप से मज़बूत करने का काम था। हमने एक बार में एक क्षमता जोड़ी: पहले camera controls, फिर lighting, फिर marching cubes pipeline से आया compute-generated mesh, फिर buffer plumbing ताकि GPU output सीधे Three.js geometry attributes में जाए। हर जोड़ के बाद हमने पक्का किया कि पिछली layer अब भी सही तरह से काम कर रही है।
Spike 14 को नए tab में खोलें ↗ · Source देखें
यह सुनने में धीमा लगता है। यह ठीक एक दिन के लिए धीमा था, और इसने हमें थोड़ी देर बाद कई दिन बचाए जब seam logic और policy switching जटिल हो गए।
जिस खास तरह के bug ने इस discipline को सही ठहराया वह था hairline artifacts। पतली-पतली परतें जो geometry corruption जैसी दिखती थीं पर असल में पुराना data थीं। Compute shader एक buffer में N vertices लिखता, लेकिन draw call अब भी पिछले frame के N+M vertices render करने के लिए सेट रहता। वे अतिरिक्त vertices पुराने dispatch का कूड़ा रखते थे। दिखने में नतीजा था झिलमिलाते रेज़र-पतले triangles जो बेतरतीब ढंग से आते और गायब होते थे।
इस तरह के bug को आप intuition से नहीं हराते। आप इसे controlled deltas से हराते हैं जहां आपको ठीक-ठीक पता होता है कि आखिरी चलते हुए state और मौजूदा टूटे हुए state के बीच क्या बदला।
WebGPU integration ने हमें buffer lifecycle के बारे में भी सिखाया। WebGPU में GPU buffers एक बार किसी खास usage के लिए map हो जाने पर immutable होते हैं। अगर marching cubes output बढ़ने की वजह से आपको vertex buffer का आकार बदलना हो, तो आपको एक नया buffer बनाना होता है और binding को update करना होता है। यहां कोई realloc नहीं है। उस lifecycle को सही करना, यानी in-flight GPU काम से टकराए बिना पुराने buffers को नष्ट करना, ऐसे explicit fence management की मांग करता था जो WebGL में मौजूद नहीं है।
भाग 9 में हम Transvoxel seam के काम में उतरते हैं। वह chapter जानबूझकर एक scaffold से शुरू होता है। इस मुकाम तक आते-आते हमने यह सबक पूरी तरह अपना लिया था कि integration में जल्दबाज़ी रहस्य पैदा करती है, और सोच-समझकर किया गया setup ऐसे problems पैदा करता है जिन्हें debug किया जा सके।
इस chapter में बताई गई technology
WebGPU. WebGL का उत्तराधिकारी, जो browser में compute shaders और indirect rendering के साथ low-level GPU access देता है। Open worlds के लिए WebGPU की दो अहम खूबियां: compute shaders GPU की तरफ terrain generation, foliage placement, और culling को मुमकिन बनाते हैं; indirect rendering GPU को compute output के आधार पर तय करने देता है कि क्या draw करना है, जिससे घने scenes में CPU की अड़चनें खत्म हो जाती हैं। Desktop पर Chrome, Edge, और Firefox में उपलब्ध है। देखें WebGPU performance की बढ़त के तौर पर।
Three.js Shading Language (TSL). Three.js का node-आधारित shader system जो कच्चे GLSL/WGSL की जगह composable JavaScript expressions लाता है। texture(), positionWorld, smoothstep(), और fog() जैसे TSL nodes runtime पर एक shader graph बनाते हैं जो उपयुक्त backend (WebGL GLSL या WebGPU WGSL) में compile होता है। TSL की वजह से material logic एक बार लिखकर दोनों renderers के लिए चलाना मुमकिन है। Node graph हर frame पर evaluate होता है, इसलिए dynamic uniforms और conditional branching सहज रूप से काम करते हैं।
WebGPU में GPU buffer lifecycle. WebGPU buffers खास usage flags (VERTEX, STORAGE, COPY_DST, आदि) के साथ बनते हैं और बनने के बाद इनका आकार नहीं बदला जा सकता। अगर कोई marching cubes dispatch buffer की क्षमता से ज़्यादा vertices पैदा करता है, तो आपको एक नया buffer बनाना होगा, binding update करना होगा, और पुराने को नष्ट करना होगा। ऐसा buffer नष्ट करना जिसका अब भी किसी in-flight GPU command में reference है, errors पैदा करता है। Explicit fence management (device.queue.onSubmittedWorkDone() के ज़रिए) यह पक्का करता है कि पुराना buffer तब तक नष्ट न हो जब तक GPU उसका इस्तेमाल पूरा न कर ले। यह lifecycle discipline WebGL में मौजूद नहीं है, जहां driver memory को अपने आप संभालता है।
Incremental hardening. Integration के लिए एक process discipline: एक known-good baseline तैयार करो, एक बार में एक क्षमता जोड़ो, और हर जोड़ के बाद पक्का करो कि पिछली layer अब भी काम कर रही है। यह तरीका एक दिन के लिए धीमा होता है और बाद की debugging में कई दिन बचाता है क्योंकि हर regression को एक खास, controlled बदलाव तक ढूंढा जा सकता है। यह baseline-फिर-increment pattern AAA open world development में आम है जहां risk संभालने के लिए systems को एक खास क्रम में integrate किया जाता है।
12 में से भाग 8।
पिछला: भाग 7 - Marching cubes और पहली असली caves
अगला: भाग 9 - Transvoxel एक scaffold से शुरू हुआ
Series guide: /hi/blog/2026-02-25-open-world-browser-series-guide