मैं एक Minecraft-esque voxel दुनिया को कैसे अनुकूलित कर सकता हूं?


76

मैंने पाया कि Minecraft की अद्भुत बड़ी दुनियाएं बहुत ही धीमी गति से नेविगेट करने में सक्षम हैं, यहां तक ​​कि एक क्वाड कोर और भावपूर्ण ग्राफिक्स कार्ड के साथ।

मुझे लगता है कि Minecraft की सुस्ती से आता है:

  • जावा, स्थानिक विभाजन और स्मृति प्रबंधन के रूप में मूल C ++ में तेज है।
  • कमजोर दुनिया विभाजन।

मैं दोनों मान्यताओं पर गलत हो सकता हूं। हालांकि, इससे मुझे बड़ी लोमड़ी की दुनिया को प्रबंधित करने के सबसे अच्छे तरीके के बारे में सोचना पड़ा। यह एक सच 3 डी दुनिया है, जहां एक ब्लॉक दुनिया के किसी भी हिस्से में मौजूद कर सकते हैं के रूप में, यह मूल रूप से एक बड़े 3D सरणी है [x][y][z], जहां दुनिया में प्रत्येक ब्लॉक एक प्रकार है (यानी BlockType.Empty = 0, BlockType.Dirt = 1आदि)

मेरा मानना ​​है कि इस प्रकार की दुनिया को अच्छा प्रदर्शन करने के लिए, आपको निम्नलिखित की आवश्यकता होगी:

  • सभी क्यूब्स को विभाजित करने के लिए कुछ किस्म ( अष्ट / kd / bsp ) के पेड़ का उपयोग करें ; ऐसा लगता है कि एक ऑक्टा / केडी बेहतर विकल्प होगा, क्योंकि आप प्रति क्यूबाई स्तर पर विभाजन कर सकते हैं न कि एक त्रिभुज स्तर पर।
  • कुछ एल्गोरिदम का उपयोग करके यह पता लगाएं कि वर्तमान में कौन से ब्लॉक देखे जा सकते हैं, क्योंकि उपयोगकर्ता के करीब ब्लॉक पीछे के ब्लॉक को बाधित कर सकते हैं, जिससे उन्हें रेंडर करना बेकार हो जाता है।
  • ब्लॉक ऑब्जेक्ट को खुद को हल्का रखें, इसलिए उन्हें पेड़ों से जोड़ना और निकालना जल्दी है।

मुझे लगता है कि इसका कोई सही जवाब नहीं है , लेकिन मुझे इस विषय पर लोगों की राय देखने में दिलचस्पी होगी। आप एक बड़े स्वर-आधारित विश्व में प्रदर्शन कैसे सुधारेंगे?



2
तो आप वास्तव में क्या पूछ रहे हैं? क्या आप बड़ी दुनिया के प्रबंधन के लिए अच्छे दृष्टिकोण या अपने विशेष दृष्टिकोण पर प्रतिक्रिया, या बड़ी दुनिया के प्रबंधन के विषय पर राय पूछ रहे हैं?
doppelgreener

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

2
इसलिए स्पष्ट रहें और अपनी पोस्ट में एक प्रश्न जोड़ें ताकि हमें पता चले कि हम किस प्रश्न का उत्तर दे रहे हैं। ;)
डोपेलग्रेनर

3
"नेविगेट करने में बेहद धीमी" से आपका क्या मतलब है? जब गेम नया इलाक़ा बनाता है तो निश्चित रूप से कुछ धीमा होता है, लेकिन उसके बाद, minecraft को इलाके को अच्छी तरह से संभालना पड़ता है।
थेडियन

जवाबों:


107

वोक्सल इंजन रॉक्स

वोक्सल इंजन ग्रास

जावा बनाम सी ++ के संबंध में, मैंने दोनों में एक voxel इंजन लिखा है (C ++ संस्करण ऊपर दिखाया गया है)। मैं भी 2004 से (जब वे प्रचलन में नहीं थे) voxel इंजन लिख रहे हैं। :) मैं थोड़ी झिझक के साथ कह सकता हूं कि C ++ का प्रदर्शन कहीं बेहतर है (लेकिन इसे कोड करना भी अधिक कठिन है)। इसकी कम्प्यूटेशनल गति के बारे में कम, और स्मृति प्रबंधन के बारे में अधिक। नीचे हाथ, जब आप एक voxel दुनिया में व्हाट्स के रूप में ज्यादा डेटा आवंटित / डील कर रहे हैं, तो C (++) को हराने के लिए भाषा है। हालाँकि, आपको अपने लक्ष्य के बारे में सोचना चाहिए। यदि प्रदर्शन आपकी सर्वोच्च प्राथमिकता है, तो C ++ के साथ जाएं। यदि आप केवल रक्तस्राव-धार प्रदर्शन के बिना एक खेल लिखना चाहते हैं, तो जावा निश्चित रूप से स्वीकार्य है (जैसा कि Minecraft द्वारा स्पष्ट किया गया है)। कई तुच्छ / धार मामले हैं, लेकिन सामान्य तौर पर आप जावा से (1. लिखी गई) C ++ की तुलना में लगभग 1.75-2.0 गुना धीमी गति से चलने की उम्मीद कर सकते हैं। आप यहां मेरे इंजन के खराब रूप से अनुकूलित, पुराने संस्करण को देख सकते हैं (EDIT: नया संस्करण यहां )। जबकि चंक पीढ़ी धीमी लग सकती है, ध्यान रखें कि यह 3 डी वोरोनोई आरेखों को स्वैच्छिक रूप से पैदा कर रहा है, सीपीयू पर सतह के मानदंडों, प्रकाश व्यवस्था, एओ और छाया की गणना ब्रूट-फोर्स विधियों के साथ कर रहा है। मैंने विभिन्न तकनीकों की कोशिश की है और मैं विभिन्न कैशिंग और इंस्टेंसेसिंग तकनीकों का उपयोग करके लगभग 100x तेज चंक पीढ़ी प्राप्त कर सकता हूं।

आपके बाकी सवालों का जवाब देने के लिए, कई चीजें हैं जो आप प्रदर्शन को बेहतर बनाने के लिए कर सकते हैं।

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

  3. चूंकि GPU को डेटा पास करना इतना महंगा है, इसलिए सॉफ्टवेयर में एक इंजन लिखना संभव है जो कुछ मामलों में तेज है। सॉफ्टवेयर का लाभ यह है कि यह सभी प्रकार के डेटा हेरफेर / मेमोरी एक्सेस कर सकता है जो कि बस GPU पर संभव नहीं है।

  4. बैच के आकार के साथ खेलते हैं। यदि आप एक GPU का उपयोग कर रहे हैं, तो प्रदर्शन आपके द्वारा पारित किए जाने वाले प्रत्येक शीर्ष सरणी के आधार पर नाटकीय रूप से भिन्न हो सकता है। तदनुसार, चंक्स के आकार के साथ चारों ओर खेलें (यदि आप चंक्स का उपयोग करते हैं)। मैंने पाया है कि 64x64x64 विखंडू बहुत अच्छी तरह से काम करते हैं। कोई फर्क नहीं पड़ता कि, अपने विखंडू घन (कोई आयताकार प्रिज्म) रखें। इससे कोडिंग और विभिन्न ऑपरेशन (जैसे परिवर्तन) आसान हो जाएंगे, और कुछ मामलों में, अधिक प्रदर्शन करने वाले। यदि आप हर आयाम की लंबाई के लिए केवल एक मूल्य संग्रहीत करते हैं, तो ध्यान रखें कि दो कम रजिस्टरों को गणना के दौरान चारों ओर स्वैप किया जाए।

  5. प्रदर्शन सूचियों पर विचार करें (OpenGL के लिए)। भले ही वे "पुराने" तरीके से हों, लेकिन वे तेज हो सकते हैं। आपको एक प्रदर्शन सूची को एक चर में सेंकना चाहिए ... यदि आप वास्तविक समय में प्रदर्शन सूची निर्माण कार्यों को कॉल करते हैं, तो यह धीमी गति से धीमा होगा। प्रदर्शन सूची कैसे तेज होती है? यह केवल राज्य, बनाम प्रति-शीर्ष विशेषताएँ अद्यतन करता है। इसका मतलब है कि मैं छह चेहरों को पार कर सकता हूं, फिर एक रंग (बनाम स्वर के प्रत्येक शीर्ष के लिए एक रंग)। यदि आप GL_QUADS और क्यूबिक स्वर का उपयोग कर रहे हैं, तो यह प्रति वॉक्सेल तक 20 बाइट्स (160 बिट्स) तक बचा सकता है! (बिना किसी अल्फ़ा के 15 बाइट्स, हालाँकि आमतौर पर आप 4-बाइट को संरेखित रखना चाहते हैं।)

  6. मैं "चंक्स", या डेटा के पृष्ठों को प्रस्तुत करने की एक क्रूर-बल विधि का उपयोग करता हूं, जो एक सामान्य तकनीक है। ऑक्ट्रेसेस के विपरीत, डेटा पढ़ना / प्रोसेस करना बहुत आसान / तेज़ है, हालाँकि मेमोरी फ्रेंडली कम है (हालाँकि, इन दिनों आपको $ 200- $ 300 के लिए 64 गीगाबाइट मेमोरी मिल सकती है ... ऐसा नहीं है कि औसत उपयोगकर्ता के पास है। जाहिर है, आप पूरी दुनिया के लिए एक विशाल सरणी आवंटित नहीं कर सकते हैं (एक 1024x1024x1024 voxels का सेट 4 गीगाबाइट मेमोरी है, यह मानते हुए कि 32-बिट इंट प्रति स्वर का उपयोग किया जाता है)। इसलिए आप दर्शक से उनकी निकटता के आधार पर कई छोटे सरणी आवंटित / डील करते हैं। आप डेटा को आवंटित भी कर सकते हैं, आवश्यक प्रदर्शन सूची प्राप्त कर सकते हैं, फिर मेमोरी को बचाने के लिए डेटा को डंप कर सकते हैं। मुझे लगता है कि आदर्श कॉम्बो ऑक्टर्स और सरणियों के एक संकर दृष्टिकोण का उपयोग करने के लिए हो सकता है - दुनिया की प्रक्रियात्मक पीढ़ी, प्रकाश व्यवस्था आदि करते समय डेटा को एक सरणी में संग्रहीत करें।

  7. दूर तक रेंडर ... एक पिक्सेल काटा गया समय बच जाता है। अगर यह गहराई बफर टेस्ट पास नहीं करता है तो gpu एक पिक्सेल को टॉस करेगा।

  8. व्यूपोर्ट (आत्म व्याख्यात्मक) में केवल खंड / पृष्ठ रेंडर करें। यहां तक ​​कि अगर gpu व्यूपोर्ट के बाहर पोलगियन को क्लिप करना जानता है, तो भी इस डेटा को पारित करने में समय लगता है। मुझे नहीं पता कि इसके लिए सबसे कुशल संरचना क्या होगी ("शर्म की बात है," मैंने बीएसपी का पेड़ कभी नहीं लिखा है), लेकिन प्रति चंक आधार पर एक साधारण रेकास्ट भी प्रदर्शन में सुधार कर सकता है, और जाहिर तौर पर देखने वाले फ्रुम के खिलाफ परीक्षण होगा। समय बचाओ।

  9. स्पष्ट जानकारी, लेकिन newbies के लिए: हर एक बहुभुज को हटा दें जो सतह पर नहीं है - अर्थात यदि एक स्वर में छह चेहरे होते हैं, तो उन चेहरों को हटा दें जो कभी नहीं मिलते हैं (दूसरे स्वर को छू रहे हैं)।

  10. प्रोग्रामिंग में आप जो कुछ भी करते हैं, उसके सामान्य नियम के रूप में: CACHE LOCALITY! यदि आप चीजों को कैशे-लोकल (थोड़ी-थोड़ी देर के लिए भी) रख सकते हैं, तो इससे काफी फर्क पड़ेगा। इसका मतलब है कि अपने डेटा को कंफर्टेबल (उसी मेमोरी रीजन में) रखना, और मेमोरी के क्षेत्रों को स्विच करना भी अक्सर नहीं। , आदर्श रूप से, एक धागे पर प्रति काम करते हैं, और उस मेमोरी को थ्रेड के लिए अनन्य रखते हैं। यह सिर्फ सीपीयू कैश पर लागू नहीं होता है। इस तरह से कैश पदानुक्रम के बारे में सोचो (सबसे तेजी से सबसे धीमा): नेटवर्क (क्लाउड / डेटाबेस / आदि) -> हार्ड ड्राइव (एक SSD प्राप्त करें यदि आपके पास पहले से ही नहीं है), ram (यदि आपके पास पहले से नहीं है तो ट्रिपल चैनल या अधिक रैम प्राप्त करें), सीपीयू कैश (ओं), रजिस्टरों पर अपने डेटा को रखने का प्रयास करें। बाद वाला छोर, और जितना आपके पास है उससे अधिक स्वैप नहीं।

  11. थ्रेडिंग। कर दो। वॉक्सल दुनिया थ्रेडिंग के लिए अच्छी तरह से अनुकूल हैं, क्योंकि प्रत्येक भाग की गणना (ज्यादातर) दूसरों से स्वतंत्र रूप से की जा सकती है ... मैंने शाब्दिक दुनिया की पीढ़ी में लगभग 4x सुधार (4 कोर, 8 थ्रेड कोर i7 पर) देखा जब मैंने लिखा था। थ्रेडिंग के लिए दिनचर्या।

  12. चार / बाइट डेटा प्रकार का उपयोग न करें। या शॉर्ट्स। आपके औसत उपभोक्ता के पास एक आधुनिक एएमडी या इंटेल प्रोसेसर होगा (जैसा कि आप, शायद)। इन प्रोसेसर में 8 बिट रजिस्टर नहीं है। वे 32 बिट स्लॉट में डालकर बाइट्स की गणना करते हैं, फिर उन्हें मेमोरी में वापस (शायद) में परिवर्तित करते हैं। आपका कंपाइलर सभी प्रकार के वूडू कर सकता है, लेकिन एक 32 या 64 बिट नंबर का उपयोग आपको सबसे अधिक अनुमानित (और सबसे तेज़) परिणाम देने वाला है। इसी तरह, "बूल" मान 1 बिट नहीं लेता है; संकलक अक्सर एक बूल के लिए पूर्ण 32 बिट का उपयोग करेगा। यह आपके डेटा पर कुछ प्रकार के संपीड़न करने के लिए लुभावना हो सकता है। उदाहरण के लिए, आप 8 स्वरों को एक ही संख्या (2 ^ 8 = 256 संयोजनों) के रूप में संग्रहीत कर सकते हैं यदि वे सभी एक ही प्रकार / रंग के हों। हालाँकि, आपको इसके बारे में सोचना होगा - यह स्मृति का एक अच्छा सौदा बचा सकता है, लेकिन यह प्रदर्शन में भी बाधा डाल सकता है, यहां तक ​​कि एक छोटे से अपघटन समय के साथ भी, क्योंकि यहां तक ​​कि अतिरिक्त समय की छोटी मात्रा आपके दुनिया के आकार के साथ बहुत कम है। एक रेकास्ट की गणना करने की कल्पना करो; रेकास्ट के हर चरण के लिए, आपको विघटन एल्गोरिथ्म चलाना होगा (जब तक कि आप एक किरण चरण में 8 voxels के लिए गणना को सामान्य करने का एक स्मार्ट तरीका नहीं लेते हैं)।

  13. जैसा कि जोस शावेज उल्लेख करते हैं, फ्लाईवेट डिजाइन पैटर्न उपयोगी हो सकता है। जैसे आप एक 2D गेम में टाइल का प्रतिनिधित्व करने के लिए बिटमैप का उपयोग करेंगे, आप अपनी दुनिया को कई 3D टाइल (या ब्लॉक) प्रकारों से बना सकते हैं। इसके लिए नकारात्मक पक्ष बनावट की पुनरावृत्ति है, लेकिन आप एक साथ फिट होने वाले विचरण बनावट का उपयोग करके इसे संशोधित कर सकते हैं। अंगूठे के एक नियम के रूप में, आप जहां चाहें वहां इंस्टेंसिंग का उपयोग करना चाहते हैं।

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

  15. अपने छोरों को उल्टा करें और सरणियों को सपाट रखें! ऐसा न करें:

    for (i = 0; i < chunkLength; i++) {
     for (j = 0; j < chunkLength; j++) {
      for (k = 0; k < chunkLength; k++) {
       MyData[i][j][k] = newVal;
      }
     }
    }
    //Instead, do this:
    for (i = 0; i < chunkLengthCubed; i++) {
     //figure out x, y, z index of chunk using modulus and div operators on i
     //myData should have chunkLengthCubed number of indices, obviously
     myData[i] = newVal;
    }

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

EDIT 2: जब मल्टी-इंडेक्स लूप्स का उपयोग किया जाता है, तो z, y, x ऑर्डर को लूप इंट करने के लिए सबसे अच्छा है, बजाय अन्य तरीके से। आपका कंपाइलर इसे ऑप्टिमाइज़ कर सकता है, लेकिन मुझे आश्चर्य होगा अगर उसने ऐसा किया। यह मेमोरी एक्सेस और इलाके में दक्षता को अधिकतम करता है।

for (k < 0; k < volumePitch; k++) {
    for (j = 0; j < volumePitch; j++) {
        for (i = 0; i < volumePitch; i++) {
            myIndex = k*volumePitch*volumePitch + j*volumePitch + i;
        }
    }
}
  1. कभी-कभी आपको धारणा, सामान्यीकरण और बलिदान करना पड़ता है। आप जो सबसे अच्छा बना सकते हैं, वह यह मान लेना है कि आपकी दुनिया का अधिकांश हिस्सा पूरी तरह से स्थिर है, और केवल हर दो हज़ार फ्रेम को बदलता है। दुनिया के एनिमेटेड हिस्सों के लिए, उन्हें एक अलग पास में किया जा सकता है। यह भी मान लें कि आपकी अधिकांश दुनिया पूरी तरह से अपारदर्शी है। पारदर्शी वस्तुओं को एक अलग पास में प्रदान किया जा सकता है। मान लें कि बनावट केवल प्रत्येक x इकाइयों में भिन्न होती है, या कि वस्तुओं को केवल x वेतन वृद्धि में रखा जा सकता है। एक निश्चित विश्व आकार मान लें ... के रूप में एक अनंत दुनिया के रूप में प्रलोभन, यह अप्रत्याशित सिस्टम आवश्यकताओं को जन्म दे सकता है। उदाहरण के लिए, ऊपर की चट्टानों में वोरोनोई पैटर्न पीढ़ी को सरल बनाने के लिए, मैंने माना कि हर वोरोनोई केंद्र बिंदु एक समान ग्रिड में झूठ बोलता है, जिसमें थोड़ी सी ऑफसेट (दूसरे शब्दों में, ज्यामितीय हैशिंग से निहित है)। एक ऐसी दुनिया मान लीजिए जो लपेटती नहीं है (किनारों पर)। यह उपयोगकर्ता के अनुभव के लिए न्यूनतम लागत पर रैपिंग कोऑर्डिनेट सिस्टम द्वारा शुरू की गई कई जटिलताओं को सरल कर सकता है।

आप मेरी साइट पर मेरे कार्यान्वयन के बारे में अधिक पढ़ सकते हैं


9
+1। निबंध पढ़ने के लिए प्रोत्साहन के रूप में शीर्ष पर चित्रों सहित अच्छा स्पर्श। अब जब मैंने निबंध पढ़ा है तो मैं कह सकता हूं कि उनकी जरूरत नहीं थी और यह इसके लायक था। ;)
जॉर्ज डकेट

धन्यवाद - एक तस्वीर हजार शब्दों के लायक है, जैसा कि वे कहते हैं। :) पाठ की मेरी दीवार को कम भयभीत करने के अलावा, मैं पाठकों को यह बताने का विचार करना चाहता था कि वर्णित तकनीकों का उपयोग करके कितने voxels को एक उचित दर पर प्रस्तुत किया जा सकता है।
गवन वूलरी

14
मैं अभी भी चाहता हूं कि एसई पसंदीदा विशिष्ट उत्तरों की अनुमति देगा।
joltmode

2
@PatrickMoriarty # 15 एक बहुत ही सामान्य चाल है। यह मानते हुए कि आपका कंपाइलर यह अनुकूलन नहीं करता है (यह आपके लूप को अनियंत्रित कर सकता है, लेकिन यह शायद एक बहुआयामी को कॉम्पैक्ट नहीं करेगा)। आप अपने सभी डेटा को एक ही सन्निहित मेमोरी स्पेस में, कैशिंग के लिए रखना चाहते हैं। एक बहुआयामी सरणी (संभावित) को कई स्थानों पर आवंटित किया जा सकता है, क्योंकि यह बिंदुओं की एक सरणी है। लूप को अनियंत्रित करने के लिए, संकलित कोड कैसा दिखता है, इसके बारे में सोचें। कम से कम रजिस्टर और कैश स्वैप के लिए, आप सबसे कम संस्करण / निर्देश तैयार करना चाहते हैं। जो आपको लगता है कि अधिक में संकलित करता है?
गवन वूलरी

2
हालांकि यहां कुछ बिंदु अच्छे हैं, खासकर कैशिंग, थ्रेडिंग और जीपीयू ट्रांसफर को कम करने के संबंध में, इसमें से कुछ बहुत गलत हैं। 5: हमेशा प्रदर्शन सूची के बजाय VBO / VAO का उपयोग करते हैं। 6: अधिक रैम को बस अधिक बैंडविड्थ की आवश्यकता होती है। 12 की ओर जाता है: आधुनिक विपरीत के लिए सटीक विपरीत है, जिसके लिए प्रत्येक बाइट सहेजे जाने पर कैश में अधिक डेटा फिटिंग की संभावना बढ़ जाती है। 14: Minecraft में, पिक्सल (उन सभी दूर के क्यूब्स) की तुलना में अधिक वर्टिकल होते हैं, इसलिए पिक्सेल शेडर के लिए कंप्रेशन को ले जाएं, इससे नहीं, अधिमानतः आस्थगित छायांकन के साथ।

7

बहुत सी चीजें हैं जो Minecraft अधिक कुशलता से कर सकती हैं। उदाहरण के लिए, Minecraft लगभग 16x16 टाइलों के पूरे ऊर्ध्वाधर स्तंभों को लोड करता है और उन्हें रेंडर करता है। मुझे लगता है कि कई टाइलों को अनावश्यक रूप से भेजना और रेंडर करना बहुत ही अक्षम है। लेकिन मुझे ऐसा नहीं लगता कि भाषा का चुनाव महत्वपूर्ण है।

जावा काफी तेज़ हो सकता है लेकिन इस डेटा-ओरिएंटेड चीज़ के लिए, C ++ को सरणियों तक पहुँचने और बाइट्स के भीतर काम करने के लिए काफी कम ओवरहेड के साथ एक बड़ा लाभ है। दूसरी तरफ, जावा में सभी प्लेटफार्मों पर थ्रेडिंग करना बहुत आसान है। जब तक आप OpenMP या OpenCL का उपयोग करने की योजना नहीं बनाते हैं, आपको C ++ में वह सुविधा नहीं मिलेगी।

मेरी आदर्श प्रणाली कुछ अधिक जटिल पदानुक्रम होगी।

टाइल एक एकल इकाई है, सामग्री प्रकार और प्रकाश व्यवस्था जैसी जानकारी रखने के लिए लगभग 4 बाइट्स की संभावना है।

सेगमेंट टाइल्स की एक 32x32x32 ब्लॉक होगा।

  1. यदि प्रत्येक पक्ष ठोस खंड है, तो छह पक्षों में से प्रत्येक के लिए झंडे लगाए जाएंगे। इससे रेंडरर उस सेगमेंट को पीछे छोड़ देगा। Minecraft वर्तमान में रोड़ा परीक्षण करने के लिए प्रकट नहीं होता है। लेकिन वहाँ हार्डवेयर रोड़ा उपलब्ध होने का उल्लेख किया गया था जो कम खर्चीले कार्ड पर बहुभुज की भारी मात्रा में रेंडर करने की तुलना में महंगा हो सकता है।
  2. गतिविधि (खिलाड़ियों, एनपीसी, जल भौतिकी, वृक्ष विकास, वगैरह) के दौरान खंडों को केवल मेमोरी में लोड किया जाएगा। अन्यथा उन्हें डिस्क से ग्राहकों को सीधे संपीड़ित करने के लिए भेजा जाएगा।

सेक्टर 16x16x8 खंडों का ब्लॉक होगा।

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

विश्व क्षेत्रों का एक अनंत मानचित्र होगा।

  1. क्षेत्र के प्रबंधन और उनके अगले अपडेट के लिए दुनिया जिम्मेदार होगी।
  2. दुनिया संभावित रूप से खिलाड़ियों को उनके संभावित रास्तों पर भेज देगी। Minecraft प्रतिक्रियाशील रूप से उन खंडों को भेजता है जो क्लाइंट अनुरोध करता है, जिससे देरी हो रही है।

मैं आमतौर पर इस विचार को पसंद करता हूं, लेकिन आप आंतरिक रूप से दुनिया के क्षेत्रों का नक्शा कैसे बना सकते हैं ?
क्लैशसॉफ्ट

जबकि सेक्टर में सेगमेंट और सेगमेंट में टाइल्स के लिए एक सरणी सबसे अच्छा समाधान होगा, दुनिया में सेक्टरों को अनंत मानचित्र आकार के लिए अनुमति देने के लिए कुछ अलग करना होगा। मेरा सुझाव हैश के लिए XY निर्देशांक का उपयोग करते हुए एक हैश तालिका (छद्म शब्दकोश <वेक्टर2i, सेक्टर>) का उपयोग करना होगा। तब विश्व बस दिए गए निर्देशांक पर एक क्षेत्र देख सकता है।
जोश ब्राउन

6

Minecraft बहुत जल्दी है, यहां तक ​​कि मेरे 2-कोर पर भी। जावा एक सीमित कारक नहीं लगता है, यहाँ, हालांकि सर्वर लैग का एक सा है। स्थानीय खेल बेहतर करने लगते हैं, इसलिए मैं वहां कुछ अक्षमताओं को संभालने जा रहा हूं।

आपके प्रश्न के अनुसार, Notch (Minecraft के लेखक) ने तकनीक के बारे में कुछ लंबाई में ब्लॉग किया है। विशेष रूप से, दुनिया "चंक्स" में संग्रहीत होती है (आप कभी-कभी इन्हें देखते हैं, खासकर जब कोई गायब हो जाता है क्योंकि दुनिया अभी तक अंदर नहीं है।), इसलिए पहला अनुकूलन यह तय करना है कि क्या कोई ठग देखा जा सकता है या नहीं। ।

एक चंक के भीतर, जैसा कि आपने अनुमान लगाया है, ऐप को यह तय करना होगा कि क्या एक ब्लॉक को देखा जा सकता है या नहीं, अन्य ब्लॉक द्वारा अस्पष्ट है या नहीं, इसके आधार पर।

ध्यान दें, भी, कि ब्लॉक FACES हैं, जिन्हें माना नहीं जा सकता है, या तो अस्पष्ट होने के कारण (अर्थात, एक और ब्लॉक चेहरे को ढंकता है) या किस दिशा में कैमरा इशारा कर रहा है (यदि कैमरा उत्तर की ओर है, तो आप 'किसी भी ब्लॉक का उत्तर चेहरा नहीं देखें!'

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

यदि आप रेंडर गति, डेटा आकार या क्या अनुकूलित करना चाहते हैं, तो आपका प्रश्न स्पष्ट नहीं है। वहाँ स्पष्टीकरण उपयोगी होगा।


4
"क्लंप्स" को आमतौर पर चंक्स नाम दिया जाता है।
मार्को

अच्छी पकड़ (+1); उत्तर अपडेट किया गया। (मूल रूप से स्मृति के लिए कर रहा था, और सही शब्द भूल गया था।)
ओली

आपके द्वारा संदर्भित अक्षमताओं को "नेटवर्क" के रूप में भी जाना जाता है, जो कभी भी एक ही तरह से दो बार काम नहीं करता है, यहां तक ​​कि एक ही अंत बिंदुओं के साथ संचार भी होता है।
एडविन बक

4

यहां सामान्य जानकारी और सलाह के कुछ शब्द दिए गए हैं, जिन्हें मैं एक um के रूप में दे सकता हूं, अत्यधिक अनुभवी Minecraft modder (जो कम से कम आंशिक रूप से आपको कुछ मार्गदर्शन दे सकता है।)

Minecraft धीमा होने का कारण कुछ संदिग्ध, निम्न-स्तरीय डिज़ाइन निर्णयों के साथ करना है - उदाहरण के लिए, हर बार जब कोई ब्लॉक स्थिति से संदर्भित होता है, तो खेल 7 के साथ निर्देशांक को मान्य करता है यदि यह सुनिश्चित करने के लिए बयान कि यह सीमा से बाहर नहीं है। । इसके अलावा, 'चंक' (गेम के साथ काम करने वाले ब्लॉकों की 16x16x256 इकाई) को हथियाने का कोई तरीका नहीं है, फिर इसमें सीधे संदर्भ ब्लॉक, कैश लुकअप और, erm, मूर्खतापूर्ण सत्यापन मुद्दों (iow, प्रत्येक ब्लॉक संदर्भ भी शामिल है) को बायपास करने के लिए अन्य चीजों के साथ एक चंक लुकअप।) अपने मॉड में, मैंने सीधे ब्लॉक के एरे को खींचने और बदलने का एक तरीका बनाया, जिसने बड़े पैमाने पर कालकोठरी पीढ़ी को अनपेक्षित रूप से लैग्गी से अनजाने में तेजी से बढ़ाया।

EDIT: एक अलग दायरे में चरों को घोषित करने के दावे को हटा दिया गया, जिसके परिणामस्वरूप प्रदर्शन लाभ हुआ, यह वास्तव में ऐसा प्रतीत नहीं होता है। मैं उस समय मानता हूं कि मैंने इस परिणाम को किसी और चीज़ के साथ स्वीकार किया था, जिसके साथ मैं प्रयोग कर रहा था (विशेष रूप से, डबल्स के बीच की जातियों को हटाकर और डबल्स को समेकित करके विस्फोट से संबंधित कोड में तैरता है ... समझ में आता है, यह एक बहुत बड़ा प्रभाव था!)

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

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

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

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


2

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

आप इस डेटा के साथ क्या करते हैं तो आप पर निर्भर है। जीएफएक्स प्रदर्शन के लिए, आप फिर छिपी हुई वस्तुओं को क्लिप करने के लिए क्लिपिंग का उपयोग कर सकते हैं, ऐसी वस्तुएं जो दिखने में बहुत छोटी हैं, आदि।

यदि आप अभी ग्राफिक्स प्रदर्शन तकनीकों की तलाश कर रहे हैं तो मुझे यकीन है कि आप नेट पर सामान के पहाड़ पा सकते हैं।


1

कुछ देखने के लिए फ्लाईवेट डिजाइन पैटर्न है। मेरा मानना ​​है कि अधिकांश उत्तर इस डिज़ाइन पैटर्न को एक या दूसरे तरीके से संदर्भित करते हैं।

जबकि मुझे नहीं पता कि सटीक विधि Minecraft प्रत्येक ब्लॉक प्रकार के लिए मेमोरी को कम करने के लिए उपयोग कर रही है, यह आपके गेम में उपयोग करने के लिए एक संभावित एवेन्यू है। विचार एक प्रोटोटाइप ऑब्जेक्ट की तरह केवल एक ऑब्जेक्ट के लिए है, जो सभी ब्लॉकों के बारे में जानकारी रखता है। एकमात्र अंतर प्रत्येक ब्लॉक का स्थान होगा।

लेकिन यहां तक ​​कि स्थान को कम से कम किया जा सकता है: यदि आपको पता है कि जमीन का एक ब्लॉक एक प्रकार का है, तो उस जमीन के आयामों को एक विशाल ब्लॉक के रूप में क्यों न रखें, जिसमें एक स्थान डेटा हो?

स्पष्ट रूप से जानने का एकमात्र तरीका है कि आप अपना स्वयं का कार्यान्वयन शुरू करें, और प्रदर्शन के लिए कुछ मेमोरी टेस्ट करें। आईये जानते हैं कि यह कैसा रहेगा!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.