मैं एक Minecraft शैली के खेल में रोड़ा के साथ स्वर आधारित प्रकाश कैसे लागू कर सकता हूं?


13

मैं C # और XNA का उपयोग कर रहा हूं। प्रकाश के लिए मेरा वर्तमान एल्गोरिथ्म एक पुनरावर्ती विधि है। हालांकि, यह महंगा है , उस बिंदु पर जहां हर 5 सेकंड में एक 8x128x8 चंक की गणना की जाती है।

  • क्या अन्य प्रकाश विधियां हैं जो चर-अंधेरे छाया बनायेंगी?
  • या पुनरावर्ती विधि अच्छी है, और शायद मैं इसे गलत कर रहा हूं?

यह सिर्फ ऐसा लगता है कि पुनरावर्ती सामान मौलिक रूप से महंगा है (प्रति चक्र लगभग 25k ब्लॉकों से गुजरने के लिए मजबूर)। मैं रे ट्रेसिंग के समान एक विधि का उपयोग करने के बारे में सोच रहा था, लेकिन मुझे नहीं पता कि यह कैसे काम करेगा। एक और बात मैंने कोशिश की कि एक सूची में प्रकाश स्रोतों को संग्रहीत किया जाए, और प्रत्येक ब्लॉक को प्रत्येक प्रकाश स्रोत से दूरी प्राप्त करने के लिए, और इसका उपयोग करके इसे सही स्तर तक प्रकाश करने के लिए, लेकिन फिर प्रकाश दीवारों के माध्यम से जाएगा।

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

world.get___atएक ऐसा फ़ंक्शन है जो इस चंक के बाहर ब्लॉक प्राप्त कर सकता है (यह चंक क्लास के अंदर है)। Locationमेरी अपनी संरचना है जो एक की तरह है Vector3, लेकिन फ्लोटिंग पॉइंट वैल्यू के बजाय पूर्णांक का उपयोग करता है। light[,,]चंक के लिए लाइटमैप है।

    private void recursiveLight(int x, int y, int z, byte lightLevel)
    {
        Location loc = new Location(x + chunkx * 8, y, z + chunky * 8);
        if (world.getBlockAt(loc).BlockData.isSolid)
            return;
        lightLevel--;
        if (world.getLightAt(loc) >= lightLevel || lightLevel <= 0)
            return;
        if (y < 0 || y > 127 || x < -8 || x > 16 || z < -8 || z > 16)
            return;
        if (x >= 0 && x < 8 && z >= 0 && z < 8)
            light[x, y, z] = lightLevel;

        recursiveLight(x + 1, y, z, lightLevel);
        recursiveLight(x - 1, y, z, lightLevel);
        recursiveLight(x, y + 1, z, lightLevel);
        recursiveLight(x, y - 1, z, lightLevel);
        recursiveLight(x, y, z + 1, lightLevel);
        recursiveLight(x, y, z - 1, lightLevel);
    }

1
अगर आप 2 मिलियन ब्लॉक प्रति चंक कर रहे हैं तो कुछ बहुत ही गलत है - विशेष रूप से तब जब 8,192 ब्लॉक वास्तव में 8 * 128 * 8 चंक हो। आप क्या कर सकते हैं कि आप प्रत्येक ब्लॉक के माध्यम से जा रहे हैं ~ 244 बार? (यह 255 हो सकता है?)
doppelgreener

1
मैंने अपना गणित गलत किया। क्षमा करें: पी। बदल रहा है। लेकिन यही वजह है कि जब आपको जाने की आवश्यकता होती है, तो आपको हर ब्लॉक से "बबल आउट" करना होता है, जब तक कि आप अपनी सेटिंग से अधिक एक हल्के स्तर को हिट नहीं करते। इसका मतलब है कि वास्तविक प्रकाश के स्तर को हिट करने से पहले प्रत्येक ब्लॉक 5-10 बार अधिलेखित हो सकता है। 8x8x128x5 = बहुत

2
कैसे आप अपने Voxels भंडारण कर रहे हैं? ट्रैवर्सल समय को कम करना महत्वपूर्ण है।
समरसा

1
क्या आप अपना प्रकाश एल्गोरिथ्म पोस्ट कर सकते हैं? (आप पूछते हैं कि क्या आप इसे बुरी तरह से कर रहे हैं, हमें पता नहीं है)
doppelgreener

मैं उन्हें "ब्लॉक" की एक सरणी में संग्रहीत कर रहा हूं, और एक ब्लॉक में सामग्री के लिए एक Enum, प्लस भविष्य के उपयोग के लिए मेटाडेटा बाइट शामिल है।

जवाबों:


6
  1. प्रत्येक प्रकाश में एक सटीक (फ्लोटिंग पॉइंट) स्थिति होती है, और एक स्केलर लाइट त्रिज्या मान द्वारा परिभाषित सीमा क्षेत्र LR,।
  2. प्रत्येक स्वर की केंद्र में एक सटीक (फ्लोटिंग पॉइंट) स्थिति होती है, जिसे आप ग्रिड में इसकी स्थिति से आसानी से गणना कर सकते हैं।
  3. केवल एक बार 8192 स्वरों में से प्रत्येक के माध्यम से चलाएं, और प्रत्येक के लिए, यह देखें कि क्या यह प्रत्येक एन रोशनी के गोलाकार बाउंडिंग वॉल्यूम के भीतर जाँच करके आता है |VP - LP| < LR, जहां वीपी मूल के सापेक्ष स्वर की स्थिति वेक्टर है और मूल के सापेक्ष LPप्रकाश की स्थिति वेक्टर है। प्रत्येक प्रकाश जिसका त्रिज्या वर्तमान वॉक्सेल में पाया जाता है के लिए, को बढ़ा देते यह प्रकाश के केंद्र से दूरी के अनुसार प्रकाश कारक है |VP - LP|। यदि आप उस वेक्टर को सामान्य करते हैं और फिर उसका परिमाण प्राप्त करते हैं, तो यह 0.0-> 1.0 की सीमा में होगा। एक लोमड़ी अधिकतम प्रकाश स्तर तक पहुंच सकती है 1.0।

रनटाइम है O(s^3 * n), जहां sआपके स्वर क्षेत्र की लंबाई (128) है और nप्रकाश स्रोतों की संख्या है। यदि आपके प्रकाश स्रोत स्थिर हैं, तो यह कोई समस्या नहीं है। यदि आपके प्रकाश स्रोत वास्तविक समय में चलते हैं, तो आप पूरी तरह से हर अपडेट को पुनः प्राप्त करने के बजाय केवल डेल्टास पर काम कर सकते हैं।

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


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

विस्तार के लिए धन्यवाद @MartinSojka हां एक बुद्धिमान बाढ़ भराव की तरह लगता है। वैश्विक रोशनी पर किसी भी प्रयास के साथ, लागतें भी चतुर अनुकूलन के साथ अधिक हो जाती हैं। इस प्रकार पहले 2 डी में इन समस्याओं का प्रयास करना अच्छा है, और यदि वे दूर से महंगे हैं, तो जान लें कि आपके हाथों में 3 डी में एक निश्चित चुनौती होगी।
इंजीनियर 12

4

Minecraft ही सूरज की रोशनी इस तरह से नहीं करता है।

आप बस ऊपर से नीचे तक सूरज की रोशनी भरते हैं, प्रत्येक परत पड़ोसी परत से प्रकाश को इकट्ठा कर रही है, जो पिछली परत में क्षीणन के साथ है। बहुत तेज़ - एकल पास, कोई सूची नहीं, कोई डेटा संरचना नहीं, कोई पुनरावृत्ति नहीं।

आपको बाद में पास में टॉर्च और अन्य गैर-बाढ़ रोशनी को जोड़ना होगा।

ऐसा करने के लिए कई अन्य तरीके हैं, जिसमें फैंसी दिशात्मक प्रकाश प्रसार आदि शामिल हैं, लेकिन वे स्पष्ट रूप से धीमे हैं और आपको यह पता लगाना होगा कि क्या आप उन दंडों को देखते हुए अतिरिक्त यथार्थवाद में निवेश करना चाहते हैं।


रुको, तो वास्तव में Minecraft यह कैसे करता है? मुझे ठीक-ठीक नहीं मिल रहा था कि आप क्या कह रहे थे ... "हर परत पड़ोसी परत से प्रकाश को पिछले परत में क्षीणन के साथ इकट्ठा कर रही है" क्या मतलब है?

2
सबसे ऊपरी परत (निरंतर ऊंचाई का टुकड़ा) से शुरू करें। इसे धूप से भरें। फिर नीचे की परत पर जाएं, और पिछली परत (इसके ऊपर) में निकटतम स्वर से इसकी रोशनी का पता चलता है। ठोस स्वरों में शून्य प्रकाश डालें। आपके पास "कर्नेल" तय करने के कुछ तरीके हैं, ऊपर दिए गए स्वरों से योगदान का वजन, Minecraft पाया अधिकतम मूल्य का उपयोग करता है, लेकिन प्रचार कम नहीं होने पर इसे 1 से घटा देता है। यह पार्श्व क्षीणन है, इसलिए स्वरों के अनब्लॉक किए गए ऊर्ध्वाधर स्तंभों को पूर्ण सूर्य के प्रकाश का प्रसार और कोनों के चारों ओर हल्का खंभा मिलेगा।
ब्योर्न वेसेन

1
कृपया ध्यान दें कि यह तरीका किसी भी वास्तविक भौतिकी पर आधारित नहीं है :) मुख्य समस्या यह है कि आप सार में एक गैर-दिशात्मक प्रकाश (वायुमंडलीय बिखरने) और एक सरल हेमिस्ट्री के साथ रेडियोसिटी को उछालने की कोशिश कर रहे हैं। यह बहुत अच्छा लग रहा है।
ब्योर्न वेसेन

3
एक "होंठ" के बारे में जो लटका हुआ है, वहां प्रकाश कैसे उठता है? ऊपर की दिशा में प्रकाश कैसे यात्रा करता है? जब आप केवल ऊपर-नीचे जाते हैं, तो आप ओवरहैंग में भरने के लिए ऊपर की ओर नहीं जा सकते। मशाल / अन्य प्रकाश स्रोत भी। आप यह कैसे करेंगे? (वे केवल नीचे जा सकते थे!)

1
@Felheart: अभी कुछ समय हुआ था जब मैंने इस पर ध्यान दिया था, लेकिन संक्षेप में एक न्यूनतम परिवेश प्रकाश स्तर है जो आमतौर पर ओवरहैंग के नीचे के लिए पर्याप्त है ताकि वे पूरी तरह से काले न हों। जब मैंने इसे स्वयं कार्यान्वित किया, तो मैंने नीचे से> ऊपर एक दूसरा पास जोड़ा, लेकिन मैंने वास्तव में परिवेश पद्धति की तुलना में कोई बड़ा सौंदर्य सुधार नहीं देखा। मशालों / बिंदुओं को अलग से संभाला जाना चाहिए - मुझे लगता है कि यदि आप एक दीवार के बीच में एक मशाल लगाते हैं और थोड़ा प्रयोग करते हैं तो आप MC में उपयोग होने वाले प्रचार पैटर्न को देख सकते हैं। अपने परीक्षणों में, मैं उन्हें एक अलग प्रकाश क्षेत्र में फिर से जोड़ देता हूं।
ब्योर्न वेसन

3

किसी ने कहा कि यदि आप इसे समझ गए हैं, तो अपने स्वयं के प्रश्न का उत्तर देने के लिए, हां। एक विधि का पता लगाया।

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

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

मुझे पता है कि इसकी तरह की जटिल, मैंने अपना सर्वश्रेष्ठ समझाने की कोशिश की। लेकिन महत्वपूर्ण तथ्य यह है कि यह काम करता है और तेज है।


2

मैं एक एल्गोरिथ्म का सुझाव देता हूं जो आपके मल्टी-पास समाधान को मूल पुनरावर्ती विधि के साथ जोड़ती है , और सबसे अधिक संभावना है कि उनमें से किसी की तुलना में थोड़ा तेज है।

आपको प्रत्येक लाइट स्तर के लिए 16 सूचियों (या किसी भी प्रकार के संग्रह) की आवश्यकता होगी। (वास्तव में, कम सूचियों का उपयोग करने के लिए इस एल्गोरिथ्म को अनुकूलित करने के तरीके हैं, लेकिन यह तरीका वर्णन करना सबसे आसान है।)

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

अब, प्रकाश स्तर 16 के साथ ब्लॉकों की सूची के माध्यम से जाना। यदि उनसे सटे ब्लॉक में से किसी का प्रकाश स्तर 15 से कम है, तो उनके प्रकाश स्तर को 15 पर सेट करें और उन्हें उपयुक्त सूची में जोड़ें। (यदि वे पहले से ही किसी अन्य सूची में थे, तो आप उन्हें इससे हटा सकते हैं, लेकिन यदि आप नहीं करते हैं तो भी यह कोई नुकसान नहीं करता है।)

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

आप ध्यान दें कि मैंने निर्दिष्ट नहीं किया है कि सूचियों को कैसे संग्रहीत किया जाना चाहिए; वास्तव में बहुत ज्यादा किसी भी उचित कार्यान्वयन को करना चाहिए, जब तक कि किसी दिए गए ब्लॉक को सम्मिलित करना और एक मनमाना ब्लॉक निकालना दोनों तेजी से संचालन होते हैं। एक लिंक की गई सूची में काम करना चाहिए, लेकिन चर-लंबाई सरणियों का कोई भी आधा सभ्य कार्यान्वयन। बस जो भी आपके लिए सबसे अच्छा काम करता है उसका उपयोग करें।


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

आप इस तरह से दीवार परिवर्तन भी संभाल सकते हैं: जब एक दीवार को हटा दिया जाता है, तो उस ब्लॉक पर एक नया पुनरावर्ती प्रकाश पास शुरू करें; जब एक जोड़ा जाता है, तो सभी ब्लॉकों के लिए एक प्रकाश पुनरावृत्ति करें जो नए दीवार वाले ब्लॉक के समान प्रकाश स्रोत को इंगित करते हैं।

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

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