मेरे अपने दृश्य ग्राफ को रोल करना


23

हैलो खेल विकास एसई!

मैं एक सरल और बहुत हल्के गेम इंजन बनाने की आशा के साथ ओपनजीएल के माध्यम से अपना रास्ता रेंग रहा हूं । मैं परियोजना को एक सीखने के अनुभव के रूप में देखता हूं जो अंत में थोड़ा पैसा कमा सकता है, लेकिन किसी भी तरह से मजेदार होगा।

अब तक मैंने GLFW का इस्तेमाल कुछ बुनियादी I / O, एक विंडो (ओह इतनी फैंसी F11 फुलस्क्रीन कुंजी के साथ) और निश्चित रूप से एक OpenGL संदर्भ प्राप्त करने के लिए किया है। मैंने भी GLEW का इस्तेमाल बाकी OpenGL एक्सटेंशन को दिखाने के लिए किया है क्योंकि मैं Windows का उपयोग कर रहा हूं और मैं सभी OpenGL 3.0+ का उपयोग करना चाहता हूं।

जो मुझे सीन ग्राफ में लाती है। संक्षेप में, मैं अपना रोल करना चाहूंगा। यह निर्णय ओएसजी को देखने और कुछ लेख पढ़ने के बाद आया कि कैसे एक दृश्य ग्राफ की अवधारणा मुड़, मुड़ी हुई और टूट गई है। इस तरह के एक लेख में बताया गया है कि कैसे दृश्य रेखांकन विकसित हुआ है ...

फिर हमने इस अतिरिक्त सामान में जोड़ा, जैसे कि क्रिसमस के पेड़ पर गहने लटकाए, सिवाय इसके कि कुछ गहने अच्छे रसदार हैं और कुछ पूरे जीवित गाय हैं।

सादृश्य के बाद, मैं स्टेक को पसंद करता हूं, एक दृश्य ग्राफ का मांस क्या होना चाहिए, बिना अतिरिक्त कोड के बवासीर या किसी भी पूरे गायों पर पट्टा करने के लिए।

तो इस बात को ध्यान में रखते हुए, मैं खुद को सोचता हूं कि वास्तव में एक दृश्य ग्राफ क्या होना चाहिए और एक साधारण दृश्य ग्राफ कैसे लागू किया जाना चाहिए? यहाँ मैं अब तक क्या है ...

एक माता-पिता, एन-बच्चों के पेड़ या डीएजी जो ...

  • खेल वस्तु रूपांतरण (स्थिति, रोटेशन, स्केल) का ट्रैक रखना चाहिए
  • अनुकूलन के लिए रेंडर राज्यों को रखना चाहिए
  • दृश्य हताशा के भीतर नहीं वस्तुओं को खींचने का एक साधन प्रदान करना चाहिए

निम्नलिखित गुणों के साथ ...

  • सभी नोड्स को रेंडर करने योग्य माना जाना चाहिए (भले ही वे रेंडर न करें) इसका मतलब है कि वे ...

    • सभी को सुस्त होना चाहिए (), राज्य () और ड्रा () तरीके (वापसी 0 यदि गैर-दिखाई देते हैं)
    • cull () पुनरावर्ती रूप से सभी बच्चों पर cull () कॉल करता है, इस प्रकार पूरे नोड और सभी बच्चों के लिए एक पूर्ण जाल मेष उत्पन्न होता है। एक अन्य विधि, हैचेंज () तथाकथित स्टैटिक मेश को अनुमति दे सकती है ताकि प्रत्येक फ्रेम में उनकी कलिंग ज्यामिति की आवश्यकता न पड़े। यह इस तरह से काम करेगा कि यदि उप-पेड़ में कोई नोड बदल गया है तो नीचे रूट के लिए सभी ज्यामिति को फिर से बनाया गया है।
  • रेंडर स्टेट्स को एक साधारण एन्यूमरेशन में आयोजित किया जाएगा, प्रत्येक नोड इस एन्यूमरेशन से एक ओपनजीएल स्टेट सेट का चयन करेगा, जिसे इसकी आवश्यकता होती है और उस नोड पर स्टेट को सेटअप करने से पहले सेटअप किया जाएगा। यह बैचिंग के लिए अनुमति देता है, दिए गए राज्य सेट के सभी नोड्स को एक साथ प्रस्तुत किया जाएगा, फिर अगला राज्य सेट सेटअप और इसी तरह होगा।

  • किसी भी नोड को सीधे ज्यामिति / शेडर / बनावट डेटा नहीं रखना चाहिए, इसके बजाय नोड्स को साझा ऑब्जेक्ट्स (शायद एक संसाधन प्रबंधक की तरह कुछ सिंगलटन ऑब्जेक्ट द्वारा प्रबंधित) को इंगित करना चाहिए।

  • दृश्य रेखांकन अन्य दृश्य रेखांकन (शायद एक प्रॉक्सी नोड का उपयोग करके) को इस तरह की स्थितियों की अनुमति देने में सक्षम होना चाहिए , इस प्रकार जटिल मल्टी-मेज़ मॉडल / ऑब्जेक्ट को एक टन डेटा जोड़े बिना दृश्य ग्राफ़ के आसपास कॉपी करने की अनुमति मिलती है।

मैं अपने मौजूदा डिजाइन पर कुछ मूल्यवान प्रतिक्रिया प्राप्त करने की उम्मीद कर रहा हूं। क्या यह लापता कार्यक्षमता है? वहाँ एक बहुत बेहतर तरीका / डिजाइन पैटर्न है? क्या मुझे कुछ बड़ी अवधारणा याद आ रही है जो कुछ हद तक सरल 3 डी गेम के लिए इस डिजाइन में शामिल करना आवश्यक होगा? आदि।

धन्यवाद, -कोडि

जवाबों:


15

संकल्पना

मौलिक रूप से, एक दृश्य ग्राफ एक द्वि-निर्देशित चक्रीय ग्राफ से अधिक कुछ नहीं है जो स्थानिक संबंधों के पदानुक्रम-संरचित सेट का प्रतिनिधित्व करने के लिए कार्य करता है।

जैसा कि नोट किया गया है, जंगली जीवों में दृश्य ग्राफ में अन्य अच्छाइयों को शामिल किया जाता है। चाहे आप देखते हैं कि मांस या गाय संभवतः आपके अनुभव पर निर्भर करता है कि वहां इंजन और पुस्तकालय हैं।

इसे लाइटवेट रखते हुए

मैं आपके दृश्य ग्राफ नोड होने के यूनिटी 3 डी शैली का समर्थन करता हूं (जो कि यह दिल है एक स्थानिक / स्थलाकृतिक संरचना के बजाय एक सामयिक है) स्वाभाविक रूप से स्थानिक मापदंडों और कार्यक्षमता को शामिल करते हैं। मेरे इंजन में, मेरे नोड्स यूनिटी 3 डी की तुलना में हल्के वजन के हैं, जहां वे सुपरक्लास / कार्यान्वित इंटरफेस से बहुत सारे अनावश्यक जंक सदस्यों को विरासत में देते हैं: यहां मेरे पास है - जितना प्रकाश आपको मिल सकता है:

  • माता-पिता / बच्चे सूचक सदस्य।
  • स्थानिक पैरामीटर सदस्यों को पूर्व-रूपांतरित करें: xyz स्थिति, पिच, यव और रोल।
  • एक परिवर्तन मैट्रिक्स; एक पदानुक्रमित श्रृंखला में मेट्रिसेस बहुत जल्दी और आसानी से पेड़ के ऊपर / नीचे चलकर गुणा कर सकते हैं, जिससे आपको पदानुक्रमित स्थानिक रूपांतर मिलेंगे जो एक दृश्य ग्राफ की मुख्य विशेषता है;
  • एक updateLocal()विधि जो केवल इस नोड के ट्रांसफॉर्म मैट्रेस को अपडेट करती है
  • एक updateAll()विधि जो इसे अपडेट करती है और सभी वंशज नोड्स के रूपांतरण को बदलते हैं

... मैं अपने नोड वर्ग में समीकरण-ऑफ-मोशन लॉजिक और इस प्रकार वेग / त्वरण सदस्य (रैखिक और कोणीय) शामिल करता हूं। आप इसे आगे बढ़ा सकते हैं, और यदि आप चाहें तो इसे अपने मुख्य नियंत्रक में संभाल सकते हैं। लेकिन वह यह है - वास्तव में बहुत हल्का। याद रखें, आप हजारों संस्थाओं पर ये कर सकते हैं। इसलिए जैसा कि आपने सुझाव दिया है, इसे हल्का रखें।

पदानुक्रम का निर्माण

आप एक दृश्य ग्राफ के बारे में क्या कहते हैं जो अन्य दृश्य रेखांकन को संदर्भित करता है ... मैं पंचलाइन की प्रतीक्षा कर रहा हूं? बेशक वे करते हैं। यही उनका मुख्य उपयोग है। आप किसी भी नोड को किसी भी अन्य नोड में जोड़ सकते हैं, और नए परिवर्तन के स्थानीय स्थान में परिवर्तन स्वचालित रूप से होने चाहिए। आप जो कुछ भी कर रहे हैं वह एक पॉइंटर को बदल रहा है, ऐसा नहीं है कि आप डेटा की नकल कर रहे हैं! एक पॉइंटर बदलने से, आपके पास फिर एक गहरा दृश्य ग्राफ होता है। अगर प्रॉक्सी का उपयोग करना चीजों को और अधिक कुशल बनाता है तो हर तरह से, लेकिन मैंने कभी जरूरत नहीं देखी।

रेंडर से जुड़े लॉजिक से बचें

रेंडरिंग के बारे में भूल जाते हैं क्योंकि आप अपने दृश्य ग्राफ नोड क्लास को लिखते हैं, या आप अपने लिए चीजों को भ्रमित करेंगे। यह सब मायने रखता है कि आपके पास एक डेटा मॉडल है - चाहे वह दृश्य ग्राफ हो या नहीं, इससे कोई फर्क नहीं पड़ता - और कुछ रेंडरर उस डेटा मॉडल का निरीक्षण करने जा रहा है और उसके अनुसार दुनिया में वस्तुओं को प्रस्तुत करता है, चाहे वह 1, 2 में हो। , 3 या 7 आयाम। मैं जो बिंदु बना रहा हूं वह यह है: अपने दृश्य ग्राफ को तर्क प्रस्तुत करने के साथ दूषित न करें। एक दृश्य ग्राफ टोपोलॉजी और स्थलाकृति के बारे में है - अर्थात कनेक्टिविटी और स्थानिक विशेषताएं। ये अनुकार की वास्तविक स्थिति हैं और प्रतिपादन की अनुपस्थिति में भी मौजूद हैं (जो कि किसी व्यक्ति के पहले चित्र से लेकर आलेखीय विवरण तक सूर्य के नीचे कोई भी रूप ले सकता है)। नोड्स रेंडरिंग-संबंधित ऑब्जेक्ट को इंगित नहीं करते हैं - हालांकि रिवर्स अच्छी तरह से सच हो सकता है। इस पर भी विचार करें: आपके पूरे पेड़ में प्रत्येक दृश्य ग्राफ नोड रेंडर करने योग्य नहीं होगा। कई सिर्फ कंटेनर होंगे। तो एक पॉइंटर-टू-रेंडर-ऑब्जेक्ट के लिए मेमोरी क्यों आवंटित करें? यहां तक ​​कि एक पॉइंटर सदस्य जो कभी भी उपयोग नहीं किया जाता है, अभी भी मेमोरी ले रहा है। इसलिए पॉइंटर दिशा को उल्टा करें: रेंडर-संबंधित उदाहरण डेटा मॉडल (जो आपके दृश्य ग्राफ नोड हो सकता है या शामिल हो सकता है) का संदर्भ देता है, न कि इसके विपरीत। और यदि आप नियंत्रक की अपनी सूची के माध्यम से चलाने का एक आसान तरीका चाहते हैं, फिर भी संबंधित दृश्य तक पहुंच प्राप्त करते हैं, तो एक शब्दकोश / हैशटेबल का उपयोग करें, जो ओ (1) पढ़ने के समय का उपयोग करता है। इस तरह से कोई संदूषण नहीं है, और आपके सिमुलेशन तर्क को परवाह नहीं है कि रेंडरर्स जगह में हैं, जो कोडिंग के आपके दिन और रात बनाता है तो एक पॉइंटर-टू-रेंडर-ऑब्जेक्ट के लिए मेमोरी क्यों आवंटित करें? यहां तक ​​कि एक पॉइंटर सदस्य जो कभी भी उपयोग नहीं किया जाता है, अभी भी मेमोरी ले रहा है। इसलिए पॉइंटर दिशा को उल्टा करें: रेंडर-संबंधित उदाहरण डेटा मॉडल (जो आपके दृश्य ग्राफ नोड हो सकता है या शामिल हो सकता है) का संदर्भ देता है, न कि इसके विपरीत। और यदि आप नियंत्रक की अपनी सूची के माध्यम से चलाने का एक आसान तरीका चाहते हैं, फिर भी संबंधित दृश्य तक पहुंच प्राप्त करते हैं, तो एक शब्दकोश / हैशटेबल का उपयोग करें, जो ओ (1) पढ़ने के समय का उपयोग करता है। इस तरह से कोई संदूषण नहीं है, और आपके सिमुलेशन तर्क को परवाह नहीं है कि रेंडरर्स जगह में हैं, जो कोडिंग के आपके दिन और रात बनाता है तो एक पॉइंटर-टू-रेंडर-ऑब्जेक्ट के लिए मेमोरी क्यों आवंटित करें? यहां तक ​​कि एक पॉइंटर सदस्य जो कभी भी उपयोग नहीं किया जाता है, अभी भी मेमोरी ले रहा है। इसलिए पॉइंटर दिशा को उल्टा करें: रेंडर-संबंधित उदाहरण डेटा मॉडल (जो आपके दृश्य ग्राफ नोड हो सकता है या शामिल हो सकता है) का संदर्भ देता है, न कि इसके विपरीत। और यदि आप नियंत्रक की अपनी सूची के माध्यम से चलाने का एक आसान तरीका चाहते हैं, फिर भी संबंधित दृश्य तक पहुंच प्राप्त करते हैं, तो एक शब्दकोश / हैशटेबल का उपयोग करें, जो ओ (1) पढ़ने के समय का उपयोग करता है। इस तरह से कोई संदूषण नहीं है, और आपके सिमुलेशन तर्क को परवाह नहीं है कि रेंडरर्स जगह में हैं, जो कोडिंग के आपके दिन और रात बनाता है और यदि आप नियंत्रक की अपनी सूची के माध्यम से चलाने का एक आसान तरीका चाहते हैं, फिर भी संबंधित दृश्य तक पहुंच प्राप्त करते हैं, तो एक शब्दकोश / हैशटेबल का उपयोग करें, जो ओ (1) पढ़ने के समय का उपयोग करता है। इस तरह से कोई संदूषण नहीं है, और आपके सिमुलेशन तर्क को परवाह नहीं है कि रेंडरर्स जगह में हैं, जो कोडिंग के आपके दिन और रात बनाता है और यदि आप नियंत्रक की अपनी सूची के माध्यम से चलाने का एक आसान तरीका चाहते हैं, फिर भी संबंधित दृश्य तक पहुंच प्राप्त करते हैं, तो एक शब्दकोश / हैशटेबल का उपयोग करें, जो ओ (1) पढ़ने के समय का उपयोग करता है। इस तरह से कोई संदूषण नहीं है, और आपके सिमुलेशन तर्क को परवाह नहीं है कि रेंडरर्स जगह में हैं, जो कोडिंग के आपके दिन और रात बनाता हैदुनिया आसान है।

पुलिंग के लिए, ऊपर देखें। एरिया-ऑफ-इंटरेस्ट कलिंग एक सिमुलेशन लॉजिक कॉन्सेप्ट है। यानी, आप इस (आमतौर पर बॉक्सिंग, गोलाकार या गोलाकार) क्षेत्र के बाहर की दुनिया को संसाधित नहीं करते हैं। रेंडरिंग होने से पहले यह मुख्य कंट्रोलर / गेम लूप में होता है। दूसरी ओर, फ्रिंज कलिंग विशुद्ध रूप से रेंडर-संबंधित है। इसलिए अभी से भूल जाना। इसका दृश्य आलेखों से कोई लेना-देना नहीं है, और इस पर ध्यान केंद्रित करके आप जो हासिल करने की कोशिश कर रहे हैं उसका सही उद्देश्य अस्पष्ट होगा।

एक अंतिम नोट ...

मुझे वह प्रबल अनुभूति होती है जो आप फ्लैश (विशेष रूप से एएस 3) पृष्ठभूमि से कर रहे हैं, यहां दिए गए रेंडरिंग के बारे में सभी विवरण दिए गए हैं। हां, फ्लैश स्टेज / डिस्प्लेऑबजेक्ट प्रतिमान में दृश्य के भाग के रूप में सभी रेंडर लॉजिक शामिल हैं। लेकिन फ्लैश बहुत सारी धारणाएं बनाता है जिन्हें आप जरूरी नहीं बनाना चाहते हैं। पूरी तरह से खेल इंजन के लिए, उचित SoC के माध्यम से कोड जटिलता के प्रदर्शन, सुविधा और नियंत्रण के कारणों के लिए, दोनों को मिश्रण नहीं करना बेहतर है ।


1
धन्यवाद निक। मैं वास्तव में एक 3D एनिमेटर हूं (असली 3D फ्लैश नहीं) प्रोग्रामर बन गया, इस प्रकार मैं ग्राफिक्स के बारे में सोचना चाहता हूं। यदि यह काफी बुरा नहीं है, तो मैंने जावा में शुरुआत की और उस भाषा में "सब कुछ एक वस्तु होनी चाहिए" मानसिकता से खुद को चुभ रहा है। आपने मुझे आश्वस्त किया है कि दृश्य ग्राफ को रेंडरिंग और कोडिंग कोड से अलग किया जाना चाहिए, अब मेरे गियर बिल्कुल उसी तरह से घूम रहे हैं जो कि पूरा होना चाहिए। मैं रेंडरर का इलाज करने के बारे में सोच रहा हूं जैसे कि यह एक अलग प्रणाली है जो डेटा को रूपांतरित करने के लिए दृश्य ग्राफ का संदर्भ देता है, आदि
Cody Smith

1
@ कोडीस्मिथ, खुशी है कि यह मदद की। बेशर्म प्लग, लेकिन मैं एक ढांचा बनाए रखता हूं जो SoC / MVC के बारे में है। ऐसा करने के लिए, मैं उद्योग में अधिक परंपरागत शिविर के साथ आ रहा हूं जो जोर देकर कहता है कि सब कुछ एक केंद्रीय, अखंड वस्तु में होना चाहिए। लेकिन यहां तक ​​कि वे आम तौर पर आपको बताएंगे - अपने प्रतिपादन को अपने दृश्य ग्राफ से अलग रखें। एसओसी / एसआरपी एक ऐसी चीज है जिस पर मैं पर्याप्त जोर नहीं दे सकता - कभी भी जरूरत से ज्यादा तर्क को एक ही वर्ग में न मिलाएं। मैं एक ही कक्षा में मिश्रित तर्क पर जटिल OO वंशानुक्रम श्रंखलाओं की वकालत करता, अगर आप मेरे सिर पर बंदूक रख देते!
इंजीनियर

नहीं, मुझे अवधारणा पसंद है। और आपका अधिकार, यह SoC का पहला उल्लेख है जिसे मैंने गेम डिज़ाइन के बारे में पढ़ने के वर्षों में कहीं भी देखा है। एक बार फिर धन्यवाद।
कोडी स्मिथ 20

@CodySmith क्विक ने इस पर फिर से ब्राउज़ करते हुए सोचा। सामान्य तौर पर, चीजों को डिकौप्ड रखना अच्छा होता है। अपने codebase में मॉडल नियंत्रक वस्तुओं है कि प्रतिपादन गुजरना के विभिन्न प्रकार के लिए, तथापि, यह है आप का संग्रह रखने के लिए के लिए ठीक Renderableरों उन कोर मॉडल नियंत्रक वस्तुओं के लिए आंतरिक रूप से (जो एक इंटरफ़ेस या अमूर्त वर्ग है)। इसके अच्छे उदाहरण हैं इकाइयाँ या यूआई तत्व। इस प्रकार आप तेजी से केवल उन रेंडरर्स को उस विशेष कोर ऑब्जेक्ट के लिए प्रासंगिक रूप से एक्सेस कर सकते हैं - कार्यान्वयन के विनिर्देश के बिना जो इकाई वर्ग को दूषित करेगा, इसलिए इंटरफेस का उपयोग।
इंजीनियर

@CodySmith संस्थाओं के साथ लाभ स्पष्ट है, जो उदाहरण के लिए हो सकता है। विश्व व्यूपोर्ट में और न्यूनतम पर दोनों का प्रतिनिधित्व करते हैं। इसलिए, संग्रह। वैकल्पिक रूप से, आप प्रत्येक मॉडल-नियंत्रक ऑब्जेक्ट के लिए केवल एक रेंडरर स्लॉट की अनुमति दे सकते हैं, आंतरिक रूप से उस ऑब्जेक्ट के लिए। लेकिन इंटरफ़ेस को सामान्य रखें! कोई बारीकियों - बस Renderer
इंजीनियर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.