1993 की तरह ग्राफिक्स बनाना
(staniks.github.io)- Catlantean 3D एक साइड प्रोजेक्ट है जिसका लक्ष्य 1990 के दशक की शुरुआत वाले PC गेम्स जैसी सीमाओं के साथ एक पूरा first-person shooter बनाना है, और यह 320x240 resolution व 256-color palette आधारित rendering को लक्ष्य करता है
- renderer केवल palette index संभालता है, इसलिए दूरी के आधार पर अंधेरा दिखाने के लिए 32-स्टेप colormap पहले से precompute किया जाता है, और runtime में O(1) lookup से गहरा रंग चुना जाता है
- asset creation को Blender-आधारित pre-rendered sprite, हाथ से बनाए गए sprite और texture, तथा Python script से बनने वाले procedural texture में बाँटा गया है
- हाथ से बनाया गया HUD और pixel-level scale rules छोटी resolution में sharpness और readability बनाए रखने की मुख्य सीमाएँ हैं, और world के 1 unit को 64 pixel के आधार पर सेट किया गया है
- Tiled की जगह अपना map editor बनाया गया है, और release के बाद वही editor खिलाड़ियों को देने की योजना है; game source code को GitHub पर open source के रूप में जारी करने का इरादा है
प्रोजेक्ट के लक्ष्य और सीमाएँ
- Catlantean 3D एक साइड प्रोजेक्ट है, जिसे एक साल से अधिक समय से फुर्सत में धीरे-धीरे विकसित किया जा रहा है, और लक्ष्य अगले साल Steam release का है
- उद्देश्य 1990 के दशक की शुरुआत में आम रही तकनीकों से बना एक पूरा, जारी करने योग्य first-person shooter तैयार करना है
- आधुनिक compiler और platform abstraction layer की अनुमति है, लेकिन abstraction layer को सिर्फ pixel लिखने वाले framebuffer, keyboard और mouse input, sample लिखने वाले audio buffer, और filesystem I/O तक सीमित रखा गया है
- game के asset तक सब कुछ बिल्कुल शुरुआत से बनाना है, और rendering व sound mixing भी पूरी तरह खुद लागू करनी है
- target resolution 320x240 है, और स्क्रीन का हर pixel केवल 256 रंगों में से एक ही इस्तेमाल कर सकता है
- game logic deterministic behavior सुनिश्चित करने के लिए fixed-point का उपयोग करता है, जबकि rendering में determinism कम महत्वपूर्ण होने से floating-point का उपयोग किया जाता है
- नतीजा केवल एक tech demo नहीं, बल्कि मज़ेदार और पूरी तरह खेलने योग्य game होना चाहिए, और AI output का उपयोग नहीं किया जाता
- दिखाया गया सारा काम अभी work in progress है और काफ़ी बदल सकता है
Palette rendering
-
VGA graphics
- VGA hardware का Mode 13h, 320x200 का 256-color graphics mode था, और यह एक पूरी पीढ़ी के PC games को परिभाषित करने वाला मशहूर mode था
- programmer के नज़रिए से Mode 13h एक linear framebuffer देता था, जिसमें हर pixel को 256-color palette के index के रूप में 1 byte में व्यक्त किया जाता था
- pixel draw करने के लिए बस किसी खास address पर 1 byte लिखना होता था, और shader या VRAM जैसी अवधारणाओं से नहीं जूझना पड़ता था
- modern game asset image में लाखों रंग इस्तेमाल कर सकते हैं, लेकिन 256-color सीमा में हर रंग का चुनाव सोच-समझकर और इरादे से करना पड़ता है
- Doom और Duke Nukem जैसे games को इस बात के उदाहरण के रूप में रखा गया है कि तकनीकी सीमाओं की वजह से भी graphics में sharpness और clarity आ सकती है
- Catlantean 3D उसी एहसास को फिर से बनाने की कोशिश करता है, लेकिन 320x200 की जगह VGA Mode-X के क़रीब 320x240 चुनता है
- 320x200 को 4:3 display पर दिखाने से pixel square नहीं रहते; यह तरीका ज़्यादा authentic है, लेकिन निजी पसंद के कारण इससे बचा गया है
-
Palette
- palette की शुरुआत 768 byte से होती है, और इसे कई बार trial-and-error व iteration के बाद चुना गया
- palette में transparent color के लिए चमकीला pink, pure white, और pure black—तीनों के लिए एक-एक रंग reserve किया गया है
- खून दिखाने के लिए red family के काफ़ी shades चाहिए थे, और red, green, blue key तथा रंग-भेद वाले doors के लिए green और blue families भी ज़रूरी थीं
- background को cat worship के कारण प्राचीन Egypt जैसी parody भूमि Catlantis के रूप में रखा गया है, इसलिए yellow और brown वाले desert tones की ज़रूरत ज़्यादा है
- Catlantis पर cybernetic dog-humans का कब्ज़ा होने की सेटिंग के कारण tech facility दिखाने के लिए gray tones भी काफ़ी चाहिए थे
- gray की monotony तोड़ने और अंधेरा होने पर warm alternate color की तरह इस्तेमाल करने के लिए beige tones भी शामिल किए गए
- बाकी रंग texture बनाने की प्रक्रिया के दौरान ज़रूरत पड़ने पर भरे गए, और “देखने में ठीक लगा” जैसी subjective कसौटी पर तय हुए
- palette एक बार में तैयार नहीं हुई; assets बनाने, testing और iteration के दौरान इसे लगातार समायोजित किया गया
colormap और lighting
-
raycaster संरचना
- Catlantean 3D एक पारंपरिक raycaster है, और map एक ही आकार के tile से बना होता है
- कुछ tile दीवारें हैं, जबकि दूसरे tile खाली जगह हैं जिनमें केवल floor और ceiling होती है
- renderer स्क्रीन के हर column के लिए DDA algorithm का उपयोग करते हुए tilemap में आगे बढ़ता है और map geometry से टकराने की जगह खोजता है
- collision position के आधार पर सही texture coordinate से sample की गई wall column स्क्रीन पर draw की जाती है
- उसके बाद floor और ceiling को horizontal scanline के रूप में render करके बाकी स्क्रीन भरी जाती है
- केवल palette के सहारे game world render करने पर दृश्य सपाट और असरहीन लगता है
- खिलाड़ी से दूरी बढ़ने पर रोशनी कम हो और map tile का एक side दूसरे से थोड़ा गहरा हो, तो depth का एहसास आता है
-
Palette-आधारित darkening
- आधुनिक hardware-accelerated renderer में vertex distance के आधार पर color vector पर floating-point factor गुणा करके shader में आसानी से अंधेरा किया जा सकता है
- palette renderer रंग की अवधारणा से नहीं, बल्कि palette index से काम करता है, इसलिए किसी रंग का गहरा version ढूँढने के लिए पूरी palette खंगालनी पड़ती है
- अगर हर rendered pixel के लिए 256-color palette खोजी जाए तो यह बहुत धीमा होगा, इसलिए runtime से पहले precompute करके तेज color lookup तैयार किया जाता है
- palette को एक row मानकर 32 brightness steps चुने जाएँ, तो हर color के लिए original को छोड़कर 31 गहरे variants चाहिए होते हैं
- हर color के RGB value और brightness index से target darker color निकाला जाता है, लेकिन यह ज़रूरी नहीं कि वह रंग palette में वास्तव में मौजूद हो
- target color के सबसे क़रीबी palette color को ढूँढने के लिए palette search करके colormap बनाया जाता है
- शुरुआत में Euclidean distance इस्तेमाल किया गया, लेकिन बहुत से रंग gray की तरफ़ खिंच जाते थे, और dark colors ठंडे व बेजान लगते थे
- बाद में colors को Oklab color space में बदला गया और perceptual distance formula का उपयोग किया गया, जो इंसानी color-difference perception के ज़्यादा क़रीब है
- color को गहरा करते समय उसे थोड़ा warm hue की ओर सरकाने वाली pixel art तकनीक, hue shifting, भी लागू की गई
- colormap हर color के brightness variant को दिखाने वाला palette index का 2D matrix है, और palette colors तक सीमित होने के कारण gradient अब भी पूरी तरह परफ़ेक्ट नहीं है
-
Runtime cost में कमी
- जब distance-based colormap row index तय हो जाता है, तो उस brightness row के Nवें item को चुनकर darkened color N का palette index मिल जाता है
- इस तरीके से runtime में darker color चुनना O(1) lookup बन जाता है
- wall rendering में wall column पूरी तरह vertical होती है और column के सभी pixel camera से समान दूरी पर होते हैं, इसलिए हर screen column के लिए colormap row index केवल एक बार निकाला जाता है
- floor rendering में किसी horizontal row के सभी pixel समान दूरी पर होते हैं, इसलिए हर screen row के लिए केवल एक बार गणना होती है
- sprite flat billboard होते हैं, जिनके सभी pixel camera से समान दूरी पर माने जाते हैं, इसलिए हर visible sprite के लिए केवल एक बार गणना होती है
- walls के लिए 320 बार, floor के लिए अधिकतम 240 बार, और हर visible sprite के लिए केवल एक बार गणना करनी होती है; raycasting छिपे हुए object हटाने का काम भी मुफ्त में दे देता है
- Doom और कई अन्य games ने भी ऐसा ही approach इस्तेमाल किया था
Asset creation का तरीका
-
Asset की तीन श्रेणियाँ
- Catlantean 3D के texture और sprite तीन श्रेणियों में बाँटे गए हैं
- पहली श्रेणी Blender में बने 3D model को texture के रूप में render करके बनाए गए pre-rendered sprite की है
- दूसरी श्रेणी हाथ से बनाए गए sprite और texture की है
- तीसरी श्रेणी हाथ से बने art को मिलाकर special Python script से तैयार procedural texture की है
-
Pre-rendered sprites
- जटिल animated sprite में कई frame बदलने पड़ते हैं, इसलिए iteration कठिन और समय लेने वाली होती है
- अधिक efficient तरीका यह है कि Blender में 3D model बनाया जाए, rigging और animation की जाए, और फिर Blender Python API इस्तेमाल करने वाली script से कई texture render किए जाएँ
- बदलाव model में किए जाते हैं और rendering script बाकी काम संभाल लेती है, जिससे iteration का समय काफ़ी घट जाता है
- मुख्य कठिनाई यह थी कि rendered sprite बहुत धुंधले और रंग उड़े हुए लगते थे
- high resolution में render करके filtering के साथ छोटा करने वाला तरीका मिला-जुला साबित हुआ, क्योंकि detail filtering में दब जाती थी और edge sharpness खो जाती थी
- सबसे असरदार और reusable तरीका Blender compositing का उपयोग करके सही contrast और sharpness पाना निकला
- image तैयार हो जाने पर एक special Python script palette quantization करके engine द्वारा इस्तेमाल की जाने वाली 1-byte-per-pixel image बनाती है
- script source image के हर pixel के लिए Oklab के आधार पर perceptually सबसे क़रीबी palette color ढूँढती है, और उसी color के index को pixel value बनाती है
- index array और size information को game में इस्तेमाल होने वाले simple TEX format में pack किया जाता है
- enemy sprite में कई animation हो सकते हैं, और हर animation में sprite के मुड़ सकने वाले 8 directions के frame होने चाहिए
- Python script हर animation के लिए sprite को rotate करती है, सभी frame render करती है, फिर दोबारा rotate करती है, और यह क्रम दोहराती है
- sprite file name को sprite name, action name, direction, और frame index दिखाने वाली naming convention के अनुसार रखा जाता है
- rendered sprite repository में नहीं रखे जाते और
.gitignoreमें डाले जाते हैं; दूसरी machine पर build script सभी model render करके sprite तैयार कर देती है - RTX 3070 पर लगभग 15 model process करने में करीब 10 second लगते हैं
-
हाथ से बनाए गए sprite और texture
- development की शुरुआत में status bar face के लिए बिल्ली Vilko की texture वाला cat-shaped head Blender में बनाया गया था
- यह नतीजा आलसी और कम मेहनत वाला लगा, भावनाएँ ठीक से व्यक्त नहीं कर पाया, और mood feedback में लोगों ने सबसे पहले इसी पर टिप्पणी की
- कुछ elements ऐसे हैं जिन्हें हाथ से बनाना ही पड़ता है, और निष्कर्ष यह निकला कि animated hand-drawn version कहीं बेहतर है
- sprite के आकार की वजह से हर pixel जानबूझकर रखा जाना चाहिए; इसे Blender renderer पर नहीं छोड़ा जा सकता
- यही तर्क ज़्यादातर pickup items पर भी लागू हुआ, और पुराने pre-rendered नतीजे छोटे scale पर Blender compositor से लगातार अच्छे नहीं निकल रहे थे
- इंसानी हाथ से सुधार के बाद pickup items की sharpness और readability बहुत बेहतर हो गई
- sprite resolution को बस बढ़ा देने से game rasterizer उसे scale तो कर सकता है, लेकिन pixel scale consistent नहीं रहता, इसलिए परिणाम अच्छे नहीं लगते
- एक ही row या column में आगे-पीछे चलते समय pixel size समान रहने की अवचेतन अपेक्षा होती है, इसलिए अगर अलग-अलग sprite का pixel scale अलग हो तो वह अजीब लगता है
- Catlantean 3D में world का 1 unit, 64 pixel के बराबर है, और सभी sprite इसी scale के हिसाब से बनाए जाते हैं
- world unit की एक-चौथाई ऊँचाई वाला sprite, 64/4=16 pixel ऊँचा होना चाहिए
HUD और procedural generation pipeline
-
HUD
- HUD और उसके लगभग सभी components हाथ से रखे और बनाए गए हैं
- स्क्रीन के नीचे का status bar, कई transition panel और screen, तथा font, hand-drawn HUD श्रेणी में आते हैं
- हर चीज़ को सीधे paint करने के बजाय Affinity Photo के layer effects और compositing का काफ़ी उपयोग किया गया है
- इस्तेमाल किए गए effects में सपाट सतह को 3D एहसास देने वाला emboss effect, rough feel के लिए noise generation और overlay, color overlay, blending mode, और glow effect शामिल हैं
- HUD elements में बार-बार iteration होती है, इसलिए layer-based rearrangement की सुविधा भी महत्वपूर्ण है
- आम तौर पर Affinity Photo में पहले truecolor में काम किया जाता है, और कई elements दरअसल solid-color rectangle पर special effects व blending लागू करके बनाए जाते हैं
- Affinity Photo से export की गई image में anti-aliasing से जुड़े लगने वाले अजीब artifact आते थे, और उन्हें विश्वसनीय रूप से बंद नहीं किया जा सका
- pixel-accurate काम के लिए यह उपयुक्त नहीं था, इसलिए Aseprite में pixel-perfect text, artwork slicing, और ज़्यादा sharp boundaries पर अतिरिक्त paint जैसे काम किए गए
-
Procedurally generated textures
- कुछ texture इतने सरल या विशिष्ट होते हैं कि उन्हें सीधे हाथ से बनाया जा सकता है, लेकिन बहुत से texture base material के ऊपर wear, dust, और surface-detail variation साझा करते हैं
- हर variation को हाथ से बनाना उबाऊ और असंगत हो जाता, इसलिए उन्हें Python script से generate किया गया
- generation pipeline में surface relief को परिभाषित करने वाला heightmap, variation के लिए noise map, dust और wear के लिए grime map, दो base colors, और brightmap input के रूप में लिए जाते हैं
- heightmap वास्तव में normal map बनाने के लिए इस्तेमाल होता है, और normal map का उपयोग सरल lighting और shadow bake करने में होता है
- brightmap उन हिस्सों को निर्दिष्ट करता है जहाँ दूसरे parameters से स्वतंत्र रूप से रंग बनाए रखना है
- script अंतिम texture तैयार करती है और palette quantization भी करती है, ताकि वह सीधे engine में इस्तेमाल हो सके
- texture edit करना pixels दोबारा paint करने की जगह parameters समायोजित करने का काम बन जाता है, जो अकेले काम करते समय बहुत समय बचाता है
gibs और pre-rendered effects
-
Gibs
- जब enemy को point-blank shotgun blast या explosion जैसी अत्यधिक damage मिलती है, तो आम तौर पर gibbing होता है
- भारी damage के impact को दिखाने के लिए enemy के खून-सने टुकड़ों में फटने वाला animation इस्तेमाल होता है
- यह pipeline Python script-केंद्रित है, जो sprite, palette, और parameter set लेकर game data में जाने वाले animation frame बनाती है
- पहले चरण, Voronoi decomposition में, sprite के opaque body से K seed pixel यादृच्छिक रूप से चुने जाते हैं, और सभी pixel को सबसे क़रीबी seed को सौंप दिया जाता है
- इस तरह बना हर cell उड़ने वाले एक टुकड़े में बदल जाता है
- दूसरे चरण, wound bleeding में, अलग-अलग टुकड़ों से सटे boundary pixel को depth 0 का घाव चिह्नित किया जाता है, और BFS अंदर की ओर फैलते हुए depth value देता है
- rendering के समय boundary के पास के pixel game palette से निकले ramp के blood color की ओर blend होते हैं, जबकि टुकड़े के अंदर जाते-जाते original sprite color ज़्यादा बचा रहता है
- palette ramp का चुनाव parameterized है, इसलिए किसी खास enemy के लिए green या blue “blood” भी इस्तेमाल किया जा सकता है
- तीसरे चरण, physics में, हर टुकड़े को center point, sprite center से बाहर की ओर जाने वाली random spread velocity, rotation velocity, gravity, और drag दिया जाता है
- collision detection नहीं है, लेकिन टुकड़े floor से टकराने पर रुक जाते हैं; यह भले ही crude हो, लेकिन पर्याप्त नतीजा देता है
- टुकड़ों की संख्या, explosion force, gravity, drag, spread, और wound depth को parameter से adjust किया जा सकता है
- अच्छे दिखने वाले seed ढूँढने में थोड़ा trial-and-error लगता है, लेकिन हाथ से animation बनाने से फिर भी तेज़ है
- यही तकनीक flower pot, barrel, और crate जैसे destructible environment object पर भी लागू होती है
- pre-rendered animation की तरह gibs के output भी repository में नहीं रखे जाते; checkout के बाद दोबारा generate किए जाते हैं, और runtime नगण्य है
-
Pre-rendered particle system
- ज़्यादातर particle effects Aseprite में हाथ से बनाए जाते हैं, लेकिन कुछ को gibs जैसी प्रक्रिया से generate और bake किया जाता है
- Python script simulation चलाकर PNG frame sequence बनाती है, और बाद में उन्हें TEX में quantize किया जाता है
- runtime particle system नहीं है; सभी effects पहले से bake किए जाते हैं ताकि software rasterizer उन्हें जितना संभव हो उतनी तेज़ी से render कर सके
- यहाँ “particle” शब्द थोड़ा भ्रामक है, क्योंकि वास्तव में particles simulate नहीं किए जाते
- हर frame pixel-by-pixel radial energy field की गणना करके और कई स्वतंत्र layers को जोड़कर compose किया जाता है
- core एक soft disc है जो animation के दौरान बाहर की ओर फैलती है
- rays, core के आसपास की नुकीली light streaks हैं; इनके sharpness और length सेट किए जा सकते हैं, और हर ray में RNG-आधारित length jitter होता है जिससे वे अनियमित दिखें
- ring एक वैकल्पिक फैलती हुई shockwave है, और noise पूरे energy field पर value noise गुणा करके साफ़ shape को rough और irregular बनाता है
- जमा हुई pixel-wise energy को script parameters में निर्दिष्ट palette ramp के अनुसार quantize किया जाता है
- palette design के कारण हर row को bright से dark तक जाने वाले gradient की तरह माना जाता है, इसलिए blending या alpha calculation के बिना केवल palette index arithmetic से pixel को dark किया जाता है
- कुछ threshold से ऊपर pixel को white की ओर धकेला जाता है ताकि white-hot core जैसा प्रभाव मिले
- विकल्प के तौर पर ऊपर छोटे sparkle बिखेरे जा सकते हैं; ये cross-shaped होते हैं, बाहर की ओर बढ़ते हैं, और अपनी lifetime के दौरान fade हो जाते हैं
- animation, explosion या teleport flash जैसे बढ़कर गायब होने वाले one-shot mode और first frame व last frame के मेल से seamless loop mode—दोनों का समर्थन करता है
- loop mode plasma bolts और energy projectiles जैसे लगातार दोहरने वाले effects के लिए उपयोगी है
Map editor और tool ecosystem
- map editing की शुरुआत Tiled से हुई थी; वह सामान्य रूप से एक ठीक tool था, लेकिन game के लिए ज़रूरी कुछ specific features उसमें नहीं थे
- Tiled में per-cell light level painting, cell flags, और game-specific property की अवधारणा नहीं थी, इसलिए शुरुआत में object properties का ज़रूरत से ज़्यादा उपयोग करके workaround बनाया गया
- Tiled के JSON output को engine के binary format में बदलने के लिए Python script भी चाहिए थी; यह tool और game की ज़रूरतों के बीच mismatch को भरने वाला अतिरिक्त घटक था
- अगर खिलाड़ी को map बनाने के लिए Tiled install करना पड़े, उसका interface सीखना पड़े, और conversion script सेट करनी पड़े, तो यह editor के वास्तव में इस्तेमाल होने की संभावना लगभग खत्म कर देने जितना बोझिल हो जाता
- custom editor per-cell light level painting, cell flags, और game जिन सभी entity व property type को जानता है, उनका native support देता है
- game release होने पर खिलाड़ियों को वही editor दिया जाएगा जो development में इस्तेमाल हुआ है
- editor plug-and-play है, और उसी editor से सीधे level run किया जा सकता है
- यह पता है कि toolbar icons बहुत खराब हैं, और ठीक इसी वजह से उन्हें वैसा ही रखा गया है
- editor wxPython में बनाया गया है, जो tkinter की तुलना में widget, event handling, और layout के मामले में ज़्यादा उपयुक्त लगा
- wxPython का परिणाम ज़्यादा native दिखता था, और iteration तेज़ी से आगे बढ़ी
- MVP pattern पर आधारित संरचना UI logic और map data को साफ़-साफ़ अलग रखती है, जो उस स्थिति में महत्वपूर्ण है जहाँ map format अभी स्थिर नहीं है और दोनों तरफ़ बार-बार बदलाव हो रहे हैं
- editor का हर हिस्सा Python में नहीं लिखा गया; model का बड़ा भाग
pybastlibrary पर निर्भर करता है pybastpybind के ज़रिए engine की internal Python binding है, जो game data archive पढ़ना, game texture पढ़ना, entity coordinates के लिए fixed-point class, और serialization प्रदान करती है- यह Python में उन चीज़ों को दोबारा लागू करने से बचने का फैसला है जो पहले से C++ में लिखी जा चुकी हैं, और engine व tools मिलकर एक छोटा, क़रीबी ecosystem बनाते हैं
Release plan और public release model
- Catlantean 3D के 2027 की पहली तिमाही में आने की उम्मीद है
- अभी ध्यान level design, enemy और weapon जोड़ने, तथा ongoing polish work पर है
- लक्ष्य कीमत 5 से 8 डॉलर के बीच है
- game source code को GitHub पर open source के रूप में जारी करने की योजना है
- graphics, level, sound, music आदि वाला वास्तविक data archive game खरीदने पर ही मिलेगा
- process की transparency को लगातार भरोसा बनाने वाले कुछ गिने-चुने तत्वों में माना गया है
- indie games, AAA की तुलना में, छोटे audience पर निर्भर होते हैं, लेकिन वही audience project को follow करने, support करने, और दूसरों तक पहुँचाने के लिए ज़्यादा इच्छुक होती है
- विकास प्रक्रिया दिखाना इस बात को जताने का सबसे ईमानदार तरीका माना गया है कि जो बनाया जा रहा है उसकी सच में परवाह की जा रही है
1 टिप्पणियां
Hacker News की राय
अगर आप software rendering के साथ प्रयोग करना चाहते हैं, तो SDL2 और C में ऐसा लगभग सबसे छोटा उदाहरण मौजूद है जो हर platform पर main memory की ARGB8888 2D array को screen पर कुशलता से चढ़ाता है: https://gist.github.com/CoryBloyd/6725bb78323bb1157ff8d4175d...
320x200x8-bit palette framebuffer को ARGB में बदलने वाला conversion आपको खुद करना होगा ;)
अगर आप यह देखना चाहते हैं कि palette framebuffer से क्या-क्या किया जा सकता है, तो http://www.effectgames.com/demos/canvascycle/ पर Show Options दबाकर देखें, या उस artist की GDC talk https://youtu.be/aMcJ1Jvtef0 देख लें
उसके बाद अगर आपको classic Deluxe Paint IIe जैसा एहसास चाहिए, तो https://github.com/mriale/PyDPainter चलाइए, और अगर थोड़ा ज़्यादा modern tool चाहिए, तो https://www.aseprite.org/ खोल लीजिए
कम-से-कम SDL3 में अब renderer या texture की ज़रूरत नहीं है। SDL_GetWindowSurface से surface लें और SDL_UpdateWindowSurface से उसे दिखा दें
लाइब्रेरी को मैं जितना समझता हूँ, यह software graphics के सबसे करीब का तरीका है, और SDL अब भी double buffering अपने आप संभाल लेता है
यह निश्चित रूप से सबसे बुनियादी तरीका है। inner loop में थोड़ी optimization करनी हो, तो pixel loop में जाने से पहले scanline offset पहले से calculate कर लें:
int s = y*screenRect.w;for (int x = 0; x < screenRect.w; x++) {pixels[s + x] = argb(255, frame>>3, y+frame, x+frame);}साझा करने के लिए धन्यवाद। Quake के कई लोकप्रिय fork पहले से मौजूद हैं, लेकिन Planimeter एक ऐसा Quake-VS2026 fork वितरित कर रहा है जिसमें कोई बदलाव नहीं जोड़े गए हैं
टीम x64 build पर काम कर रही है, और इसके लिए पुरानी SciTech Multi-platform Graphics Library, जो सिर्फ x86 के लिए है, को SDL3 से बदलना पड़ेगा। दूसरा रास्ता scitech-mgl को x64 पर port करना है, लेकिन इसकी संभावना कम लगती है, और आखिरी बार मैंने सुना था कि software renderer हट भी सकता है
हालांकि software renderer और SDL_Texture के साथ इसे शायद बचाया जा सके
यह लेख Doom से काफी प्रेरित है, लेकिन असली raycasting engine Doom के बजाय उसके पूर्ववर्तियों, खासकर Wolfenstein 3D, के ज़्यादा करीब है
इसमें vertical walls और एक-सी floor तथा ceiling height का इस्तेमाल होता है। Wolf3D में performance कारणों से textured floor और ceiling नहीं थे, लेकिन इसी तरह के कुछ दूसरे games में वे मौजूद थे
Doom, और अगर याददाश्त सही है तो Duke Nukem भी, कहीं ज़्यादा लचीला BSP engine इस्तेमाल करते थे, जिसमें दीवारें किसी भी angle पर मिल सकती थीं और floor/ceiling की ऊँचाई बदल सकती थी। फिर भी levels अब भी “flat” थे, यानी एक ही level में कई मंज़िलें नहीं बनाई जा सकती थीं; उदाहरण के लिए ऐसा पुल नहीं बनाया जा सकता था जिसके ऊपर और नीचे दोनों तरफ से चला जा सके
Build engine BSP का इस्तेमाल नहीं करता था। वह sectors के बीच connections को portals की तरह मानता था, उन portals के हिसाब से clipping करता था, और दीवारों को 90 degree घुमाए गए trapezoid की तरह rasterize करता था
इसी वजह से चलती हुई trains या घूमती हुई light जैसी dynamic wall geometry संभव थी, और जब तक आप एक साथ दोनों कमरों को नहीं देख सकते, तब तक “room over room” जैसी संरचना भी बनाई जा सकती थी
Blood और Shadow Warrior में इससे भी ज़्यादा “3D” जैसे spaces बनाने के लिए एक workaround इस्तेमाल किया गया था: एक जैसे आकार के sectors बनाकर, एक sector के floor को दूसरे sector की ceiling तक जाने वाले portal की तरह इस्तेमाल करना। यह engine की मूल सुविधा नहीं थी, लेकिन जिन studios के पास source access भी नहीं था वे भी इसे खुद लागू कर सके, इतना flexible यह था
Duke Nukem 3D के पहले level में भी Build के कुछ tricks इस्तेमाल हुए थे। उदाहरण के लिए sprites को camera के साथ घुमने के बजाय axis-aligned रखा जा सकता था और उनमें collision भी हो सकती थी, इसलिए हर sprite को axis-aligned rectangle मानकर बुनियादी 3D geometry बनाई जा सकती थी। पहले level में इसका उपयोग exit button से ठीक पहले दो buildings के बीच bridge बनाने में हुआ था
Blake Stone और Rise of the Triad ने Wolf3D engine के बाद के version इस्तेमाल किए थे, और उनमें textured floor and ceiling थे
Duke Nukem का Build engine BSP का इस्तेमाल नहीं करता था
https://www.jonof.id.au/forum/topic-137.html#msg1548
बाद में Shadow Warrior में शायद ऐसा करना संभव था। याद पड़ता है कि यह portals से किया गया था, और editor में इसे सेट करना काफी दर्दनाक था
floor के मामले में, जहाँ तक मुझे पता है, DOOM भी इसे पूरी तरह सही तरीके से नहीं करता था। vertical walls में किसी खास wall segment के लिए pixel की हर column पर perspective division सिर्फ एक बार करना पड़ता है
लेकिन floor में यह सुविधा नहीं मिलती, और अगर याद सही है तो DOOM floor को patches में बाँटता था, फिर सही perspective सिर्फ corners पर calculate करता था और बीच के हिस्से को interpolate करता था
शुरुआत में मुझे यह बस Wolfenstein 3D का reskin लगा था। वह बहुत ही अनुचित आकलन था, और इसमें सचमुच बहुत सारा काम लगाया गया था
यह शानदार लेख है। खासकर gib animation बनाने का तरीका दिलचस्प लगा।
यह एक तकनीकी डेमो था, लेकिन 90 के दशक के मध्य में मैंने भी कुछ ऐसा ही बनाया था। एक बात जो इस लेख में नहीं दिखाई गई, वह यह थी कि texture पर 8x8 या 16x16 lightmap का उपयोग करके टिमटिमाती मशालें या गलियारे में उड़ते हुए रोशनी फैलाने वाले rocket जैसे effects आसानी से बनाए जा सकते थे। चाहें तो lighting को “bake” करने के लिए भी lightmap का उपयोग किया जा सकता था।
चूँकि lightmap “सिर्फ” 8x8 का होता था, इसलिए हर luxel, यानी lightmap की हर unit, के लिए light source तक की दूरी और line of sight निकालकर brightness value तय करने भर का गणित सम्भालना संभव था। texture render करते समय luxel को lookup table के साथ इस्तेमाल करके असल में draw होने वाले pixel का रंग तय किया जाता था।
performance के लिए, याद पड़ता है कि lightmap को प्रति सेकंड 15 बार update किया जाता था। DJGPP की बदौलत rendering में inline assembly इस्तेमाल की थी, और उस समय floating-point operations धीमे थे, इसलिए fixed-point arithmetic का उपयोग किया था, जो अच्छी तरह optimize हो जाता था। उस दौर के कंप्यूटरों के हिसाब से rendering performance हैरान करने वाली थी।
1990 के दशक की शुरुआत और मध्य का graphics programming काफ़ी मज़ेदार था। memory-mapped video RAM में pixel data लिखो और वह सीधे स्क्रीन पर दिख जाता था।
0xA0000 को point करने वाला एक pointer ही काफ़ी था, और किसी API की ज़रूरत नहीं पड़ती थी। यहाँ बताए गए non-square pixel 320×200 VGA mode का कारण यह था कि video buffer 64000 bytes का था, इसलिए वह 16-bit segment के भीतर आ जाता था और 16-bit code व CPU के लिए address करना आसान हो जाता था।
लेकिन उसी कमजोरी की वजह से स्क्रीन के हर pixel पर कहीं ज़्यादा काम किया जा सकता था, और इसी कारण ऐसे raycasting या BSP tree systems संभव हुए।
sprite और background layer के लिए dedicated processor नहीं थे, लेकिन इसी वजह से PC जो कर सकता था वह कठोर fixed-function architecture में कैद नहीं था।
90 के दशक के मध्य और उत्तरार्ध में dedicated 3D processors आ जाने के बाद यह समस्या नहीं रही, लेकिन 90 के दशक की शुरुआत में थोड़े समय के लिए अनोखी visual rendering का एक खेल का मैदान मौजूद था।
DJGPP और Free Pascal, DJ Delorie के उसी go32 extender का उपयोग करते हैं, और क्योंकि वह पूरी linear mapping नहीं करता था, इसलिए स्क्रीन पर कुछ दिखाने के लिए थोड़ा अतिरिक्त काम करना पड़ता था।
सबसे दिलचस्प चीज़ें अंदरूनी tools हैं। जैसे gib animation बनाने वाली Python script, या Blender से 2D spritesheet बनाने वाली दूसरी Python script।
मूल लेखक साफ़ तौर पर ऐसा 10x engineer लगता है जो अच्छी artwork भी बना सकता है, और मेरे हिसाब से ऐसे मामले सच में बहुत दुर्लभ होते हैं। यह भी काफ़ी चौंकाने वाली बात थी कि इसमें art direction इतनी consistent थी।
पिछले 15 सालों में game industry में, CEO या lead director को छोड़ दें तो मुझे शायद ही किसी का नाम पता है।
अभी-अभी मुझे एहसास हुआ कि यह शायद उन दुर्लभ shooters में से एक हो सकता है जिनमें महिला protagonist है। बिल्ली की calico pattern है, और ऐसी बिल्लियाँ लगभग हमेशा मादा होती हैं (https://en.wikipedia.org/wiki/Calico_cat)
क्या महिला protagonist वाले shooter इतने दुर्लभ हैं? तुरंत दिमाग में आने वाले काफ़ी mainstream उदाहरण ही लें तो Perfect Dark, Mirror's Edge, Dishonored 1 या 2, Metroid आदि सब किसी न किसी तरह shooter हैं और उनमें महिला protagonist है।
हालाँकि पूरी सटीकता से कहें तो Mirror's Edge “shooter” से ज़्यादा “first-person” के क़रीब है।
इसके अलावा “RPG + FPS” में भी बहुत सी ऐसी games हैं जिनमें आप पुरुष या महिला, दोनों में से किसी के रूप में खेल सकते हैं।
लगता है लेखक को भी pattern और बिल्ली के लिंग की संभावना का पता है:
After all, I do need to give the protagonist his fair share. [image] (Yes, I know it's a female, but call it convention rooted in dialect.)यह Perfect Dark game नहीं है।
आजकल boomer shooter में महिला protagonists काफ़ी हैं। उदाहरण के लिए Selaco[0], Supplice[1], The Citadel[2] और उसका sequel[3], Zortch[4] और उसका आने वाला sequel[5], Nightmare Reaper[6], COVEN[7], Viscerafest[8], Hedon[9] वगैरह।
बल्कि अब तो लगता है कि महिला protagonist वाले boomer shooters, उनके बिना वाले games से भी ज़्यादा हैं :-P Steam search में “boomer shooter” और “female protagonist” tags को मिलाकर देखें तो 143 results आते हैं, हालाँकि उनमें ऐसे games भी शामिल हैं जिनमें character gender चुना जा सकता है, या जिनमें ज़्यादातर समय पुरुष के रूप में खेलते हैं लेकिन कुछ हिस्सों में महिला के रूप में।
[0] https://store.steampowered.com/app/1592280/Selaco/
[1] https://store.steampowered.com/app/1693280/Supplice/
[2] https://store.steampowered.com/app/1378290/The_Citadel/
[3] https://store.steampowered.com/app/3371240/Beyond_Citadel/
[4] https://store.steampowered.com/app/2443360/Zortch/
[5] https://store.steampowered.com/app/3807500/Zortch_2/
[6] https://store.steampowered.com/app/1051690/Nightmare_Reaper/
शायद यह जानबूझकर नहीं किया गया होगा, लेकिन कुल मिलाकर ऐसी चीज़ों से मैं ज़्यादा प्रभावित नहीं होता और न ही उनमें कोई खास मूल्य देखता हूँ। Hollywood में महिलाओं को अपने से दोगुने आकार के पुरुषों को पीटकर गिराते हुए दिखाना भी ऐसा ही है
मुझे यह अवास्तविक, हास्यास्पद और हानिकारक लगता है
वाकई बहुत बढ़िया। 90 के दशक की एक और मज़ेदार ट्रिक palette animation थी। सिर्फ palette बदलकर ही बहुत कम runtime cost में बेहद शानदार effects बनाए जा सकते थे
सही। इस तकनीक का शानदार उदाहरण देखना हो तो मैं इस वेबसाइट की ज़ोरदार सिफारिश करता हूँ
http://www.effectgames.com/demos/canvascycle/
फ्रेम के बीच में palette बदलना भी मज़ेदार है। PC में Amiga के copper जैसी चीज़ नहीं थी, इसलिए timing पर कहीं ज़्यादा ध्यान देना पड़ता है, लेकिन फिर भी यह संभव है
मुझे याद है कि Diablo 1 और 2 के कई दुश्मन दरअसल एक ही sprite पर अलग palette चढ़ाकर बनाए गए थे। क्या यह वही ट्रिक है?
नीला पानी है, बैंगनी plasma है, और लाल/नारंगी खून या lava है
render करने के बाद quantized sprites इतने अच्छे दिखे, यह देखकर मैं सचमुच हैरान था। उस तेज़ conversion की वजह से वे बहुत crisp दिख रहे थे
एक fellow developer के तौर पर जो बेहिसाब कड़े constraints वाला 3D engine बना रहा है, यहाँ दिए गए विवरण और अपनाई गई प्रक्रिया को देखना मुझे सच में बहुत अच्छा लगा
मैं PlayStation homebrew के लिए voxel space rendering tech demo के साथ छेड़छाड़ कर रहा हूँ। वीकेंड के एक-दो दिन काम करने के बाद भी लगभग 10~15 FPS के अच्छे नतीजे मिल रहे हैं, और अभी तक मैंने DMA या GTE तो दूर, polyline primitive भी इस्तेमाल नहीं किया है
trigonometry और पुराने ज़माने की low-level optimization tricks को फिर से निकालना ताज़गी भरा है। जब scratch buffer सिर्फ 1KiB का हो और stack में भी उसका केवल एक हिस्सा ही इस्तेमाल किया जा सके, तब एहसास होता है कि काम पर जिन microcontrollers का मैं इस्तेमाल करता हूँ वे कितने शानदार हैं। वहाँ हर thread को 8KiB stack मिलता है, और C++ template functions की 50 से ज़्यादा परतों वाला backtrace भी निकल आता है।