Önem Örneklemesi Nedir?


33

Önem örneklemesi nedir? Bu konuda okuduğum her yazı 'PDF' anlamına geliyor, bu da ne?

Topladığım kadarıyla, önemli örnekleme sadece yarımkürede diğerlerinden daha önemli olan alanları örnekleme tekniğidir. Bu nedenle, ideal olarak, gürültüyü azaltmak ve hızı artırmak için ışık kaynaklarına doğru ışınları örneklemeliyim. Ayrıca, bazı BRDF'lerin otlatma açılarıyla hesaplanmasında çok az bir farkı yoktur, bu yüzden kaçınmak için önemli örneklemenin kullanılması iyi midir?

Cook-Torrance BRDF için önem örneklemesi yapacak olsaydım, bunu nasıl yapabilirdim?


Bu, bir PDF'nin ne olduğunu açıklayan iyi bir bağlantıdır. TL; DR, PDF (sürekli aka kayan nokta) rasgele sayı olasılığını tanımlayan bir fonksiyondur. Belirli bir PDF'den rasgele sayılar oluşturmak zor olabilir ve bunu yapmak için birkaç teknik vardır. Bu onlardan biri hakkında konuşuyor. Bundan sonraki makale başka bir yoldan bahsediyor. blog.demofox.org/2017/08/05/…
Alan Wolfe

Yanıtlar:


51

Kısa cevap:

Önem örneklemesi , gerçek işlevin şekline yakın bir tahminci seçerek Monte Carlo Entegrasyonunda varyansı azaltma yöntemidir.

PDF , Olasılık Yoğunluk Fonksiyonunun kısaltmasıdır . Bir pdf(x) olarak oluşturulan rasgele bir numune olasılığını vermektedir x .

Uzun cevap:

Başlamak için, Monte Carlo Entegrasyonunun ne olduğunu ve matematiksel olarak nasıl göründüğünü gözden geçirelim.

Monte Carlo Entegrasyonu, bir integralin değerini tahmin etmek için kullanılan bir tekniktir. Genellikle integrale kapalı bir form çözümü olmadığında kullanılır. Bu gibi görünüyor:

f(x)dx1Ni=1Nf(xi)pdf(xi)

İngilizce olarak, bu fonksiyondan art arda rasgele örneklerin ortalamasını alarak bir integrali hesaplayabileceğinizi söylüyor. Olarak N büyük olur, yaklaşım daha yakın ve daha yakın çözeltiye alır. pdf(xi) her rastgele örneğin olasılık yoğunluğu işlevini temsil eder.

Bir örnek yapalım: İntegral I değerini hesaplayın .

I=02πexsin(x)dx

Monte Carlo Entegrasyonunu kullanalım:

I1Ni=1Nexsin(xi)pdf(xi)

Bunu hesaplamak için basit bir python programı:

import random
import math

N = 200000
TwoPi = 2.0 * math.pi

sum = 0.0

for i in range(N):
    x = random.uniform(0, TwoPi)

    fx = math.exp(-x) * math.sin(x)
    pdf = 1 / (TwoPi - 0.0)

    sum += fx / pdf

I = (1 / N) * sum
print(I)

Eğer programı çalıştırırsak, I=0.4986941

Parçalara göre ayırma kullanarak tam çözümü elde edebiliriz:

I=12(1e2π)=0.4990663

Monte Carlo Çözümünün pek doğru olmadığını göreceksiniz. Bunun nedeni bir tahmin olmasıdır. Bu, N sonsuzluğa giderken, tahminin doğru cevaba daha yakın ve daha yakın olması gerektiğini söyledi. Zaten N=2000 bazı çalışmalar neredeyse doğru cevaplarla aynı.

PDF hakkında bir not: Bu basit örnekte, her zaman düzenli rastgele bir örnek alırız. Düzgün bir rastgele örneklem, her bir numunenin seçilme ihtimalinin tamamen aynı olduğu anlamına gelir. [0,2π] aralığında örnek alıyoruz , bu nedenle, pdf(x)=1/(2π0)

Önemi örnekleme çalışır değil tekdüze örnekleme. Bunun yerine, sonuca çok katkıda bulunan daha fazla örnek (önemli) ve sonuca yalnızca biraz katkıda bulunan daha az sayıda örnek (daha az önemli) seçmeye çalışıyoruz. Bu nedenle adı, önemi örnekleme.

ffİyi örneklemeyle kötü örneklemenin karşılaştırılması

Yol İzlemede örneklemenin önemine bir örnek, bir yüzeye çarptıktan sonra bir ışın yönünün nasıl seçileceğidir. Yüzey mükemmel bir şekilde speküler değilse (yani bir ayna veya cam), giden ışın yarımkürede herhangi bir yerde olabilir.

Giden ışınlar yarımkürede herhangi bir yere gidebilir

Biz olabilir tekdüze yeni ışın üretmek için Yarımküreyi tadın. Bununla birlikte, oluşturma denkleminin içinde bir kosinüs faktörü olduğu gerçeğinden faydalanabiliriz:

Lo(p,ωo)=Le(p,ωo)+Ωf(p,ωi,ωo)Li(p,ωi)|cosθi|dωi

cos(x)

Bununla mücadele etmek için örneklemeyi önem veriyoruz. Eğer kosinüs ağırlıklı bir yarımküreye göre ışınlar üretersek, ufkun üzerinde daha fazla ve daha ufkun yakınında daha fazla ışın üretilmesini sağlıyoruz. Bu, farkı azaltır ve gürültüyü azaltır.

Sizin durumunuzda, Cook-Torrance, microfacet tabanlı BRDF kullanacağınızı belirttiniz. Yaygın şekli:

f(p,ωi,ωo)=F(ωi,h)G(ωi,ωo,h)D(h)4cos(θi)cos(θo)

nerede

F(ωi,h)=Fresnel functionG(ωi,ωo,h)=Geometry Masking and Shadowing functionD(h)=Normal Distribution Function

"A Graphic's Guy's Note" blogunda Cook-Torrance BRDF'lerinin nasıl örnekleneceği ile ilgili mükemmel bir yazı var. Seni blog postasına yönlendireceğim . Bu, aşağıda kısa bir genel bakış oluşturmaya çalışacağımı söyledi:

NDF, genel olarak Cook-Torrance BRDF'nin baskın kısmıdır, bu nedenle örneklemeye önem verirsek, NDF'ye dayanarak örneklemeliyiz.

Cook-Torrance, kullanılacak belirli bir NDF belirtmiyor; hangisini istediğimize göre seçmekte özgürüz. Bununla birlikte, birkaç popüler NDF vardır:

  • GGX
  • Beckmann
  • Blinn

Her NDF'nin kendi formülü vardır, bu nedenle her biri farklı şekilde örneklenmelidir. Sadece her biri için son örnekleme fonksiyonunu göstereceğim. Formülün nasıl elde edildiğini görmek istiyorsanız, blog gönderisine bakın.

GGX şöyle tanımlanır:

DGGX(m)=α2π((α21)cos2(θ)+1)2

θ

θ=arccos(α2ξ1(α21)+1)

ξ

ϕ

ϕ=ξ2

Beckmann şöyle tanımlanır:

DBeckmann(m)=1πα2cos4(θ)etan2(θ)α2

Şunlarla örneklenebilir:

θ=arccos(11=α2ln(1ξ1))ϕ=ξ2

Son olarak, Blinn şöyle tanımlanır:

DBlinn(m)=α+22π(cos(θ))α

Şunlarla örneklenebilir:

θ=arccos(1ξ1α+1)ϕ=ξ2

Uygulamaya koymak

Temel bir geriye doğru yol izleyiciye 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. sahnenin etrafında zıplıyoruz, gittikçe renk ve ışık zayıflıyoruz. Her sıçramada, ışın için yeni bir yön seçmek zorundayız. Yukarıda belirtildiği gibi, biz olabilir düzgün yeni ışın üretmek için Yarımküreyi tadın. Ancak, kod daha akıllıdır; BRDF'yi temel alan yeni yönü örnekler. (Not: Bu giriş yönüdür, çünkü biz geriye doğru bir yol izleyicisiyiz)

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

Hangi olarak uygulanabilir:

void LambertBRDF::Sample(float3 outputDirection, float3 normal, UniformSampler *sampler) {
    float rand = sampler->NextFloat();
    float r = std::sqrtf(rand);
    float theta = sampler->NextFloat() * 2.0f * M_PI;

    float x = r * std::cosf(theta);
    float y = r * std::sinf(theta);

    // Project z up to the unit hemisphere
    float z = std::sqrtf(1.0f - x * x - y * y);

    return normalize(TransformToWorld(x, y, z, normal));
}

float3a TransformToWorld(float x, float y, float z, float3a &normal) {
    // Find an axis that is not parallel to normal
    float3a majorAxis;
    if (abs(normal.x) < 0.57735026919f /* 1 / sqrt(3) */) {
        majorAxis = float3a(1, 0, 0);
    } else if (abs(normal.y) < 0.57735026919f /* 1 / sqrt(3) */) {
        majorAxis = float3a(0, 1, 0);
    } else {
        majorAxis = float3a(0, 0, 1);
    }

    // Use majorAxis to create a coordinate system relative to world space
    float3a u = normalize(cross(normal, majorAxis));
    float3a v = cross(normal, u);
    float3a w = normal;


    // Transform from local coordinates to world coordinates
    return u * x +
           v * y +
           w * z;
}

float LambertBRDF::Pdf(float3 inputDirection, float3 normal) {
    return dot(inputDirection, normal) * M_1_PI;
}

İnputDirection'ı (koddaki 'wi') örnekledikten sonra, bunu BRDF'nin değerini hesaplamak için kullanırız. Ve sonra Monte Carlo formülüne göre pdf ile bölüyoruz:

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

Nerede Eval () sadece BRDF fonksiyonu kendisidir (Lambert, Blinn-Phong, Cook-Torrance, vs.):

float3 LambertBRDF::Eval(float3 inputDirection, float3 outputDirection, float3 normal) const override {
    return m_albedo * M_1_PI * dot(inputDirection, normal);
}

Güzel cevap OP ayrıca bu cevabın dokunmadığı Cook-Torrance önemini örneklemekten de istedi.
PeteUK

6
Cook-Torrance
RichieSams hakkında

Örneğin GGX, açıyı hesaplamak için cos (θ) küresel koordinatlarını örneklemek için açıyı hesaplamak ve GGX'de normal hak olarak kullanmak için örneklenmiş formülü kullanırız. Yoksa formül GGX’in yerini alıyor mu?
Arjan Singh

3
Sorularınıza cevap vermek için bir bölüm ekledim. Ancak, kısacası, ilk yönteminiz doğru. Daha sonra, normal GGX formülde o yeni bir yön kullanın yönünü oluşturmak için örnekleme formülü kullanın ve Monte Carlo formülü için pdf alır.
RichieSams

GGX için nasıl hesaplayacağım / örnekleyebilirim wi? Küresel koordinatlar açısını sample nasıl örnekleyeceğimi biliyorum ama gerçek yön vektörü için bu nasıl yapılır?
Arjan Singh

11

f(x)f(x) her biri için örnek ve örneklerin ortalamasını hesaplar. Bununla birlikte, bu "saf" Monte Carlo entegrasyonunun "yavaşça yakınsadığı" söylenir, yani özellikle yüksek frekansa sahipse, temel gerçeğe yaklaşmak için çok sayıda örneğe ihtiyacınız vardır.

Önem örneklemeyle [0, 1] aralığında N rastgele örnek almak yerine, in önemli bölgelerinde daha fazla örnek alırsınız.f(x) sonuçta en fazla katkıda . Bununla birlikte, işlevin önemli bölgelerine karşı örnekleme önyargınız olduğundan, bu örneklerin PDF'nin (olasılık yoğunluğu işlevi) ortaya çıktığı önyargıya karşı daha az ağırlıklandırılması gerekir. PDF, bir numunenin verilen pozisyondaki olasılığını söyler ve her numuneyi her numune pozisyonundaki PDF değeri ile bölerek numunelerin ağırlıklı ortalamasını hesaplamak için kullanılır.

f=FGπ(nωi)(nωo)
2π yarımküre için).

NDF için, düzgün dağılmış numune pozisyonunu PDF ağırlıklı numune pozisyonuna dönüştürmek için PDF'nin Kümülatif Dağıtım Fonksiyonunu hesaplamanız gerekir . İzotropik NDF için bu, fonksiyonun simetrisi nedeniyle 1D fonksiyonuna basittir. CDF türevi hakkında daha fazla bilgi için bu eski GPU Gems makalesini inceleyebilirsiniz .

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.