C में 3D मॉडलर बनाना एक हफ्ते में
- पिछले साल के शरद ऋतु में मैंने "Wheel Reinvention Jam" नाम के एक सप्ताह लंबी प्रोग्रामिंग इवेंट में भाग लिया
- मकसद यह था कि मौजूदा सॉफ्टवेयर सिस्टम को एक नए नज़रिए से फिर से देखने का प्रयास करना
- मैंने "ShapeUp" नाम का एक 3D मॉडलर बनाया, और इस लेख को पढ़ने से पहले ShapeUp का डेमो वीडियो देख लेने से समझना आसान होगा
- ShapeUp को सीधे ब्राउज़र में जाकर टेस्ट किया जा सकता है
भाषा चयन: C
- TypeScript compiler की स्लो परफॉर्मेंस से परेशान होकर मैंने Jam में हिस्सा लिया
- अगर esbuild या Bun के TypeScript parser से शुरुआत की जाए, तो TypeScript का तेज़ subset implement करने वाला project शायद संभव लगता था
- लेकिन टर्मिनल कमांड execution speed की तुलना से कोई अच्छा demo नहीं बनता, इसलिए मैंने दिशा 3D project की ओर बदल दी
- Ray-marched signed distance fields (SDFs) की वजह से मुझे लगा कि सिर्फ एक हफ्ते में शुरुआत से 3D project बनाना संभव है
- समान स्तर के triangle-based renderer की तुलना में, SDF का इस्तेमाल करके scene कहीं जल्दी implement की जा सकती है
- पहले मैंने SDF shader लिखा था, लेकिन वह बहुत बेसिक स्तर का था, और code edit करके मॉडलिंग करना प्राकृतिक नहीं लग रहा था
- मैं माउस से shape edit करना चाहता था, और इस Jam को वही मौका समझा
- मैंने project का नाम ShapeUp रखा
C भाषा प्रयोग करने के फायदे
- C बहुत सरल और मूलभूत (low-level) भाषा है, इसलिए मुझे लगा कि इसमें built-in data structures की कमी और pointer bugs सुधारने में बहुत समय लग जाता है
- लेकिन इसी simplicity ने फायदे दिए
- जल्दी compile होता है
- सिंटैक्स किसी जटिल ऑपरेशन को छुपाती नहीं
- बहुत सरल है, इसलिए बार-बार सिंटैक्स खोजने की जरूरत नहीं पड़ती
- native और web assembly में आसानी से compile हो जाता है
- C की कमियाँ मैंने 22 साल के अनुभव से बने habits के जरिए संभाल लीं
- ShapeUp एक छोटा-सा single C file प्रोजेक्ट है, इसलिए बहुत सरल दिखता है
ShapeUp की डाटा संरचना
- मॉडल
Shapes नाम के एक संरचना (struct) के array से बना है
- Shapes को statically allocated array में रखा गया है
- allocation failure या memory leak का risk नहीं रहता
- 100 Shapes की सीमा वास्तव में restrictive नहीं थी
- renderer optimization के लिए समय न होने से frame rate शायद 100 पर पहुंचने से पहले ही गिरने लगता
- अगर समय होता तो मैं मॉडल को छोटे blocks में विभाजित करके हर block के अंदर raymarching करता
- dynamic memory सिर्फ 3 जगहों पर
malloc call की गई
- save (पूरे document को hold करने लायक बड़ा buffer allocate करना)
- OBJ export (सभी vertices को hold करने के लिए बड़ा buffer allocate करना)
- GLSL shader generation (shader source के लिए buffer)
- हर case में function के अंतिम भाग में एक ही
free है
- यह उदाहरण दिखाता है कि C में memory management कितना सरल हो सकता है
- C#, JavaScript, Python जैसी भाषाएँ Shape के लिए अलग-अलग malloc कर प्रत्येक pointer को dynamic array में रखने वाली allocation शैली लागू करती हैं
- C में memory layout control करना आसान है
यूज़र इंटरफेस
- इसे immediate mode user interface (IMGUI) से implement किया गया
- मुझे IMGUI शैली का UI पसंद है
- debugging बहुत आसान हो जाता है
- elements को place करने के लिए वास्तविक programming language इस्तेमाल की जा सकती है (CSS, constraints, SwiftUI की तुलना में)
- अधिकांश IMGUI की तरह यहाँ भी enum से track करते हैं कि किस element पर focus है या mouse क्या action कर रहा है
- इस project में dynamic array या hashmap की ज़रूरत नहीं थी, लेकिन जरूरत होती तो
stb_ds.h जैसा कुछ use करता
Raylib लाइब्रेरी की समस्याएँ
- C चुनना सही था, लेकिन Raylib समस्या बन गया
- डेवलपर experience को कमजोर करने वाली कुछ अजीब design choices हैं
- जहाँ enum अपेक्षित है वहाँ
int use करके compiler type checking रोक दी गई और functions self document नहीं होते
- डिफ़ॉल्ट parameter validation नहीं होता (इन्हें डिज़ाइन चयन मानना चाहिए)
- dependencies के लिए ownership नहीं लेता (GLFW issues हल नहीं करता और patch नहीं भेजता)
- raygui UI library लगभग toy ही है
- floating point numbers दिखा नहीं सकता
- overlapping या clipped elements के लिए mouse event routing नहीं संभालता
- rounded corners बना नहीं सकता
- अच्छे तरीके से style नहीं कर सकता
- bugs भी हैं
- font बदलने को रोकने वाला bug
- draw function triangles के बीच साझा vertices न होने से pixel gaps छोड़ देता है
- हर समस्या मिलने पर report भेजी, लेकिन ज्यादातर "won't fix" कहकर बंद हो गया और bug report लिखने में बहुत समय खर्च होने से छोड़ दी
- OpenGL window दे देने में मदद हुई, लेकिन उस सुविधा की कीमत बहुत भारी पड़ी
- शुक्र है कि सीधे OpenGL functions उपयोग करने या शुरुआत से feature बनाने का रास्ता मिल गया
- आगे से मैं
sokol use करने वाला हूँ
एक हफ्ते की डेवलपमेंट प्रक्रिया
- ShapeUp को 6 दिन में खत्म करने के लिए 4 प्रमुख हिस्सों में बाँटा गया था
- यूज़र इंटरफेस (3D tools, keyboard shortcuts, sidebar, game controller)
- GLSL shader generator + Ray marching renderer
- GPU-based mouse picking
- export के लिए Marching cubes
- हर हिस्सा कठिन नहीं था, पर सही priority सेट करना और बीच में अटकना avoid करना कठिन रहा
- कठिन या time-consuming problems का समाधान अक्सर design से किया गया, या फिर 90% cases में काम करने वाले सरल solutions से
- कभी-कभी किसी feature को एक दिन के लिए छोड़ देने पर अनजाने में हल मिल गया
- हमेशा एक काम करने वाला 3D modeler पास था, और समय मिलते ही उसे धीरे-धीरे बेहतर करता गया
- मुझे यह pyramid बनाने जैसा लगा; स्तर दर स्तर बनाओ, आखिरी लेयर तक शायद pyramid पूरा न हो, पर किसी भी stage पर रुक जाओ तो एक complete pyramid जैसा दिख सकता है
प्रोजेक्ट का परिणाम
- एक हफ्ते बाद मेरे पास एक meaningful 3D model बनाने वाला और
.obj फ़ाइल में export करने वाला 3D program था
- यह multi-platform पर चलता है और open/save दोनों features मौजूद हैं
- परियोजना में 2024 लाइन C code और 250 लाइन GLSL है
- लगभग 2300 लाइन में ही काफ़ी उपयोगी 3D मॉडलर दिखाया जा सकता है—यह थोड़ा चौंकाने वाला था
- मुझे Jam recap और Handmade Seattle conference में ShapeUp demo दिखाने का invite मिला
- लोगों ने शायद ShapeUp से प्रभावित होकर देखा, लेकिन बहुत बड़ी सफलता जैसा नहीं लगा; यह अपेक्षाकृत छोटा/simple project था
- अगर मेरे काम में कोई खास बात थी, तो यह था कि क्या बनाना है उसकी सही समझ, उसे बनाने का ज्ञान, और एक हफ्ते में काम पूरा करने की discipline
GN⁺ की राय
- C की simplicity और speed दिखाने वाला यह दिलचस्प project है। लेकिन इसकी low abstraction level के कारण इसे सीधे production में इस्तेमाल करना मुश्किल दिखता है। आधुनिक 3D मॉडलिंग tools की सभी features अगर C में खुद implement की जाएँ तो बेहद भारी प्रयास चाहिए होगा
- एक हफ्ते में काम करने वाला program बना देना impressive है। लेकिन लंबी अवधि के नज़रिए से code maintenance और feature expansion देखें तो शायद C++ या Rust बेहतर विकल्प हैं
- SDF rendering तेज़ और आसान है, लेकिन modeling की freedom और quality में इसकी सीमा दिखती है। commercial modeling tools आमतौर पर SubD या NURBS जैसी surface modeling techniques पर निर्भर करते हैं। लेकिन games या demos जैसे real-time महत्वपूर्ण क्षेत्रों में SDF rendering अभी भी बहुत उपयोगी दिखती है
- यह open source library चुनने की कठिनाइयों का अच्छा उदाहरण है। दस्तावेज़, code quality और support को सही से परखकर तय करना चाहिए; खुद implement करना भी अच्छा विकल्प हो सकता है
- पहले काम करने वाला program बनाना और धीरे-धीरे सुधार करना production में भी बहुत practical है। core features पहले मजबूत करें और बाद में details सुधारते जाएँ—priority सही सेट करना ज़रूरी लगता है
1 टिप्पणियां
Hacker News टिप्पणियाँ