क्या रूसी रूले वास्तव में जवाब है?


21

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

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

  • क्या रूसी रूले निष्पक्ष परिणाम देता है?
  • एक निष्पक्ष परिणाम के लिए रूसी रूले आवश्यक है ?

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

एक बड़ी संख्या में नमूनों को देखते हुए, क्या दोनों दृष्टिकोण एक निष्पक्ष परिणामी छवि पर अभिसरण करेंगे?

मैं रूसी रूले दृष्टिकोण का उपयोग करने के अंतर्निहित कारण को समझना चाहता हूं। क्या गति या गुणवत्ता में महत्वपूर्ण अंतर है?


मैं समझता हूं कि कुल ऊर्जा को संरक्षित करने के लिए ऊर्जा को अन्य किरणों के बीच फिर से विभाजित किया जाता है। हालाँकि, क्या यह पुनर्वितरण तब भी नहीं किया जा सकता था, जब किरण को उस सीमा तक पहुँचने के बाद बेतरतीब ढंग से निर्धारित जीवन काल होने के बजाय, एक निश्चित सीमा से नीचे छोड़ने पर समाप्त कर दिया गया था?

इसके विपरीत, अगर किसी ऊर्जा को किरण को समाप्त किए बिना समाप्त करने वाली ऊर्जा को उसकी ऊर्जा के पुनर्वितरण के बिना समाप्त कर दिया जाएगा, तो आखिरकार वह वैसे भी खो जाती है (क्योंकि जिन किरणों को फिर से विभाजित किया जाता है, उन्हें भी समाप्त कर दिया जाता है), यह कैसे स्थिति में सुधार करती है?

जवाबों:


26

रूसी रूले को समझने के लिए, आइए एक बहुत ही बुनियादी पिछड़े पथ अनुरेखक को देखें:

void RenderPixel(uint x, uint y, UniformSampler *sampler) {
    Ray ray = m_scene->Camera.CalculateRayFromPixel(x, y, sampler);

    float3 color(0.0f);
    float3 throughput(1.0f);

    // Bounce the ray around the scene
    for (uint bounces = 0; bounces < 10; ++bounces) {
        m_scene->Intersect(ray);

        // The ray missed. Return the background color
        if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
            color += throughput * float3(0.846f, 0.933f, 0.949f);
            break;
        }

        // We hit an object

        // Fetch the material
        Material *material = m_scene->GetMaterial(ray.geomID);
        // The object might be emissive. If so, it will have a corresponding light
        // Otherwise, GetLight will return nullptr
        Light *light = m_scene->GetLight(ray.geomID);

        // If we hit a light, add the emmisive light
        if (light != nullptr) {
            color += throughput * light->Le();
        }

        float3 normal = normalize(ray.Ng);
        float3 wo = normalize(-ray.dir);
        float3 surfacePos = ray.org + ray.dir * ray.tfar;

        // Get the new ray direction
        // Choose the direction based on the material
        float3 wi = material->Sample(wo, normal, sampler);
        float pdf = material->Pdf(wi, normal);

        // Accumulate the brdf attenuation
        throughput = throughput * material->Eval(wi, wo, normal) / pdf;


        // Shoot a new ray

        // Set the origin at the intersection point
        ray.org = surfacePos;

        // Reset the other ray properties
        ray.dir = wi;
        ray.tnear = 0.001f;
        ray.tfar = embree::inf;
        ray.geomID = RTC_INVALID_GEOMETRY_ID;
        ray.primID = RTC_INVALID_GEOMETRY_ID;
        ray.instID = RTC_INVALID_GEOMETRY_ID;
        ray.mask = 0xFFFFFFFF;
        ray.time = 0.0f;
    }

    m_scene->Camera.FrameBuffer.SplatPixel(x, y, color);
}

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

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

उस ने कहा, यह चुनना मुश्किल है कि उस कठिन सीमा को क्या होना चाहिए। 2 बाउंस के बाद कुछ दृश्य बहुत अच्छे लगते हैं; अन्य (ट्रांसमिशन या SSS के साथ) 10 या 20 तक लग सकते हैं। डिज्नी के बिग हीरो 6 से 2 बाउंस डिज्नी के बिग हीरो 6 से 9 बाउंस

यदि हम बहुत कम चुनते हैं, तो छवि स्पष्ट रूप से पक्षपाती होगी। लेकिन अगर हम बहुत अधिक चुनते हैं, तो हम गणना ऊर्जा और समय बर्बाद कर रहे हैं।

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

एक दहलीज के बाद clamping, काम करेगा , लेकिन फिर, हम दहलीज का चयन कैसे करते हैं? यदि हम बहुत बड़ा चुनते हैं, तो छवि नेत्रहीन पक्षपाती, बहुत छोटी होगी, और हम संसाधनों को बर्बाद कर रहे हैं।

रूसी रूले ने निष्पक्ष तरीके से इन समस्याओं को हल करने का प्रयास किया। सबसे पहले, यहाँ कोड है:

void RenderPixel(uint x, uint y, UniformSampler *sampler) {
    Ray ray = m_scene->Camera.CalculateRayFromPixel(x, y, sampler);

    float3 color(0.0f);
    float3 throughput(1.0f);

    // Bounce the ray around the scene
    for (uint bounces = 0; bounces < 10; ++bounces) {
        m_scene->Intersect(ray);

        // The ray missed. Return the background color
        if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
            color += throughput * float3(0.846f, 0.933f, 0.949f);
            break;
        }

        // We hit an object

        // Fetch the material
        Material *material = m_scene->GetMaterial(ray.geomID);
        // The object might be emissive. If so, it will have a corresponding light
        // Otherwise, GetLight will return nullptr
        Light *light = m_scene->GetLight(ray.geomID);

        // If we hit a light, add the emmisive light
        if (light != nullptr) {
            color += throughput * light->Le();
        }

        float3 normal = normalize(ray.Ng);
        float3 wo = normalize(-ray.dir);
        float3 surfacePos = ray.org + ray.dir * ray.tfar;

        // Get the new ray direction
        // Choose the direction based on the material
        float3 wi = material->Sample(wo, normal, sampler);
        float pdf = material->Pdf(wi, normal);

        // Accumulate the brdf attenuation
        throughput = throughput * material->Eval(wi, wo, normal) / pdf;


        // Russian Roulette
        // Randomly terminate a path with a probability inversely equal to the throughput
        float p = std::max(throughput.x, std::max(throughput.y, throughput.z));
        if (sampler->NextFloat() > p) {
            break;
        }

        // Add the energy we 'lose' by randomly terminating paths
        throughput *= 1 / p;


        // Shoot a new ray

        // Set the origin at the intersection point
        ray.org = surfacePos;

        // Reset the other ray properties
        ray.dir = wi;
        ray.tnear = 0.001f;
        ray.tfar = embree::inf;
        ray.geomID = RTC_INVALID_GEOMETRY_ID;
        ray.primID = RTC_INVALID_GEOMETRY_ID;
        ray.instID = RTC_INVALID_GEOMETRY_ID;
        ray.mask = 0xFFFFFFFF;
        ray.time = 0.0f;
    }

    m_scene->Camera.FrameBuffer.SplatPixel(x, y, color);
}

रूसी रूले बेतरतीब ढंग से थ्रूपुट के बराबर एक संभावना के साथ एक मार्ग को समाप्त करता है। तो कम थ्रूपुट वाले रास्ते जो दृश्य में ज्यादा योगदान नहीं देंगे, समाप्त होने की अधिक संभावना है।

अगर हम वहाँ रुकते हैं, तो हम अभी भी पक्षपाती हैं। हम उस पथ की ऊर्जा को खो देते हैं जिसे हम अनियमित रूप से समाप्त करते हैं। इसे निष्पक्ष बनाने के लिए, हम गैर-समाप्त रास्तों की ऊर्जा को समाप्त करने की उनकी संभावना से बढ़ावा देते हैं। यह यादृच्छिक होने के साथ-साथ रूसी रूले को निष्पक्ष बनाता है।

अपने अंतिम प्रश्नों के उत्तर देने के लिए:

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

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


ईमानदारी से, मैं इसके बारे में पूरी तरह आश्वस्त नहीं हूं to be completely unbiased it must be random। मुझे लगता है कि आप अभी भी गणित-ओके परिणाम प्राप्त कर सकते हैं नमूनों के भिन्नात्मक भार का उपयोग करके, बाइनरी पास / ड्रॉप के बजाय जो रूसी रूले लगाता है, यह सिर्फ इतना है कि रूलेट तेजी से अभिसरण करेगा क्योंकि यह एक आदर्श महत्व नमूना का संचालन कर रहा है।
v.oddou

9

रूसी रूलेट तकनीक स्वयं प्रणालीगत पूर्वाग्रह को पेश किए बिना पथ को समाप्त करने का एक तरीका है। सिद्धांत काफी सीधा है: यदि किसी विशेष शीर्ष पर आपके पास मनमाने ढंग से 0 के साथ ऊर्जा को बदलने का 10% मौका है, और यदि आप ऐसा करते हैं तो अनंत बार, आपको 10% कम ऊर्जा दिखाई देगी। एनर्जी बूस्ट सिर्फ उसकी भरपाई करता है। यदि आप पथ समाप्ति के कारण खोई गई ऊर्जा की क्षतिपूर्ति नहीं करते हैं, तो रूसी रूले पक्षपाती होंगे, लेकिन पूरी तकनीक पूर्वाग्रह से बचने का एक उपयोगी तरीका है।

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

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

यदि मैं एक ऐसी वस्तु पर विचार करता हूं जो बहुत कम ऊर्जा वाले रास्तों से रोशन होती है जो कि एक परवलयिक परावर्तक द्वारा एकत्रित की जाती है ? कम ऊर्जा पथ जरूरी नहीं कि आप पूरी तरह से उपेक्षा कर सकते हैं कि अंधाधुंध तरीके से चारों ओर उछाल। इसी तरह तर्क के लिए लागू होता है, उदाहरण के लिए, एक निश्चित संख्या में बाउंस के बाद पथों को काटना: आप एक पथ के साथ एक दृश्य का निर्माण कर सकते हैं जो किसी वस्तु को मारने से पहले 20 दर्पणों की एक श्रृंखला को उछाल देता है।

इसे देखने का एक और तरीका: यदि आप किसी निश्चित एप्सिलॉन से नीचे जाने के बाद 0 के लिए एक पथ का योगदान निर्धारित करते हैं, तो आप उस ऊर्जा हानि के लिए कैसे सही हैं? आप बस कुछ अंश द्वारा कुल ऊर्जा को कम नहीं कर रहे हैं। आप कुछ भी नहीं जानते हैं कि आप कितनी ऊर्जा की उपेक्षा कर रहे हैं, क्योंकि आप दूसरे कारक को जानने से पहले कुछ योगदान सीमा पर काट रहे हैं : घटना ऊर्जा।


8

बस कुछ अन्य उत्तरों पर विस्तार करने के लिए, यह सबूत कि रूसी रूले एक पक्षपातपूर्ण परिणाम नहीं देता है, बहुत सरल है।

एफ

एफ=एफ1++एफएन

प्रत्येक शब्द को इसके साथ बदलें:

एफमैं'={1पीमैंएफमैंसंभाव्यता के साथ पीमैं0अन्यथा

फिर:

[एफमैं']=पीमैं×1पीमैं[एफमैं]+(1-पीमैं)×0=[एफमैं]

पीमैंएफ

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