Skip to content

Browser में open world बनाना, भाग 27: noise से बना एक island, ऐसी ज़मीन जो ज़मीन जैसी दिखे

लेखक Oleg Sidorkin, Cinevva के CTO और सह-संस्थापक

यहां नए हैं? series guide का इस्तेमाल करें। यह बताती है कि spike क्या होता है और सभी भागों को जोड़ती है।

भाग 26 ने world पर पानी रखा। यह भाग उसके नीचे की ज़मीन बनाता है, दो चरणों में जो इस बात का अक्स हैं कि कोई असली जगह कैसे बनती है। Spike 54 खुद terrain है: हाथ से नहीं गढ़ा गया बल्कि noise से उगाया गया, फिर तब तक मौसम और कटाव झेलता रहा जब तक उसमें वैसी drainage और coastline न आ गई जैसी किसी ऐसी जगह की होती है जहां सचमुच पानी बहा हो। Spike 55 उस terrain की त्वचा है: उस समस्या को हल करना जो लगभग हर procedural ज़मीन को हरा देती है, यानी कि एक tiled texture tiled ही दिखती है। दोनों मिलकर एक सवाल का जवाब देते हैं, क्या कोई creator बिना किसी artist के छुए एक भरोसेमंद island और ऐसी ज़मीन पा सकता है जो ज़मीन जैसी पढ़ी जाए, और जवाब है हां, बशर्ते आप सही recipes की नकल करें।

एक coastline जो अकेला noise आपको नहीं देगा

Spike 54 को नए tab में खोलें ↗ · Source देखें

Heightmap, Red Blob Games की recipes का अनुसरण करता है, जो छोटे-छोटे transforms का एक ढेर हैं और हर एक raw noise की किसी खास खामी को ठीक करता है। Fractional Brownian motion, Perlin noise के कई octaves को जोड़ता है ताकि terrain में चौड़ी पहाड़ियां और बारीक detail दोनों हों, लेकिन सादा FBM नरम और grid के साथ संरेखित दिखता है, इसलिए sample point को पहले domain-warp किया जाता है: आप हर coordinate को एक और noise field से खिसकाते हैं, p=p+noise(p)s, जो ridges को axis पर बंधे होने के बजाय कुछ organic रूप में मोड़ देता है। फिर redistribution, elevation को एक power ek तक उठाना, midtones को नीचे धकेलता है ताकि world में सपाट घाटियां और तीखी चोटियां हों, बजाय इसके कि सब कुछ एक ही हल्की ढलान पर बैठा रहे। वह हिस्सा जो इसे अंतहीन पहाड़ियों के बजाय एक island बनाता है, वह है radial falloff: केंद्र से euclidean दूरी निकालें, d=min(1,nx2+ny2), और elevation को 1d की ओर blend करें ताकि terrain किनारों पर समुद्र में उतर जाए। एक दूसरा स्वतंत्र noise field एक moisture map बन जाता है, जो shape के लिए कुछ नहीं करता मगर बाद में biome चरण को feed करता है।

इससे आपको एक shape मिल जाता है, लेकिन वह noise का shape है। इसमें कोई नदियां नहीं हैं, पानी से कटी कोई घाटियां नहीं, कोई sediment fans नहीं, क्योंकि इस पर कभी कुछ बहा ही नहीं। इसका हल है hydraulic erosion, जो Sebastian Lague के MIT-licensed implementation से port किया गया है। हज़ारों पानी की बूंदें यादृच्छिक जगहों पर पैदा होती हैं और ढलान से नीचे लुढ़कती हैं, हर एक के पास inertia होता है ताकि वह तीखे समकोण मोड़ न ले, तेज़ होने पर sediment उठाती है और धीमी होने या जमा होने पर उसे जमा करती है, साथ ही एक पहले से गणना किया गया circular brush हर erosion घटना को एक छोटे radius में फैला देता है ताकि कटाव एक pixel की खरोंच के बजाय smooth रहे, और evaporation जो बूंद को उसके जीवनकाल में retire कर देता है। पर्याप्त बूंदें चलाओ और terrain वह चीज़ उगा लेता है जिसे noise नकली नहीं बना सकता: ऐसी drainage networks जो मिलती हैं, घाटियां जो नीचे की ओर चौड़ी होती जाती हैं, और सपाट जगहें जहां sediment बैठ गया।

GPU पर erosion, और नदियां जो जानती हैं कि वे कहां हैं

CPU erosion सही है मगर धीमा, इसलिए spike इसे एक WebGPU compute shader में भी port करता है, और दिलचस्प हिस्सा यह है कि GPU atomics आप पर क्या मजबूर कर देते हैं। Heights को fixed-point i32 के रूप में दस लाख के scale पर store किया जाता है, क्योंकि WGSL में floats पर atomic add नहीं है, और हज़ारों बूंदों के लिए एक ही cell से बिना races के समानांतर sediment जमा करने और हटाने का इकलौता तरीका integers पर atomicAdd और atomicSub है। Fixed-point round-trip का मतलब है कि भारी समानांतर drag के तहत कोई cell कभी-कभार थोड़ा negative हो सकता है, जो हानिरहित है और readback पर clamp कर दिया जाता है। CPU version हर cell के लिए एक brush table पहले से गणना करता है, मगर 10012 grid पर वह table लगभग 100 MB का होता है, इसलिए GPU port इसके बजाय हर बूंद के brush को मौके पर ही फिर से गणना करता है, थोड़े arithmetic के बदले बहुत सारी memory की बचत करता है। बूंदों की शुरुआती positions अब भी CPU से एक Mulberry32 generator के ज़रिए आती हैं ताकि runs deterministic रहें।

दो और passes मौसम-कटाव झेले terrain को एक पढ़ने योग्य map में बदल देते हैं। Drainage, Red Blob D8 flow-accumulation method इस्तेमाल करता है: हर cell पर बारिश की एक इकाई डालो, सभी cells को elevation के घटते क्रम में sort करो, और हर cell का जमा पानी उसके इकलौते सबसे नीचे वाले पड़ोसी को पास कर दो, ताकि पानी प्राकृतिक घाटियों के साथ ढेर हो जाए, और जिस भी cell का accumulation एक threshold पार करता है उसे river चिह्नित कर दिया जाता है। पेच यह है कि एक eroded heightmap में pits होते हैं, यानी ऐसी स्थानीय गहराइयां जिनसे नीचे की ओर कोई निकास नहीं, और pit में घुसता पानी बस रुक जाता है, जिससे accumulation टूट जाता है। इसलिए drainage चलने से पहले Planchon-Darboux pit filling हर pit को उसके सबसे नीचे वाले पड़ोसी से ज़रा ऊपर तक उठा देता है, minNeighbour+ϵ, बीस से कम passes तक iterate करते हुए जब तक हर cell के पास निकलने की कोई जगह न हो। आख़िर में biomes Red Blob तरीके से तय किए जाते हैं, elevation बनाम moisture पर एक two-axis lookup ताकि एक ऊंचा-और-सूखा cell rock बन जाए जबकि एक नीचा-और-गीला cell marsh, और उसके ऊपर slope-aware overrides: तीखी ढलानें moisture की परवाह किए बिना rock पर मजबूर हो जाती हैं, waterline band beach बन जाता है, और सबसे ऊंची elevations snow ले लेती हैं। नतीजा एक ऐसा island है जिसे आप एक नज़र में पढ़ सकते हैं, दो noise seeds से शुरू से आख़िर तक generate किया गया।

वह tile जो दोहराना बंद नहीं करता

Spike 55 को नए tab में खोलें ↗ · Source देखें

एक terrain को ऐसे material की ज़रूरत होती है जो एक ऐसी texture से किलोमीटरों को ढके जो कुछ ही मीटर चौड़ी है, और जिस पल आप एक tile को ज़मीन ढकने के लिए बड़ा करते हैं, आंख दोहराव पर अटक जाती है। Spike 55 एक ही geometry और lighting पर चार sampling modes का एक A/B bench है, ताकि इकलौता चर यही रहे कि texture कैसे पढ़ी जाती है। Baseline है plain: scaled UV पर एक sample, जो हर कुछ मीटर पर साफ़ tile करता है और सिर्फ़ इसलिए मौजूद है ताकि उसे हराया जा सके। मुफ़्त PBR layers Poly Haven से उनके CDN के ज़रिए आती हैं, diffuse के साथ packed ARM map (ambient occlusion, roughness, metalness) के साथ एक GL normal, सब CC0, anisotropy 8 और mipmaps के साथ load किए गए।

दिलचस्प तीन, repeat पर अलग-अलग हमले हैं। hex-linear mode, Heitz-Neyret triangle grid है: surface पर एक तिरछी triangular lattice बिछाओ, और हर fragment एक triangle के अंदर बैठता है जिसके तीनों vertices एक-एक यादृच्छिक रूप से खिसका हुआ tap लेते हैं, barycentric weights से blend किया जाता है ताकि पड़ोसी क्षेत्र texture के अलग-अलग हिस्सों को sample करें और बड़े पैमाने की tiling घुल जाए। मगर तीन taps का सादा linear blend triangle के किनारों पर उनके रंगों का औसत निकाल देता है, जिससे एक दिखाई देने वाला triangular pattern बच जाता है, ठीक वही artifact जिससे spike 48 टकराया था। hex-vp mode उसी 2018 के paper से प्रकाशित fix है: barycentric sum के बाद, texture के mean color को घटाओ, squared weights के sum के inverse square root से rescale करो ताकि variance स्थिर रहे, फिर mean को वापस जोड़ दो। इससे blend भर में contrast स्थिर रहता है ताकि triangles गायब हो जाएं, यही वजह है कि material हर load की गई texture का 1-by-1 readback करता है ताकि पहले से उसके mean color का अंदाज़ा लगा सके। चौथा mode, iq-untiled, Inigo Quilez की Texture Repetition technique 3 है: एक low-frequency variation pattern से blend किए गए दो offset taps, तीन के बजाय बस दो samples और शुरू से कोई triangle structure नहीं, सस्ता विकल्प जो टिका रहता है।

किसी भी mode के ऊपर एक वैकल्पिक triplanar projection बैठता है, यही वह चीज़ है जो उसी material को बिना खींचे एक cliff पर लपेटने देती है। एक UV के बजाय, shader तीन world-axis projections को sample करता है, X की ओर वाली surfaces YZ plane पढ़ती हैं, Y, ZX पढ़ता है, Z, XY पढ़ता है, और इन्हें abs(normalWorld) से blend करता है जिसे चार और आठ के बीच एक sharpening power तक उठाया जाता है ताकि 45-डिग्री की ढलान तीनों projections को घोलकर लुगदी न बना दे। Bench इस अदला-बदली को साफ़ कर देता है: variance-preserving hex blending गुणवत्ता का विजेता है और Quilez का two-tap performance के लिहाज़ से सजग वाला, और दोनों plain को इतने बड़े अंतर से हराते हैं कि किसी creator को कभी plain tile ship नहीं करनी चाहिए।

इस अध्याय में बताई गई technology

Recipe-stacked heightmap generation. Red Blob Games की recipes raw noise को terrain में बुनती हैं: organic ridges के लिए domain-warped FBM (p=p+noise(p)s), सपाट घाटियों और तीखी चोटियों के लिए ek redistribution, और किनारों को समुद्र में उतारकर island बनाने के लिए 1d की ओर blend किया गया euclidean radial falloff। एक दूसरा noise field biome assignment के लिए moisture map है। देखें landscape generation

Hydraulic erosion, CPU और GPU. Sebastian Lague का droplet model (inertia, carrying capacity, एक पहले से गणना किया गया circular deposit brush, evaporation) असली drainage काटता है जिसे noise नकली नहीं बना सकता। WebGPU compute port heights को दस लाख के scale पर fixed-point i32 के रूप में store करता है ताकि बूंदें एक ही cell को समानांतर रूप से atomicAdd/atomicSub कर सकें, 10012 पर ~100 MB की table से बचने के लिए हर बूंद के brush को मौके पर फिर से गणना करता है, और शुरुआती positions को एक deterministic Mulberry32 generator से seed करता है।

Pit filling के साथ D8 drainage. Red Blob D8 flow accumulation हर cell पर बारिश की एक इकाई डालता है, cells को घटते elevation के क्रम में sort करता है, और हर cell का पानी उसके सबसे नीचे वाले पड़ोसी को पास करता है, एक threshold से ऊपर वाली नदियों को चिह्नित करते हुए। Planchon-Darboux pit filling पहले हर स्थानीय गहराई को minNeighbour+ϵ तक उठाता है (बीस से कम passes तक iterate करते हुए) ताकि पानी कभी फंसे नहीं और accumulation जुड़ा रहे। एक two-axis elevation-by-moisture lookup biomes तय करता है, slope overrides के साथ जो cliffs पर rock, waterline पर beach, और चोटियों पर snow मजबूर करते हैं।

Texture tiling को चार तरीकों से तोड़ना. एक जैसी geometry और lighting पर: plain (एक tap, साफ़ tile करता है), hex-linear (Heitz-Neyret triangle grid, linear blend एक triangle pattern छोड़ देता है), hex-vp (EGSR 2018 §3.3 variance-preserving fix जो mean घटाता है, squared weights के inverse-sqrt से rescale करता है, और mean को फिर से जोड़ता है, हर texture के लिए एक 1×1 mean readback चाहिए), और iq-untiled (Inigo Quilez two-tap technique 3)। Triplanar projection तीन world-axis planes को sample करता है जिन्हें abs(normalWorld) से 4-8 की power तक blend किया जाता है ताकि cliffs न खिंचें। variance-preserving गुणवत्ता पर जीतता है, two-tap लागत पर। देखें terrain materials


29 में से भाग 27। पिछला: भाग 26 - पानी बनाने के तीन तरीके अगला: भाग 28 - क्षितिज तक घास, और ऐसी ज़मीन जो खुद को छुपा लेती है Series guide: /hi/blog/2026-02-25-open-world-browser-series-guide