प्रक्रियात्मक बनावट निर्माण में तेजी लाना


14

हाल ही में मैंने एक ऐसे खेल पर काम करना शुरू किया है जो एक प्रक्रियात्मक रूप से उत्पन्न सौर प्रणाली में होता है। कुछ सीखने की अवस्था के बाद (न तो स्काला, OpenGL 2 ES या लिबगडेक्स से पहले काम किया है), मेरे पास एक बुनियादी टेक डेमो है जहां आप एक एकल प्रक्रियात्मक ग्रह के चारों ओर घूमते हैं:

यहाँ छवि विवरण दर्ज करें

मैं जिस समस्या को लेकर चल रहा हूं वह बनावट निर्माण का प्रदर्शन है। मैं जो कर रहा हूं उसका एक त्वरित अवलोकन: एक ग्रह एक घन है जिसे एक गोले में विकृत किया गया है। प्रत्येक तरफ, चिंता (जैसे 256 x 256) बनावट को लागू किया जाता है, जिसे एक 8n xn बनावट में बांधा जाता है जिसे टुकड़ा shader को भेजा जाता है। अंतिम दो रिक्त स्थान का उपयोग नहीं किया जाता है, वे केवल यह सुनिश्चित करने के लिए वहां हैं कि चौड़ाई 2 की शक्ति है। बनावट वर्तमान में सीपीयू पर उत्पन्न होती है, सिंपलेक्स शोर एल्गोरिथ्म के अपडेट किए गए 2012 संस्करण का उपयोग करके कागज में 'सिम्प्लेक्स' से जुड़ा हुआ है। शोर ध्वस्त '। एल्गोरिथ्म का परीक्षण करने के लिए मैं जिस दृश्य का उपयोग कर रहा हूं, उसमें दो गोले हैं: ग्रह और पृष्ठभूमि। दोनों 3 डी सिंप्लेक्स शोर के छह सप्तक से युक्त एक ग्रेस्केल बनावट का उपयोग करते हैं, इसलिए उदाहरण के लिए अगर हम 128x128 चुनते हैं तो बनावट का आकार 128 x 128 x 6 x 2 x 6 = शोर फ़ंक्शन के बारे में 1.2 मिलियन कॉल हैं।

ग्रह के सबसे करीब आपको स्क्रीनशॉट में दिखाया गया है और गेम के लक्ष्य रिज़ॉल्यूशन 1280x720 है, इसका मतलब है कि मैं 512x512 बनावट का उपयोग करना पसंद करूंगा। इस तथ्य के साथ कि वास्तविक बनावट निश्चित रूप से मूल शोर की तुलना में अधिक जटिल होगी (सूर्य की रोशनी के आधार पर टुकड़े टुकड़े में मिश्रित और दिन और रात की बनावट होगी, और एक मुखौटा मुखौटा। मुझे महाद्वीपों के लिए शोर की आवश्यकता है, भूरा रंग भिन्नता। , बादल, शहर की रोशनी, आदि) और हम कुछ देख रहे हैं जैसे 512 x 512 x 6 x 3 x 15 = 70 मिलियन अकेले ग्रह के लिए शोर कॉल। अंतिम गेम में, ग्रहों के बीच यात्रा करते समय गतिविधियां होंगी, इसलिए 5 या 10 सेकंड की प्रतीक्षा, संभवतः 20, स्वीकार्य होगी क्योंकि मैं यात्रा करते समय पृष्ठभूमि में बनावट की गणना कर सकता हूं, हालांकि स्पष्ट रूप से बेहतर है।

हमारे परीक्षण दृश्य पर वापस जाना, मेरे पीसी पर प्रदर्शन बहुत भयानक नहीं है, हालांकि अभी भी बहुत धीमी गति से अंतिम परिणाम पर विचार 60 बार संभव हो रहा है

128x128 : 0.1s
256x256 : 0.4s
512x512 : 1.7s

यह मेरे द्वारा जावा में सभी प्रदर्शन-महत्वपूर्ण कोड स्थानांतरित करने के बाद है, क्योंकि स्काला में ऐसा करने की कोशिश बहुत खराब थी। हालाँकि, मेरे फ़ोन (सैमसंग गैलेक्सी S3) पर इसे चलाने से अधिक समस्या उत्पन्न होती है:

128x128 :  2s
256x256 :  7s
512x512 : 29s

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

  • बनावट को पहले से न समझें, लेकिन टुकड़े टुकड़े को सब कुछ गणना करने दें। शायद संभव नहीं है, क्योंकि एक बिंदु पर मेरे पास एक पिक्सेल shader के साथ पूर्णस्क्रीन क्वाड के रूप में पृष्ठभूमि थी और मुझे अपने फोन पर लगभग 1 एफपीएस मिला।
  • एक बार बनावट को रेंडर करने के लिए GPU का उपयोग करें, इसे स्टोर करें और तब से संग्रहीत बनावट का उपयोग करें। अपसाइड: सीपीयू पर ऐसा करने से तेज हो सकता है क्योंकि जीपीयू फ्लोटिंग पॉइंट कैलकुलेशन में तेज होना चाहिए। डाउनसाइड: प्रभाव जो (आसानी से) सरल शोर के कार्यों के रूप में व्यक्त नहीं किए जा सकते हैं (जैसे गैस ग्रह भंवर, चंद्रमा क्रेटर, आदि) जीएलएएसएल में स्काला / जावा की तुलना में कोड करने के लिए बहुत अधिक कठिन हैं।
  • बड़ी मात्रा में शोर बनावट की गणना करें और उन्हें एप्लिकेशन के साथ शिप करें। यदि संभव हो तो मैं इससे बचना चाहूंगा।
  • संकल्प कम करो। मुझे एक 4x प्रदर्शन लाभ मिलता है, जो वास्तव में पर्याप्त नहीं है और मैं बहुत अधिक गुणवत्ता खो देता हूं।
  • तेजी से शोर एल्गोरिथ्म का पता लगाएं। अगर किसी के पास सभी कान हैं, लेकिन सिम्प्लेक्स पहले से ही पर्लिन से तेज होना चाहिए।
  • कम रिज़ॉल्यूशन टेक्सचर और कम शोर वाले ऑक्टेव के लिए एक पिक्सेल आर्ट स्टाइल अपनाएँ। जबकि मैंने मूल रूप से इस शैली में खेल की कल्पना की थी, मैं यथार्थवादी दृष्टिकोण को प्राथमिकता देता हूं।
  • मैं कुछ गलत कर रहा हूं और प्रदर्शन पहले से ही एक या दो ऑर्डर बेहतर होना चाहिए। अगर ऐसा है, तो कृपया मुझे बताएं।

अगर किसी के पास इस समस्या के बारे में कोई सुझाव, टिप्स, वर्कअराउंड या अन्य टिप्पणियां हैं, तो मैं उन्हें सुनना पसंद करूंगा।

Layoric के जवाब में, यहां वह कोड है जिसका मैं उपयोग कर रहा हूं:

//The function that generates the simplex noise texture
public static Texture simplex(int size) {
    byte[] data = new byte[size * size * columns * 4];
    int offset = 0;
    for (int y = 0; y < size; y++) {
        for (int s = 0; s < columns; s++) {
            for (int x = 0; x < size; x++) {
                //Scale x and y to [-1,1] range
                double tx = ((double)x / (size - 1)) * 2 - 1;
                double ty = 1 - ((double)y / (size - 1)) * 2;

                //Determine point on cube in worldspace
                double cx = 0, cy = 0, cz = 0;
                if      (s == 0) { cx =   1; cy =  tx; cz =  ty; }
                else if (s == 1) { cx = -tx; cy =   1; cz =  ty; }
                else if (s == 2) { cx = - 1; cy = -tx; cz =  ty; }
                else if (s == 3) { cx =  tx; cy = - 1; cz =  ty; }
                else if (s == 4) { cx = -ty; cy =  tx; cz =   1; }
                else if (s == 5) { cx =  ty; cy =  tx; cz = - 1; }

                //Determine point on sphere in worldspace
                double sx = cx * Math.sqrt(1 - cy*cy/2 - cz*cz/2 + cy*cy*cz*cz/3);
                double sy = cy * Math.sqrt(1 - cz*cz/2 - cx*cx/2 + cz*cz*cx*cx/3);
                double sz = cz * Math.sqrt(1 - cx*cx/2 - cy*cy/2 + cx*cx*cy*cy/3);

                //Generate 6 octaves of noise
                float gray = (float)(SimplexNoise.fbm(6, sx, sy, sz, 8) / 2 + 0.5);

                //Set components of the current pixel
                data[offset    ] = (byte)(gray * 255);
                data[offset + 1] = (byte)(gray * 255);
                data[offset + 2] = (byte)(gray * 255);
                data[offset + 3] = (byte)(255);

                //Move to the next pixel
                offset += 4;
            }
        }
    }

    Pixmap pixmap = new Pixmap(columns * size, size, Pixmap.Format.RGBA8888);
    pixmap.getPixels().put(data).position(0);

    Texture texture = new Texture(pixmap, true);
    texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
    return texture;
}

//SimplexNoise.fbm
//The noise function is the same one found in http://webstaff.itn.liu.se/~stegu/simplexnoise/SimplexNoise.java
//the only modification being that I replaced the 32 in the last line with 16 in order to end up with
//noise in the range [-0.5, 0.5] instead of [-1,1]
public static double fbm(int octaves, double x, double y, double z, double frequency) {
    double value = 0;
    double f = frequency;
    double amp = 1;
    for (int i = 0; i < octaves; i++) {
        value += noise(x*f, y*f, z*f) * amp;
        f *= 2;
        amp /= 2;
    }
    return value; 
}

आप अपने शोर समारोह के लिए जावा में वर्तमान में क्या पोस्ट कर सकते हैं? यह कहते हुए कि इससे होने वाले किसी भी प्रदर्शन का लाभ नहीं है, लेकिन कोई आपको बढ़ावा देने के लिए कुछ कर सकता है।
डैरेन रीड

मैंने वह कोड जोड़ा है जिसका उपयोग मैं मूल पोस्ट में कर रहा हूं।
फाल्कनएनएल

आपके Q प्रति से संबंधित नहीं है, लेकिन आपके साथ काम करने के बाद आपको अपने Pixmap पर डिस्पोज () कॉल करना चाहिए।
17

जवाबों:


10

आप इस तरह दृष्टिकोण (2) और (3) को जोड़ सकते हैं:

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

+1 मुझे लगता है कि इसे प्रभावित करने के लिए सबसे अच्छा तरीका होगा संयोजन को लागू करने या लागू करने के लिए खेल के साथ टेक्सचर का एक गुच्छा उत्पन्न करना और उन्हें पैकेजिंग करना।
TheNickmaster21

2

प्रक्रिया समय के संदर्भ में प्रक्रियात्मक बनावट पीढ़ी एक मोफो का * * है। यह है जो यह है।

सिम्प्लेक्स शोर का सबसे अच्छा कार्यान्वयन मैंने पाया है स्टीफन गुस्तावसन

वास्तविक गणना समय में सुधार से परे (यह वास्तव में बहुत कठिन है कि आप 1024x1024 प्रक्रियात्मक बनावट की गणना करते समय अपने कंप्यूटर से बहुत कुछ पूछ रहे हैं ), कथित प्रतीक्षा समय को कम करने के सर्वोत्तम तरीकों में से एक है आपका ऐप जितना संभव हो उतना बैकग्राउंड थ्रेड काम करता है।

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

गौर करने वाली बात यह है कि, डिस्क पर बेतरतीब ढंग से कई सौ उत्पन्न टेक्स्ट को कैश करें और लोड समय पर इनमें से किसी एक का चयन करें। अधिक डिस्क, लेकिन कम लोड समय।

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