BRDF e coordinate sferiche nel ray tracing


9

Ho sviluppato un ray tracer che utilizza un modello di illuminazione phong / blinn phong standard. Ora lo sto modificando per supportare il rendering basato fisicamente, quindi sto implementando vari modelli BRDF. Al momento sono concentrato sul modello Oren-Nayar e Torrance-Sparrow. Ognuno di questi si basa su coordinate sferiche utilizzate per esprimere gli incidenti e la direzione della luce in uscita.

La mia domanda è: in che modo è quello giusto convertire wi e wo da coordinate cartesiane a coordinate sferiche?

Sto applicando la formula standard riportata qui https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions ma non sono sicuro di fare la cosa giusta, perché il mio vettore non è con la coda all'origine del sistema di coordinate cartesiane, ma sono centrate sul punto di intersezione del raggio con l'oggetto.

Qui puoi trovare la mia attuale implementazione:

Qualcuno può aiutarmi a dare una spiegazione del modo corretto di convertire il vettore wi e wo da coordinate cartesiane a coordinate sferiche?

AGGIORNARE

Copio qui la parte pertinente del codice:

calcolo delle coordinate sferiche

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

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

AGGIORNAMENTO 2

Dopo alcune ricerche ho trovato questa implementazione di Oren-Nayar BRDF .

Nell'implementazione sopra theta per wi e wo si ottiene semplicemente facendo arccos (wo.dotProduct (Normal)) e arccos (wi.dotProduct (Normal)). Questo mi sembra ragionevole, dato che possiamo usare la normale del punto di intersezione come direzione zenitale per il nostro sistema di coordinate sferiche e fare il calcolo. Il calcolo di gamma = cos (phi_wi - phi_wo) fa una sorta di proiezione di wi e guai su quello che chiama "spazio tangente". Supponendo che tutto sia corretto in questa implementazione, posso semplicemente usare le formule | View - Normal x (View.dotProduct (Normal)) | e | Light - Normal x (Light.dotProduct (Normal)) | ottenere la coordinata phi (invece di usare arctan ("qualcosa"))?


Qualcuno potrebbe aiutarmi?
Fabrizio Duroni,

Puoi mostrare lo snippet di codice esatto, non l'intero repository?
concept3d

Sembra che questa sia una delle domande più misteriose sul ray tracing di tutti i tempi: D
Fabrizio Duroni,

Ti incoraggio a chiedere qui computergraphics.stackexchange.com
concept3d

Risposte:


2

In realtà è meglio non usare le coordinate sferiche (o qualsiasi angolo per quella materia) per implementare i BRDF, ma piuttosto lavorare direttamente nel sistema di coordinate cartesiane e usare il coseno dell'angolo tra i vettori, che è un semplice punto tra i vettori di unità come sapete. Questo è sia più robusto che efficiente.

Per Oren-Nayar potresti pensare di dover usare gli angoli (a causa del minimo / massimo degli angoli), ma puoi semplicemente implementare il BRDF direttamente nello spazio cartesiano: https://fgiesen.wordpress.com/2010/10/21 / finitura-your-derivazioni-si prega

Per i microfiltri Torrance-Sparrow o Cook-Torrance BRDF non è necessario nemmeno utilizzare coordinate sferiche. In questi BRDF l'angolo viene passato a una funzione trigonometrica (di solito coseno) in termini D / F / G e al denominatore BRDF, in modo da poter utilizzare identità diritte o trigonometriche del prodotto punto senza passare per coordinate sferiche.


1

È possibile specificare un sistema di coordinate dato la N normale e un altro vettore. Sceglieremo wi. Quindi ogni vettore che ha la stessa direzione di wi quando viene proiettato sul piano tangente avrà un azimut di 0

Innanzitutto, proiettiamo wi sul piano tangente: (supponendo che wi sia già normalizzato)

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

ora possiamo fare lo stesso con wo:

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

Ora, l'arguzia e il wot giacciono sia su un piano ortogonale a N, sia tangente al punto di intersezione.

Ora possiamo calcolare l'angolo tra i due:

azimuth = arcos ( dot(wit, wot) )

Che è davvero l'azimut di wot rispetto all'ingegno quando proiettato sul piano tangente.


0

Se conosci il punto di intersezione e il punto di origine, non sarebbe solo una questione di sottrarre l'uno dall'altro in modo da ottenere il risultato come se fosse dall'origine?

Se non credi al risultato e vuoi raggiungerlo attraverso una lunga strada, puoi anche ottenere la trasformazione della rotazione per passare da un punto all'altro tramite una matrice LookAt e quindi decomporlo per ottenere il componente rotazionale. Puoi anche ottenere un quaternione da esso, se lo desideri.

I risultati sono uguali La prova è un po 'lunga, ma non complicata, e viene lasciata al lettore.


Ciao @Panda Pajama, grazie per la tua risposta, ma non riesco a capire la tua risposta. Cerco di chiarire: se avessi il punto di intersezione e il punto di vista posso calcolare wi e wo. Quindi posso usare la normale come direzione del mio zenit per calcolare, ma non sono in grado di trovare l'altro asse necessario per trovare l'angolo azimut su un piano ortogonale allo zenit. Nello snipped sopra ho semplicemente applicato le formule di conversione per coordinate sferiche su wi e wo fornite nel sistema di coordinate mondiale, ma non credo che questo sia il modo giusto per calcolare theta e phi.
Fabrizio Duroni,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.