Işın takibinde BRDF ve Küresel koordinat


9

Standart phong / blinn phong aydınlatma modelini kullanan bir ışın izleyici geliştirdim. Şimdi fiziksel olarak oluşturmayı destekleyecek şekilde değiştiriyorum, bu yüzden çeşitli BRDF modelleri uyguluyorum. Şu anda Oren-Nayar ve Torrance-Sparrow modeline odaklandım. Bunların her biri, olay wi ve giden ışık yönünü ifade etmek için kullanılan küresel koordinatlara dayanmaktadır.

Benim sorum şu: doğru olan ne wi ve wo'yu kartezyen koordinattan küresel koordinatlara dönüştürüyor?

Burada bildirilen standart formülü uyguluyorum https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions ama doğru şeyi yaptığımdan emin değilim, çünkü vektörüm kökeninde kuyruklu değil kartezyen koordinat sistemi, ancak nesne ile ışının kesişme noktası üzerinde merkezlenir.

Burada mevcut uygulamamı bulabilirsiniz:

Herkes wi ve wo vektörü kartezyen küresel koordinat dönüştürmek için doğru yolu açıklamak bana yardımcı olabilir?

GÜNCELLEME

Kodun ilgili kısmını buraya kopyalarım:

küresel koordinat hesabı

float Vector3D::sphericalTheta() const {

    float sphericalTheta = acosf(Utils::clamp(y, -1.f, 1.f));

    return sphericalTheta;
}

float Vector3D::sphericalPhi() const {

    float phi = atan2f(z, x);

    return (phi < 0.f) ? phi + 2.f * M_PI : phi;
}

Ören Nayar

OrenNayar::OrenNayar(Spectrum<constant::spectrumSamples> reflectanceSpectrum, float degree) : reflectanceSpectrum{reflectanceSpectrum} {

    float sigma = Utils::degreeToRadian(degree);
    float sigmaPowerTwo = sigma * sigma;

    A = 1.0f - (sigmaPowerTwo / 2.0f * (sigmaPowerTwo + 0.33f));
    B = 0.45f * sigmaPowerTwo / (sigmaPowerTwo + 0.09f);
};

Spectrum<constant::spectrumSamples> OrenNayar::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {

    float thetaI = wi.sphericalTheta();
    float phiI = wi.sphericalPhi();

    float thetaO = wo.sphericalTheta();
    float phiO = wo.sphericalPhi();

    float alpha = std::fmaxf(thetaI, thetaO);
    float beta = std::fminf(thetaI, thetaO);

    Spectrum<constant::spectrumSamples> orenNayar = reflectanceSpectrum * constant::inversePi * (A + B * std::fmaxf(0, cosf(phiI - phiO) * sinf(alpha) * tanf(beta)));

    return orenNayar;
}

Torrance-Sparrow

float TorranceSparrow::G(const Vector3D& wi, const Vector3D& wo, const Vector3D& wh, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float normalDotWh = fabsf(normal.dot(wh));
    float normalDotWo = fabsf(normal.dot(wo));
    float normalDotWi = fabsf(normal.dot(wi));
    float woDotWh = fabsf(wo.dot(wh));

    float G = fminf(1.0f, std::fminf((2.0f * normalDotWh * normalDotWo)/woDotWh, (2.0f * normalDotWh * normalDotWi)/woDotWh));

    return G;
}

float TorranceSparrow::D(const Vector3D& wh, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float cosThetaH = fabsf(wh.dot(normal));

    float Dd = (exponent + 2) * constant::inverseTwoPi * powf(cosThetaH, exponent);

    return Dd;
}

Spectrum<constant::spectrumSamples> TorranceSparrow::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float thetaI = wi.sphericalTheta();
    float thetaO = wo.sphericalTheta();

    float cosThetaO = fabsf(cosf(thetaO));
    float cosThetaI = fabsf(cosf(thetaI));

    if(cosThetaI == 0 || cosThetaO == 0) {

        return reflectanceSpectrum * 0.0f;
    }

    Vector3D wh = (wi + wo);
    wh.normalize();

    float cosThetaH = wi.dot(wh);

    float F = Fresnel::dieletricFresnel(cosThetaH, refractiveIndex);
    float g = G(wi, wo, wh, intersection);
    float d = D(wh, intersection);

    printf("f %f g %f d %f \n", F, g, d);
    printf("result %f \n", ((d * g * F) / (4.0f * cosThetaI * cosThetaO)));

    Spectrum<constant::spectrumSamples> torranceSparrow = reflectanceSpectrum * ((d * g * F) / (4.0f * cosThetaI * cosThetaO));

    return torranceSparrow;
}

GÜNCELLEME 2

Bazı araştırmalardan sonra Oren-Nayar BRDF'nin bu uygulamasını buldum .

Yukarıdaki uygulamada wi ve wo için teta sadece arccos (wo.dotProduct (Normal)) ve arccos (wi.dotProduct (Normal)) yapılarak elde edilir. Bu benim için makul görünüyor, çünkü kavşak noktasının normalini küresel koordinat sistemimiz için zirve yönü olarak kullanabilir ve hesaplamayı yapabiliriz. Gama = cos (phi_wi - phi_wo) hesaplaması, “teğet boşluk” olarak adlandırdığı şeye bir tür wi ve wo projeksiyonu yapar. Bu uygulamada her şeyin doğru olduğunu varsayarsak, sadece formülleri kullanabilir miyim | View - Normal x (View.dotProduct (Normal)) | ve | Işık - Normal x (Light.dotProduct (Normal)) | phi koordinatını elde etmek için (arctan kullanmak yerine ("bir şey"))?


Biri bana yardım edebilir mi?
Fabrizio Duroni

Tam kod snippet'ini gösterebilir misiniz, deponun tamamını değil mi?
concept3d

Öyle görünüyor ki, bu, al zamanlarının ışın izlemesiyle ilgili en gizemli sorulardan biri: D
Fabrizio Duroni

Burada size sormanızı
öneririm

@ Concept3d içinde yapılır. Bunu burada bulabilirsiniz computergraphics.stackexchange.com/questions/1799/…
Fabrizio Duroni

Yanıtlar:


2

Aslında daha iyi değil BRDF uygulayacağımızı da küresel koordinatlar (ya da bu konuda herhangi açıları) kullanmak değil, düz Kartezyen çalışmak bildiğiniz gibi birim vektörler arasındaki düz nokta üründür vektörleri arasındaki açı, sistem ve kullanım kosinüsü koordine etmek. Bu hem daha sağlam hem de daha verimlidir.

Oren-Nayar için açıları kullanmanız gerektiğini düşünebilirsiniz (açıların min / maks. Nedeniyle), ancak BRDF'yi doğrudan Kartezyen alanına uygulayabilirsiniz: https://fgiesen.wordpress.com/2010/10/21 / bitiş-your-türevleri-lütfen

Torrance-Sparrow veya Cook-Torrance mikrofacet BRDF'leri için küresel koordinatlar da kullanmanıza gerek yoktur. Bu BRDF'lerde açı, D / F / G terimleri ve BRDF paydasında trigonometrik (genellikle kosinüs) bir işleve geçirilir, böylece küresel koordinatlardan geçmeden nokta ürünü düz veya trigonometrik kimlikler kullanabilirsiniz .


1

Normal N ve başka bir vektör verildiğinde bir koordinat sistemi belirleyebilirsiniz. Biz wi seçeceğiz. Böylece, teğet düzleme yansıtıldığında wi ile aynı yöne sahip herhangi bir vektör 0'lık bir azimutuna sahip olacaktır.

İlk olarak, teğet düzlemde wi projelendiririz: (wi'nin zaten normalleştirilmiş olduğu varsayılarak)

wit = normalize(wi - N * dot(wi, N))

şimdi, wo ile aynı şeyi yapabiliriz:

wot = normalize(wo - N * dot(wo, N))

Şimdi, zekâ ve wot, hem N'ye dik hem de kavşak noktasına teğet olan bir düzlemde uzanır.

Şimdi ikisi arasındaki açıyı hesaplayabiliriz:

azimuth = arcos ( dot(wit, wot) )

Hangi gerçekten teğet düzlemde yansıtıldığında zekâya göre wotun azimutudur.


0

Eğer kavşak noktasını ve menşe noktasını biliyorsanız, bu sadece birinden diğerinden çıkarılması meselesi olmaz mı, böylece sonucu menşeden gelmiş gibi mi elde edersiniz?

Sonuca inanmıyorsanız ve oraya uzun yoldan ulaşmak istiyorsanız, bir LookAt matrisi aracılığıyla bir noktadan diğerine dönme dönüşümü elde edebilir ve ardından dönme bileşenini almak için ayrıştırabilirsiniz. İsterseniz ondan bir kuaterniyon da alabilirsiniz.

Sonuçlar eşittir. Kanıt biraz uzun, ama karmaşık değil ve okuyucuya bırakıldı.


Merhaba @Panda Pijama Cevabınız için teşekkür ederim, ama cevabınızı anlayamıyorum. Açıklığa kavuşturmaya çalışıyorum: Eğer kavşak noktası ve bakış açısı olsaydı wi ve wo hesaplayabilirim. Sonra normali hesaplamak için zenith yönüm olarak kullanabilirim, ancak zenith'e dik bir düzlemde azimut açısını bulmak için gereken diğer ekseni bulamıyorum. Yukarıdaki parçalamada, dünya koordinat sisteminde verilen wi ve wo üzerindeki küresel koordinat için dönüşüm formüllerini uyguladım, ancak bunun teta ve phi'yi hesaplamanın doğru yolu olduğunu düşünmüyorum.
Fabrizio Duroni
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.