Problem mit Wichtigkeitsstichproben
Ich habe versucht, eine wichtige Stichprobe auf der Lambertschen Oberfläche zu machen. Zuerst wähle ich einheitlich die Richtung aus der Einheitskugel.
vec3 direction = camera->genDirection();
...
direction = random_in_unit_sphere();
float cosine = dotp(direction,surfaceNormal);
/*
float dotp(float val){
val = dot(val);
if(val>0.0001f) return val;
else return 0.0001f;
}
*/
vec3 brdf_result = material->baseColor/Pi;//lambertian
vec3 pdf = 1.0f/(2.0f*Pi);
throughput = throughput * brdf_result * cosine / pdf;
Mit 10 Samples pro Pixel ergibt sich:
dann wähle ich eine zufällige Richtung von der Einheitshalbkugel über der Oberfläche
direction = random_in_unit_hemisphere(surfaceNormal);
float cosine = dotp(direction,surfaceNormal);
vec3 brdf_result = material->baseColor/Pi;
vec3 pdf = 1.0f/(1.0f*Pi);
throughput = throughput * brdf_result * cosine / pdf;
Das Ergebnis ist bis auf weniger Rauschen sehr ähnlich
und dann verwende ich die Wichtigkeitsstichprobenmethode von (http://in1weekend.blogspot.com/)
class onb {
public:
vec3 operator[](int i)const { return axis[i]; }
vec3 u()const { return axis[0]; }
vec3 v()const { return axis[1]; }
vec3 w()const { return axis[2]; }
vec3 local(float a, float b, float c) { return a * u() + b * v() + c * w(); }
vec3 local(const vec3& a) { return a.x * u() + a.y * v() + a.z * w(); }
void buildFromNormal(const vec3& n) {
axis[2] = normalize(n);
vec3 a;
if (std::abs(w().x) > 0.9f)
a = vec3(0.0f, 1.0f, 0.0f);
else
a = vec3(1.0f, 0.0f, 0.0f);
axis[1] = normalize(cross(w(), a));
axis[0] = cross(w(), v());
}
private:
vec3 axis[3];
};
vec3 randCosDir() {
float r1 = randFloat01();
float r2 = randFloat01();
float z = sqrt(1.0f - r2);
float phi = 2.0f * Pi * r1;
float x = cos(phi) * 2.0f * sqrt(r2);
float y = sin(phi) * 2.0f * sqrt(r2);
return vec3(x, y, z);
}
,
onb uvw;
uvw.buildFromNormal(surfaceNormal);
direction = normalize(uvw.local(randCosDir()));
float cosine = dotp(direction,surfaceNormal);
vec3 brdf_result = material->baseColor/Pi;
vec3 pdf = dotp(uvw.w(), direction)/Pi;
throughput = throughput * brdf_result * cosine / pdf;
Das Ergebnis ist jedoch anders:
Die Grundfarbe der Wand ist vec3 (0,8f, 0,8f, 0,8f) und die Farbe des Lichtkuppels ist vec3 (1,0f, 1,0f, 1,0f). In einigen Lernprogrammen befindet sich das Cosinus-Element im lambertschen brdf, und einige befinden sich in der Render-Gleichung und inhttp://in1weekend.blogspot.com/ "Wochenende eins" gibt es überhaupt keinen Kosinusartikel. Ich bin wirklich mit diesen Konzepten durcheinander. Gibt es jemanden, der mir hilft? Vielen Dank.
Bei einem anderen Rendering mit baseColor = vec3 (1.0f, 1.0f, 1.0f) und Dome-Farbe = vec3 (0.5f, 0.5f, 0.5f) (Wichtigkeitsabtastung) beträgt die durchschnittliche Farbe des endgültigen Bilds über alle Pixel vec3 (0.470884f) 0,470884f, 0,470884f).
Antworten
Es gibt einige Fehler in Ihrer Mathematik. Sie haben das Problem mit den 2π und 4π in den Hemisphäre- und Kugelabtastfunktionen bereits gefunden, aber auch diese Linien in der Cosinus-Hemisphäre-Abtastung sind falsch:
float x = cos(phi) * 2.0f * sqrt(r2);
float y = sin(phi) * 2.0f * sqrt(r2);
Es sollte keinen Faktor 2 geben: Dies verzerrt die Kosinusverteilung.
Ebenfalls,
vec3 pdf = dotp(uvw.w(), direction)/Pi;
throughput = throughput * brdf_result * cosine / pdf;
Das ist nicht falsch, aber es ist unnötig: Das pdfhebt das auf cosine, daher wäre es vorzuziehen pdf, nur 1 / π einzustellen und den Kosinusfaktor wegzulassen. Tatsächlich hebt dies auch die 1 / π in der auf brdf_result, sodass Sie diese beiden pi-Faktoren weglassen und pdfvollständig loswerden können .
Mehr zum Kosinusfaktor: Die gesamte Idee der Probenahme mit einer kosinusgewichteten Halbkugel besteht darin, zu vermeiden, dass der Kosinusfaktor im Pfaddurchsatz berücksichtigt werden muss. Grundsätzlich möchten Sie den Cosinus nur an einer Stelle haben: entweder in der Stichprobenverteilung oder im Durchsatz, aber nicht in beiden. Es ist vorzuziehen, es in die Stichprobenverteilung aufzunehmen, da dann die Varianz in den Stichproben geringer ist (da sie keinen stark variierenden Kosinusfaktor in ihrem Durchsatz haben), sodass das Rendering schneller konvergiert.
Dies ist auch eine allgemeine Maxime bei der Pfadverfolgung: Sie möchten im Allgemeinen Faktoren aus dem Durchsatz in die Strahlverteilung verschieben, wann immer dies praktikabel ist. Dies ist die Idee der Wichtigkeitsabtastung von BRDFs (Verschieben von Faktoren vom BRDF in die Strahlverteilung) und der expliziten Lichtabtastung (Verschieben von Teilen der einfallenden Lichtverteilung in die Strahlverteilung) sowie fortgeschrittener Dinge wie Abtasten mit mehreren Wichtigkeiten oder Wegführung.
Ich habe gerade festgestellt, dass wenn ich pdf = 1.0f / (4.0f * Pi) bei der Abtastung von Einheitskugeln oder pdf = 1.0f / (2.0f * Pi) bei der Abtastung von Einheitshalbkugeln verwende, das Ergebnis fast das gleiche ist wie bei der Abtastung der Wichtigkeit (Ich erhalte das gleiche Ergebnis auch, wenn ich die baseColor auf vec3 (0,4f, 0,4f, 0,4f), die Hälfte von vec3 (0,8f, 0,8f, 0,8f) setze. Und die Oberfläche einer Einheitskugel beträgt nur 4,0 f * Pi (Ich vergesse, warum ich 2.0f * Pi vorher verwendet habe). Ich muss zu zwei Schlussfolgerungen kommen:
1: die Wichtigkeitsstichprobe ist richtig!
2: Ich bin zu dumm !!!!!!