आधुनिक तरीके से ओपनजीएल के साथ बहुत सारी टाइलें खींचना


35

मैं लोगों की एक टीम के साथ एक छोटी टाइल / स्प्राइट-आधारित पीसी गेम पर काम कर रहा हूं, और हम प्रदर्शन के मुद्दों पर चल रहे हैं। पिछली बार मैंने ओपनजीएल का उपयोग 2004 के आसपास किया था, इसलिए मैं खुद को सिखा रहा हूं कि कोर प्रोफाइल का उपयोग कैसे करें, और मैं खुद को थोड़ा भ्रमित कर रहा हूं।

मुझे 250-750 48x48 टाइलों के पड़ोस में स्क्रीन को हर फ्रेम पर खींचने की आवश्यकता है, साथ ही साथ लगभग 50 स्प्राइट भी। टाइलें केवल तब बदलती हैं जब एक नया स्तर लोड होता है, और स्प्राइट हर समय बदल रहे हैं। कुछ टाइलें चार 24x24 टुकड़ों से बनी होती हैं, और स्प्राइट्स के अधिकांश (लेकिन सभी नहीं) टाइल्स के आकार के समान होते हैं। बहुत सारी टाइलें और स्प्राइट अल्फा सम्मिश्रण का उपयोग करते हैं।

अभी मैं यह सब तत्काल मोड में कर रहा हूं, जो मुझे पता है कि एक बुरा विचार है। वही सब, जब हमारी टीम के सदस्यों में से एक इसे चलाने की कोशिश करता है, तो उसे बहुत खराब फ्रेम दर (~ 20-30 एफपीएस) मिलती है, और यह अधिक खराब होता है जब अधिक टाइलें होती हैं, खासकर जब उन टाइलों में से बहुत से प्रकार होते हैं टुकड़ों में काट दिया जाता है। यह सब मुझे लगता है कि समस्या ड्रॉ कॉल की संख्या है।

मैंने इसके कुछ संभावित समाधानों के बारे में सोचा है, लेकिन मैं उन्हें कुछ लोगों द्वारा चलाना चाहता था, जो जानते हैं कि वे किस बारे में बात कर रहे हैं, इसलिए मैं अपना समय कुछ बेवकूफी में बर्बाद नहीं करता:

टाइल्स:

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

स्प्राइट:

  1. प्रत्येक स्प्राइट को अलग-अलग कॉल के साथ ड्रा करें। ऐसा लगता है कि बहुत सारी बनावट स्विच करना शामिल है, जो मुझे बताया गया है कि खराब है। क्या बनावट सरणियाँ शायद यहाँ उपयोगी हैं?
  2. किसी तरह गतिशील वीबीओ का उपयोग करें। ऊपर नंबर 2 के रूप में एक ही बनावट सवाल।
  3. प्वाइंट स्प्राइट? यह शायद मूर्खतापूर्ण है।

क्या इनमें से कोई भी विचार समझदार है? क्या कहीं अच्छा कार्यान्वयन है जो मैं देख सकता था?


यदि टाइलें हिल नहीं रही हैं और न ही बदल रही हैं और वे पूरे स्तर पर समान दिखती हैं, तो आपको पहले विचार - फ्रेम बफर का उपयोग करना चाहिए। यह सबसे कुशल होगा।
22 दिसंबर को zacharmarz

एक बनावट एटलस का उपयोग करने का प्रयास करें ताकि आपको बनावट को स्विच करने की आवश्यकता न हो, लेकिन बाकी सब कुछ समान रखें। अब उनकी फ्रामर्ट कैसे?
user253751

जवाबों:


25

टाइल्स को रेंडर करने का सबसे तेज़ तरीका इंडेक्स के साथ एक स्थैतिक वीबीओ में वर्टेक्स डेटा को पैक करना है (जैसा कि ग्लड्रॉवल्स इंगित करता है)। इसे दूसरी छवि में लिखना पूरी तरह अनावश्यक है और इसके लिए केवल बहुत अधिक स्मृति की आवश्यकता होगी। बनावट स्विचिंग बहुत महंगा है, इसलिए आप शायद सभी टाइलों को एक तथाकथित बनावट एटलस में पैक करना चाहेंगे और वीबीओ में प्रत्येक त्रिकोण को सही बनावट निर्देशांक देंगे। इसके आधार पर, यह आपके हार्डवेयर के आधार पर 1000, यहां तक ​​कि 100000 टाइल्स को रेंडर करने के लिए समस्या नहीं होनी चाहिए।

टाइल रेंडरिंग और स्प्राइट रेंडरिंग के बीच एकमात्र अंतर यह है कि स्प्राइट गतिशील हैं। तो सबसे अच्छा, अभी तक आसान आसान प्रदर्शन के लिए, आप बस एक फ्रेम ड्रा VBO प्रत्येक फ्रेम में और glDrawElements के साथ आकर्षित करने के लिए स्प्राइट कोने के लिए निर्देशांक डाल सकते हैं। इसके अलावा एक बनावट एटलस में सभी बनावट पैक। यदि आपका स्प्राइट शायद ही कभी स्थानांतरित होता है, तो आप एक गतिशील वीबीओ बनाने की कोशिश भी कर सकते हैं और जब स्प्राइट चलता है, तो इसे अपडेट कर सकते हैं, लेकिन यहां कुल ओवरकिल है, क्योंकि आप केवल कुछ स्प्राइट्स प्रस्तुत करना चाहते हैं।

आप ओपन ++: पार्टिकुलेट के साथ C ++ में बनाए गए एक छोटे प्रोटोटाइप को देख सकते हैं

मैं एक सामान्य मशीन (क्वाड कोर @ 2.66GHz) पर 400 के औसत एफपीएस के साथ लगभग 10000 पॉइंट स्प्राइट्स प्रदान करता हूं। यह सीपीयू कैप्ड है, इसका मतलब है कि ग्राफिक्स कार्ड और भी अधिक प्रस्तुत कर सकता है। ध्यान दें कि मैं यहां बनावट एटलस का उपयोग नहीं करता हूं, क्योंकि मेरे पास कणों के लिए केवल एक ही बनावट है। कणों को GL_POINTS के साथ प्रस्तुत किया जाता है और शेड्स वास्तविक क्वाड आकार की गणना करते हैं, लेकिन मुझे लगता है कि एक क्वाड प्रेंडरर भी है।

ओह, और हां, जब तक आपके पास एक वर्ग नहीं है और बनावट मानचित्रण के लिए शेड का उपयोग करते हैं, GL_POINTS काफी मूर्खतापूर्ण है। ;)


स्प्राइट्स अपनी स्थिति को बदलते हैं और वे किस बनावट का उपयोग कर रहे हैं, और उनमें से ज्यादातर हर फ्रेम में ऐसा करते हैं। इसके अलावा, स्प्राइट और बनाया जा रहा है और बहुत बार नष्ट हो जाता है। क्या ये चीजें हैं जो एक स्ट्रीम ड्रा VBO को संभाल सकती हैं?
निक

2
मूल रूप से स्ट्रीम ड्रा का अर्थ है: "इस डेटा को ग्राफिक्स कार्ड पर भेजें और ड्राइंग के बाद इसे छोड़ दें"। इसलिए आपको डेटा को प्रत्येक फ्रेम में फिर से भेजना होगा और इसका मतलब है कि इससे कोई फर्क नहीं पड़ता कि आप कितने स्प्राइट प्रस्तुत करते हैं, उनकी क्या स्थिति है, कौन सी बनावट समन्वय करती है या किस रंग की है। लेकिन एक ही बार में सभी डेटा भेजने और GPU प्रक्रिया यह एक बहुत तत्काल मोड से तेज है, ज़ाहिर है।
मार्को

यह सब समझ में आता है। क्या इसके लिए एक सूचकांक बफर चीज़ का उपयोग करना इसके लायक है? केवल वही अनुलंब दोहराए जाएंगे जो प्रत्येक आयत से दो कोने हैं, है ना? (मेरी समझ यह है कि सूचकांक glDrawElements और glDrawArrays के बीच का अंतर है। क्या यह सही है?)
निक

1
सूचकांकों के बिना आप GL_TRIANGLES का उपयोग नहीं कर सकते हैं, जो आमतौर पर खराब होता है, क्योंकि यह ड्राइंग विधि गुरुंटेड सर्वश्रेष्ठ प्रदर्शन वाला है। इसके अलावा, GL_QUADS कार्यान्वयन OpenGL 3.0 (स्रोत: stackoverflow.com/questions/6644099/… ) में चित्रित किया गया है । त्रिकोण किसी भी ग्राफिक्स कार्ड के मूल जाल हैं। तो, आप "2" 6 * बाइट को 2 वर्टेक्स शडर एग्जीक्यूटिव और वर्टेक्स_साइज़ * 2 बाइट को बचाने के लिए "अधिक" का उपयोग करते हैं। तो, आप आम तौर पर कह सकते हैं कि यह हमेशा बेहतर है।
मार्को

2
पार्टिकुलेट का लिंक मर चुका है ... क्या आप कृपया एक नया प्रदान कर सकते हैं?
SWDV

4

यहां तक ​​कि ड्रॉ कॉल्स की इस संख्या के साथ आपको उस तरह की प्रदर्शन ड्रॉप को नहीं देखना चाहिए - तत्काल मोड धीमा हो सकता है, लेकिन यह धीमा नहीं है (संदर्भ के लिए, यहां तक ​​कि प्रिय-पुराने क्वेक गिरने के बिना प्रति फ्रेम कई हजार तत्काल-मोड कॉल का प्रबंधन कर सकता है। इतनी बुरी तरह से नीचे)।

मुझे संदेह है कि यहां कुछ और दिलचस्प चल रहा है। पहली चीज जो आपको करने की ज़रूरत है वह आपके कार्यक्रम को रूपरेखा बनाने में कुछ समय का निवेश करता है, अन्यथा आप एक धारणा के आधार पर खोज का एक बड़ा जोखिम उठाते हैं जिसके परिणामस्वरूप शून्य प्रदर्शन लाभ हो सकता है। तो इसे भी कुछ के माध्यम से चलाने के रूप में बुनियादी GLIntercept के रूप में और देखें कि आपका समय कहाँ जा रहा है। उस के परिणामों के आधार पर आप अपनी वास्तविक अड़चन के बारे में कुछ वास्तविक जानकारी के साथ समस्या से निपटने में सक्षम होंगे / हैं।


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

फिर राज्य परिवर्तन कैसे? क्या आप राज्य द्वारा अपनी अपारदर्शी टाइलें समूहित कर रहे हैं?
मैक्सिमस मिनिमस

यह एक संभावना है। यह निश्चित रूप से मेरी ओर से अधिक ध्यान देने योग्य है।
निक

2

ठीक है, चूंकि मेरा अंतिम उत्तर थोड़े हाथों से निकला है, इसलिए एक नया एक विच शायद अधिक उपयोगी है।


2D- प्रदर्शन के बारे में

पहली कुछ सामान्य सलाह: 2 डी वर्तमान हार्डवेयर के लिए मांग नहीं कर रहा है, यहां तक ​​कि मोटे तौर पर बिना कोड वाला कोड भी काम करेगा। इसका मतलब यह नहीं है कि आपको इंटरमीडिएट मोड चाहिए, कम से कम यह सुनिश्चित करें कि आप राज्यों को तब न बदलें जब अनावश्यक (उदाहरण के लिए ग्लिबिंडटेक्चर के साथ एक नई बनावट को बांधना नहीं है, जब एक ही बनावट पहले से ही बाध्य है, अगर सीपीयू पर एक जांच टन है। glBindTexture-call की तुलना में तेज़) और glVertex के रूप में कुछ पूरी तरह से गलत और बेवकूफ का उपयोग न करने के लिए (यहाँ तक कि glDrawArrays तेजी से रास्ता होगा, और उपयोग करने के लिए और अधिक कठिन नहीं है, हालांकि यह बहुत "आधुनिक" नहीं है)। उन दो बहुत ही सरल नियमों के साथ फ्रेम का समय कम से कम 10ms (100 एफपीएस) होना चाहिए। अब और भी अधिक गति प्राप्त करने के लिए अगला लॉजिकल स्टेप बैचिंग है, जैसे कि एक में कई ड्रॉ कॉल करना, इसके लिए आपको बनावट एटलस को लागू करने पर विचार करना चाहिए, इसलिए आप बनावट की मात्रा को कम कर सकते हैं और इस प्रकार आप एक कॉल के साथ बड़ी मात्रा में आयतों को बढ़ा सकते हैं। यदि आप अब लगभग 2ms (500fps) के लिए नीचे नहीं हैं, तो आप कुछ गलत कर रहे हैं :)


टाइल के नक्शे

टाइल के नक्शे के लिए ड्राइंग कोड को लागू करने से लचीलापन और गति के बीच संतुलन का पता चलता है। आप स्थैतिक VBOs का उपयोग कर सकते हैं, लेकिन यह एनिमेटेड टाइल्स के साथ काम नहीं करेगा या आप केवल प्रत्येक फ्रेम में वर्टेक्स डेटा उत्पन्न कर सकते हैं और मेरे द्वारा ऊपर बताए गए नियमों को लागू कर सकते हैं, बहुत ही लचीले लेकिन अभी तक तेजी से नहीं।

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


स्प्राइट

स्प्राइट्स को बहुत लचीलेपन की आवश्यकता होती है, जिससे इसे अनुकूलित करना बहुत कठिन हो जाता है, जो "लगभग 2 डी-प्रदर्शन" अनुभाग में चर्चा की जाती है। और जब तक आप एक ही समय में स्क्रीन पर दस हजारों स्प्राइट चाहते हैं, तब तक शायद यह प्रयास के लायक नहीं है।


1
और यहां तक ​​कि अगर आपके पास दस हजार स्प्राइट हैं, तो आधुनिक हार्डवेयर को एक सभ्य गति से चलाना चाहिए :)
मार्को

@ एपीआई-जानवर इंतजार क्या? आप टुकड़े की छाया में बनावट यूवी की गणना कैसे करते हैं? आप को यूवी के टुकड़े टुकड़े करने के लिए भेजने के लिए माना जाता है?
HgMerk

0

यदि सभी अन्य विफल होते हैं...

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

संभावना है, आप लगातार पूरी स्क्रीन को बार-बार बदल रहे हैं। इसके बदले केवल बदले हुए क्षेत्रों को फिर से परिभाषित करना है। यह ओवरहेड का एक बहुत कुछ है। अवधारणा सरल है, फिर भी समझना आसान नहीं है।

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

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

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


-1

वस्तुओं के लिए एक स्प्राइट शीट बनाएं और अन्य 2 डी गेम में आप जैसे इलाके के लिए एक टाइल सेट करेंगे, बनावट को स्विच करने की कोई आवश्यकता नहीं है।

रेंडरिंग टाइल्स एक दर्द हो सकता है क्योंकि प्रत्येक त्रिकोण जोड़ी को अपनी बनावट निर्देशांक की आवश्यकता होती है। हालाँकि, इस समस्या का समाधान है, इसे इंस्टेंटेड रेंडरिंग कहा जाता है

जब तक आप अपने डेटा को इस तरह से सॉर्ट कर सकते हैं, उदाहरण के लिए, आपके पास घास की टाइलों और उनकी स्थिति की एक सूची हो सकती है, आप हर घास टाइल को एक सिंगल ड्रॉ कॉल के साथ प्रस्तुत कर सकते हैं, आपको केवल एक सरणी प्रदान करना है प्रत्येक टाइल के लिए दुनिया के मॉडल का मॉडल। अपने डेटा को इस तरह से सॉर्ट करना सबसे सरल दृश्य ग्राफ के साथ भी एक मुद्दा नहीं होना चाहिए।


-1: इंस्टेंसिंग श्री बीस्ट के शुद्ध-शेडर समाधान से भी बदतर विचार है। मध्यम जटिलता (~ 100 त्रिकोण या तो) की वस्तुओं को प्रस्तुत करते समय प्रदर्शन प्रदर्शन के लिए सबसे अच्छा काम करता है। बनावट निर्देशांक की आवश्यकता वाले प्रत्येक त्रिकोण टाइल एक समस्या नहीं है। आप बस ढीले quads के एक झुंड के साथ एक जाल बनाते हैं जो एक तिलमप बनाने के लिए होता है।
निकोल बोलस

1
@NicolBolas ठीक है, मैं सीखने के लिए जवाब देने वाला हूँ
dreta

1
स्पष्टता के लिए, निकोल बोलस, इन सब से निपटने के लिए आपका क्या सुझाव है? मार्को की स्ट्रीम ड्रा चीज़? क्या वहाँ कहीं मैं इसका एक कार्यान्वयन देख सकता हूँ?
निक

@ एनआईसी: बफर ऑब्जेक्ट्स के लिए स्ट्रीमिंग विशेष रूप से जटिल कोड नहीं है। लेकिन वास्तव में, यदि आप केवल 50 स्पिट्स के बारे में बात कर रहे हैं, तो यह कुछ भी नहीं है । ऑड्स अच्छा है कि यह आपके इलाके की ड्राइंग है जो प्रदर्शन के मुद्दे को पैदा कर रहा था, इसलिए उसके लिए स्थैतिक बफ़र्स पर स्विच करना संभवतः काफी अच्छा होगा।
निकोल बोलस

वास्तव में, अगर उदाहरण के तौर पर काम किया जाए तो हमें लगता है कि यह करना चाहिए, यह सबसे अच्छा समाधान होगा - लेकिन चूंकि यह नहीं है, इसलिए सभी उदाहरणों को एक स्थिर स्टेटबो में पकाना एक रास्ता है।
जरी कोमप्पा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.