Rus Ruleti gerçekten cevap mı?


21

Path Tracing'in bazı uygulamalarında, bazı yolları iptal etmek ve katkılarını diğer yollar arasında paylaşmak için Rus Ruleti adı verilen bir yaklaşımın kullanıldığını gördüm.

Belirli bir eşik katma değerinin altına düşene kadar bir yolu izlemek ve ardından onu terk etmek yerine, farklı bir eşiğin kullanıldığını ve katkısının bu eşiğin altında olduğu yolların yalnızca küçük bir olasılıkla sonlandırıldığını anlıyorum. Diğer yolların katkısı, sonlandırılmış yoldan kaybedilen enerjinin paylaşılmasına karşılık gelen bir miktarda artırılmıştır. Bunun tekniğin getirdiği bir önyargıyı düzeltip düzeltmeyeceği veya önyargıdan kaçınmak için tüm tekniğin kendisinin gerekli olup olmadığı bana açık değil.

  • Rus Ruleti tarafsız bir sonuç veriyor mu?
  • Tarafsız bir sonuç için Rus Ruleti gerekli mi?

Yani, küçük bir eşik kullanmak ve bu eşiğin altına düştüğü anda bir yolu sonlandırmak daha önyargılı veya daha az önyargılı bir sonuç verir mi?

İsteğe bağlı olarak çok sayıda örnek verildiğinde, her iki yaklaşım da tarafsız bir sonuç görüntüsü üzerinde birleşir mi?

Rus Ruleti yaklaşımını kullanmanın altında yatan nedeni anlamak istiyorum. Hız veya kalite açısından önemli bir fark var mı?


Toplam enerjiyi korumak için enerjinin diğer ışınlar arasında yeniden dağıtıldığını anlıyorum. Bununla birlikte, ışın, bu eşiğe ulaştıktan sonra rastgele belirlenmiş bir ömre sahip olmak yerine, sabit bir eşiğin altına düştüğünde sonlandırıldıysa yine de yeniden dağıtım yapılamaz mı?

Tersine, enerjisini yeniden dağıtmadan bir ışını sonlandırarak kaybedilecek olan enerji nihayetinde kaybolursa (yeniden dağıtıldığı ışınlar da sonunda sona erdirilir), bu durumu nasıl iyileştirir?

Yanıtlar:


26

Rus Ruletini anlamak için, çok temel bir geri yol izleyicisine bakalım:

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);
}

IE. sahne etrafında zıplıyoruz, giderken renk ve ışık zayıflaması biriktiriyoruz. Tamamen matematiksel olarak tarafsız olması için, sıçramalar gerektiğini sonsuza gidin. Ancak bu gerçekçi değildir ve belirttiğiniz gibi görsel olarak gerekli değildir; çoğu sahne için, belirli bir sayıda sıçramadan sonra, örneğin 10, son renge katkı miktarı çok azdır.

Bu nedenle, bilgisayar kaynaklarını kurtarmak için, birçok yol izleyicisinin sıçrama sayısı için zor bir sınırı vardır. Bu önyargı ekler.

Bununla birlikte, bu zor sınırın ne olması gerektiğini seçmek zor. Bazı sahneler 2 sekmeden sonra harika görünüyor; diğerleri (örneğin iletim veya SSS ile) 10 veya 20'ye kadar sürebilir. Disney'in Büyük Kahramanından 2 Sıçrama 6 Disney'in Büyük Kahramanından 6 Sıçrama

Çok düşük seçersek, görüntü görünür şekilde önyargılı olur. Ama çok yüksek seçersek, hesaplama enerjisini ve zamanını boşa harcıyoruz.

Bunu çözmenin bir yolu, belirttiğiniz gibi, bir miktar zayıflama eşiğine ulaştıktan sonra yolu sonlandırmaktır. Bu da önyargı ekler.

Bir eşikten sonra sıkıştırma, işe yarayacak , ancak yine eşiği nasıl seçeceğiz? Çok büyük seçersek, görüntü görünür şekilde önyargılı, çok küçük olacak ve kaynakları israf edeceğiz.

Rus Ruleti bu sorunları tarafsız bir şekilde çözmeye çalışır. İlk olarak, kod İşte:

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);
}

Rus Ruleti, verime ters orantılı bir yolu rastgele bir şekilde sonlandırır. Dolayısıyla, sahneye fazla katkıda bulunmayacak şekilde düşük iş hacmine sahip yolların sonlandırılması daha olasıdır.

Orada durursak, hala önyargılıyız. Rasgele sonlandırdığımız yolun enerjisini 'kaybediyoruz'. Tarafsız hale getirmek için, sonlandırılmayan yolların enerjisini, sonlandırılma olasılıklarıyla arttırırız. Bu, rastgele olmakla birlikte Rus Ruletini tarafsız kılar.

Son sorularınızı cevaplamak için:

  1. Rus Ruleti tarafsız bir sonuç veriyor mu?
    • Evet
  2. Tarafsız bir sonuç için Rus Ruleti gerekli mi?
    • Tarafsız ile ne demek istediğine bağlı. Matematiksel olarak demek istiyorsan, evet. Ancak, görsel olarak demek istiyorsan, hayır. Maksimum yol derinliğini ve kesim eşiğini çok dikkatli bir şekilde seçmeniz yeterlidir. Sahneden sahneye değişebileceğinden bu çok sıkıcı olabilir.
  3. Sabit bir olasılık (kesme) kullanabilir ve daha sonra 'kayıp' enerjiyi yeniden dağıtabilir misiniz? Bu tarafsız mı?
    • Sabit bir olasılık kullanırsanız, yanlılık eklersiniz. 'Kayıp' enerjiyi yeniden dağıtarak önyargıyı azaltırsınız, ancak yine de matematiksel olarak önyargılıdır. Tamamen tarafsız olması için rastgele olması gerekir.
  4. Enerjisini yeniden dağıtmadan bir ışını sonlandırarak kaybedilecek olan enerji nihayetinde kaybolursa (yeniden dağıtıldığı ışınlar da sona erdiğinden), bu durumu nasıl iyileştirir?
    • Rus Ruleti sadece zıplamayı durdurur. Örneği tamamen çıkarmaz. Ayrıca, 'kayıp' enerji fesih kadar zıplamalarda muhasebeleştirilir. Böylece, enerjinin 'nihayetinde kaybolmasının' tek yolu tamamen siyah bir odaya sahip olmak olacaktır.

Sonunda, Rus Ruleti, çok az miktarda ekstra hesaplama kaynağı kullanan çok basit bir algoritmadır. Buna karşılık, büyük miktarda hesaplama kaynağı kurtarabilir. Bu nedenle, gerçekten bir neden göremiyorum değil kullanmak için.


dürüst olmak gerekirse tamamen emin değilim to be completely unbiased it must be random. Rus ruletinin uyguladığı ikili geçiş / bırakma yerine numunelerin kesirli ağırlıklarını kullanarak hala matematiksel sonuçları elde edebileceğinizi düşünüyorum, sadece ruletin daha hızlı birleşeceği için mükemmel bir önem örneklemesi yapıyor.
v.oddou

9

Rus rulet tekniğinin kendisi, sistemik önyargı getirmeden yolları sonlandırmanın bir yoludur. İlke oldukça basittir: Belirli bir tepe noktasında, enerjiyi keyfi olarak 0 ile değiştirme% 10 şansınız varsa ve bunu sonsuz sayıda yaparsanız,% 10 daha az enerji görürsünüz. Enerji artışı bunu telafi ediyor. Yol sonlandırması nedeniyle kaybedilen enerjiyi telafi etmediyseniz, Rus ruleti önyargılı olurdu, ancak tüm teknik önyargıyı önlemek için yararlı bir yöntemdir.

"Katkısı küçük sabit bir değerden daha az olan yolları sonlandır" tekniğinin önyargılı olduğunu kanıtlamak isteyen bir düşman olsaydım, katkıda bulunan yollar her zaman bu değerden daha az olacak şekilde ışıklı bir sahne inşa ederdim . Belki de düşük ışıklı bir kamera simüle ediyorum.

Ancak elbette sabit değeri her zaman kullanıcı için ayarlanabilir bir parametre olarak açığa çıkarabilirsiniz, böylece sahneleri düşük ışık olduğunda daha da düşebilirler. Şimdi bu örneği bir dakikalığına göz ardı edelim.

Bir tarafından toplanan çok düşük enerjili yollarla aydınlatılan bir nesneyi düşünürsem ne olur? Parabolik bir reflektör ? Düşük enerjili yolları yok ille bir şekilde gelişigüzel yapabilirsiniz bu tamamen ihmal etrafında çıkma. Benzer şekilde akıl yürütme, örneğin, belirli sayıda zıplamadan sonra yolları kesmek için geçerlidir: bir nesneye çarpmadan önce bir dizi 20 aynadan seken yolu olan bir sahne oluşturabilirsiniz.

Bakmanın başka bir yolu: bir sabit epsilonun altına düştükten sonra bir yolun katkısını 0 olarak ayarlarsanız, bu enerji kaybını nasıl düzeltirsiniz? Toplam enerjiyi bir miktar azaltmıyorsunuz. Ne kadar enerji ihmal ettiğiniz hakkında hiçbir şey bilmiyorsunuz, çünkü diğer faktörü bilmeden önce bir katkı eşiğinde kesiyorsunuz: olay enerjisi.


8

Sadece diğer cevapların bazılarını genişletmek için, Rus Ruleti'nin biassed sonuç vermediğinin kanıtı çok basittir.

F

F=F1++FN-

Her terimi şu şekilde değiştirin:

Fben'={1pbenFbenolasılıkla pben0aksi takdirde

Sonra:

E[Fben']=pbenx1pbenE[Fben]+(1-pben)x0=E[Fben]

pbenF

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.