यादृच्छिक संख्या hlsl


13

आप एचएलएसएल में एक यादृच्छिक संख्या कैसे उत्पन्न करते हैं?

मैं पूछ रहा हूँ क्योंकि मैं gpu रे अनुरेखण की कोशिश करना चाहता हूँ । आपको पिक्सेल shader में यादृच्छिक दिशाएँ उत्पन्न करने की आवश्यकता होती है। इसलिए मैं चाहता हूं randFloat(), जहां परिणाम -1 और +1 के बीच एक यादृच्छिक संख्या है।

इसके अलावा, hlsl शोर निर्देश के साथ क्या सौदा है ? डॉक्स का कहना है कि इसे एचएलएसएल 2.0 और ऊपर से हटा दिया गया था । क्यों ?

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

विस्तार के साथ, आप सस्ते में GPU पर एक यादृच्छिक संख्या कैसे उत्पन्न कर सकते हैं?


1
आप प्रति वर्टेक्स से क्या तात्पर्य रखते हैं, कि टेक्स कोऑर्ड पिक्सेल शेपेर में प्रक्षेपित हो जाता है और इसकी पिक्सेल प्रति उस बेतरतीब बनावट को देखती है।
काइकेमारु

मेरा क्या मतलब है, अगर 2 बनावट मान एक साथ बहुत करीब होते हैं, तो यह निर्भरता होने वाली है (आपको "मिश्रित" मान मिलेगा)। यू के लिए एक वर्टेक्स है (0.5,0.5), v और समीपवर्ती वर्टेक्स (0.51,0.52) है, और उस सेगमेंट पर 500 टुकड़े हैं .. तो आउटपुट 2 या 3 वास्तविक यादृच्छिक मान होंगे (ऊपर से देखा गया) बनावट), लेकिन बाकी चेहरे के साथ रैखिक रूप से प्रक्षेपित होगा और वास्तव में यादृच्छिक नहीं होगा। मैं उस संभावना को खत्म करना चाहता हूं और एक रैंड () फ़ंक्शन है जिसे मैं पिक्सेल shader में कॉल कर सकता हूं
bobobobo

आप यह क्यों कहेंगे कि एक शीर्ष पर 0.5 और अन्य 0.51 है, जो यादृच्छिक रूप से ध्वनि नहीं करता है, आपको इन टेक्स कोर्ड्स को "यादृच्छिक" करने की आवश्यकता है, यदि आप चाहें तो आप इसे पिक्सेल shader में कर सकते हैं, लेकिन यह बहुत अधिक कार्य करता है । उन टेक्स कोर्ड्स को अपनी स्थिति से उत्पन्न होने की आवश्यकता नहीं है, इसलिए इससे कोई फर्क नहीं पड़ता कि वे एक दूसरे के कितने करीब हैं। आप एक बार वर्टिकल शेडर (स्थिति, सामान्य, टेक्सकोर्ड्स * टेक्सकोर्ड्स के रूप में कुछ पैरामीटर) का उपयोग करके एक बार यादृच्छिक बनावट का नमूना ले सकते हैं और यह आपको टेक्सकोर्ड्स देगा जो आप पिक्सेल shader को पास करते हैं
काइकेमारु

@ कीकरमारु का अर्थ है खराब घटना से, यह संभव है ..
बोबोबो

हां, यादृच्छिक क्रम में एक दूसरे के बाद दो समान मान होना संभव है
काइकेमारु

जवाबों:


14

एक पिक्सेल shader में छद्म यादृच्छिक संख्याएँ प्राप्त करना आसान नहीं है। सीपीयू पर एक छद्म यादृच्छिक संख्या जनरेटर में कुछ स्थिति होगी जो इसे फ़ंक्शन से प्रत्येक कॉल पर पढ़ता है और लिखता है। आप पिक्सेल छाया में ऐसा नहीं कर सकते।

यहां कुछ विकल्प दिए गए हैं:

  1. पिक्सेल shader के बजाय एक कंप्यूट shader का उपयोग करें - वे बफर में रीड-राइट एक्सेस का समर्थन करते हैं, इसलिए आप किसी भी मानक PRNG को लागू कर सकते हैं।

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

  3. स्क्रीन स्पेस पोजिशन के कुछ गणितीय फंक्शन को खोजें, जो ऐसे परिणाम देता है जो 'यादृच्छिक रूप से पर्याप्त' होते हैं।

एक त्वरित Google खोज ने इन कार्यों के साथ इस पृष्ठ को पाया :

float rand_1_05(in float2 uv)
{
    float2 noise = (frac(sin(dot(uv ,float2(12.9898,78.233)*2.0)) * 43758.5453));
    return abs(noise.x + noise.y) * 0.5;
}

float2 rand_2_10(in float2 uv) {
    float noiseX = (frac(sin(dot(uv, float2(12.9898,78.233) * 2.0)) * 43758.5453));
    float noiseY = sqrt(1 - noiseX * noiseX);
    return float2(noiseX, noiseY);
}

float2 rand_2_0004(in float2 uv)
{
    float noiseX = (frac(sin(dot(uv, float2(12.9898,78.233)      )) * 43758.5453));
    float noiseY = (frac(sin(dot(uv, float2(12.9898,78.233) * 2.0)) * 43758.5453));
    return float2(noiseX, noiseY) * 0.004;
}

पुन: गणना shaders, आप भी आरएनजी राज्य को थ्रेडग्रुप साझा स्मृति में संग्रहीत कर सकते हैं। दक्षता के लिए आप केवल एक आरएनजी राज्य नहीं चाहते हैं (विवाद एक बड़ी अड़चन होगी क्योंकि हर धागे ने इसे अपडेट करने की कोशिश की), लेकिन कई - शायद प्रति एक धागे के रूप में कई, या शायद प्रति 4 या 8 धागे में से एक या कुछ ऐसा - जब तक राज्य उस छोटे को संभव बनाने के लिए काफी छोटा हो जाता है (यानी शायद मेरसेन ट्विस्टर नहीं )। क्या RNG डिजाइन हैं जिनमें कई SIMD धागे एक साथ कई यादृच्छिक संख्याओं को उत्पन्न करने के लिए सहयोग कर सकते हैं? यह यहाँ काफी उपयोगी होगा।
नाथन रीड

1
बाहरी लिंक टूट गया है
जॉर्ज बीरबिलिस

2

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

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

// Source
// http://www.gamedev.net/topic/592001-random-number-generation-based-on-time-in-hlsl/
// Supposebly from the NVidia Direct3D10 SDK
// Slightly modified for my purposes
#define RANDOM_IA 16807
#define RANDOM_IM 2147483647
#define RANDOM_AM (1.0f/float(RANDOM_IM))
#define RANDOM_IQ 127773u
#define RANDOM_IR 2836
#define RANDOM_MASK 123459876

struct NumberGenerator {
    int seed; // Used to generate values.

    // Returns the current random float.
    float GetCurrentFloat() {
        Cycle();
        return RANDOM_AM * seed;
    }

    // Returns the current random int.
    int GetCurrentInt() {
        Cycle();
        return seed;
    }

    // Generates the next number in the sequence.
    void Cycle() {  
        seed ^= RANDOM_MASK;
        int k = seed / RANDOM_IQ;
        seed = RANDOM_IA * (seed - k * RANDOM_IQ ) - RANDOM_IR * k;

        if (seed < 0 ) 
            seed += RANDOM_IM;

        seed ^= RANDOM_MASK;
    }

    // Cycles the generator based on the input count. Useful for generating a thread unique seed.
    // PERFORMANCE - O(N)
    void Cycle(const uint _count) {
        for (uint i = 0; i < _count; ++i)
            Cycle();
    }

    // Returns a random float within the input range.
    float GetRandomFloat(const float low, const float high) {
        float v = GetCurrentFloat();
        return low * ( 1.0f - v ) + high * v;
    }

    // Sets the seed
    void SetSeed(const uint value) {
        seed = int(value);
        Cycle();
    }
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.