BRDF und sphärische Koordinate bei der Strahlverfolgung


9

Ich habe einen Ray Tracer entwickelt, der ein Standardmodell für Phong / Blinn Phong-Beleuchtung verwendet. Jetzt ändere ich es, um physisch basiertes Rendering zu unterstützen, und implementiere verschiedene BRDF-Modelle. Im Moment konzentriere ich mich auf das Modell Oren-Nayar und Torrance-Sparrow. Jedes von diesen basiert auf sphärischen Koordinaten, die verwendet werden, um einfallendes wi und ausgehende wo Lichtrichtung auszudrücken.

Meine Frage ist: Welcher Weg ist der richtige, um wi und wo von kartesischer Koordinate in sphärische Koordinate umzuwandeln?

Ich wende die hier angegebene Standardformel an: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions , bin mir aber nicht sicher, ob ich das Richtige tue, da mein Vektor nicht mit dem Schwanz am Ursprung des kartesisches Koordinatensystem, sind jedoch auf dem Schnittpunkt des Strahls mit dem Objekt zentriert.

Hier finden Sie meine aktuelle Implementierung:

Kann mir jemand helfen, eine Erklärung für die korrekte Konvertierung des wi und wo-Vektors von kartesischen in sphärische Koordinaten zu geben?

AKTUALISIEREN

Ich kopiere hier den relevanten Teil des Codes:

sphärische Koordinatenberechnung

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

UPDATE 2

Nach einiger Suche fand ich diese Implementierung von Oren-Nayar BRDF .

In der obigen Implementierung wird Theta für wi und wo erhalten, indem einfach arccos (wo.dotProduct (Normal)) und arccos (wi.dotProduct (Normal)) ausgeführt werden. Dies erscheint mir vernünftig, da wir die Normalen des Schnittpunkts als Zenitrichtung für unser sphärisches Koordinatensystem verwenden und die Berechnung durchführen können. Die Berechnung von gamma = cos (phi_wi - phi_wo) führt eine Art Projektion von wi und wo auf das durch, was es "Tangentenraum" nennt. Vorausgesetzt, in dieser Implementierung ist alles korrekt, kann ich einfach die Formeln | View - Normal x (View.dotProduct (Normal)) | verwenden und | Licht - Normal x (Light.dotProduct (Normal)) | um die Phi-Koordinate zu erhalten (anstatt Arctan ("etwas") zu verwenden)?


Könnte mir jemand helfen?
Fabrizio Duroni

Können Sie das genaue Code-Snippet anzeigen, nicht das gesamte Repo?
Konzept3d

Es scheint, dass dies eine der mysteriösesten Fragen zum Raytracing
aller

Ich ermutige Sie, hier zu fragen computergraphics.stackexchange.com
concept3d

Antworten:


2

Es ist eigentlich besser, keine sphärischen Koordinaten (oder Winkel) für die Implementierung von BRDFs zu verwenden, sondern direkt im kartesischen Koordinatensystem zu arbeiten und den Kosinus des Winkels zwischen Vektoren zu verwenden, der bekanntlich ein einfaches Punktprodukt zwischen Einheitsvektoren ist. Dies ist sowohl robuster als auch effizienter.

Für Oren-Nayar denken Sie vielleicht, dass Sie Winkel verwenden müssen (aufgrund der minimalen / maximalen Winkel), aber Sie können die BRDF einfach direkt im kartesischen Raum implementieren: https://fgiesen.wordpress.com/2010/10/21 / Beende-deine-Ableitungen-bitte

Für Torrance-Sparrow- oder Cook-Torrance-Mikrofacetten-BRDFs müssen Sie auch keine sphärischen Koordinaten verwenden. In diesen BRDFs wird der Winkel in D / F / G-Begriffen und im BRDF-Nenner an eine trigonometrische (normalerweise Kosinus-) Funktion übergeben, sodass Sie gerade oder trigonometrische Identitäten von Punktprodukten verwenden können, ohne sphärische Koordinaten zu durchlaufen.


1

Sie können ein Koordinatensystem mit dem normalen N und einem anderen Vektor angeben. Wir werden wi wählen. Jeder Vektor, der die gleiche Richtung wie wi hat, wenn er auf die Tangentialebene projiziert wird, hat einen Azimut von 0

Zuerst projizieren wir wi auf die Tangentialebene: (vorausgesetzt, wi ist bereits normalisiert)

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

Jetzt können wir dasselbe mit wo machen:

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

Nun liegen Witz und Witz sowohl auf einer Ebene, die orthogonal zu N ist, als auch tangential zum Schnittpunkt.

Wir können jetzt den Winkel zwischen den beiden berechnen:

azimuth = arcos ( dot(wit, wot) )

Welches ist wirklich der Azimut von Wot in Bezug auf Witz, wenn auf die Tangentialebene projiziert.


0

Wenn Sie den Schnittpunkt und den Ursprungspunkt kennen, geht es dann nicht nur darum, einen vom anderen zu subtrahieren, damit Sie das Ergebnis so erhalten, als wäre es vom Ursprung?

Wenn Sie dem Ergebnis nicht glauben und auf dem langen Weg dorthin gelangen möchten, können Sie die Rotationstransformation auch über eine LookAt-Matrix von einem Punkt zum anderen bringen und dann zerlegen, um die Rotationskomponente zu erhalten. Sie können auch eine Quaternion daraus erhalten, wenn Sie möchten.

Die Ergebnisse sind gleich. Der Beweis ist etwas lang, aber nicht kompliziert und bleibt dem Leser überlassen.


Hallo @Panda Pyjama, danke für deine Antwort, aber ich kann deine Antwort nicht verstehen. Ich versuche zu klären: Wenn ich den Schnittpunkt und den Standpunkt hätte, könnte ich wi und wo berechnen. Dann kann ich die Normale als meine Zenitrichtung verwenden, um zu berechnen, aber ich kann nicht die andere Achse finden, die benötigt wird, um den Azimutwinkel auf einer Ebene senkrecht zum Zenit zu finden. Im obigen Ausschnitt habe ich einfach die Umrechnungsformeln für die sphärische Koordinate auf wi und wo angewendet, die im Weltkoordinatensystem angegeben sind, aber ich denke nicht, dass dies der richtige Weg ist, um Theta und Phi zu berechnen.
Fabrizio Duroni
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.