Ich versuche, ein Mikrofacetten-BRDF in meinem Raytracer zu implementieren, stoße jedoch auf einige Probleme. Viele der Artikel und Artikel, die ich gelesen habe, definieren den Teilgeometrie-Term als Funktion der Ansicht und der Halbvektoren: G1 (v, h). Bei der Implementierung habe ich jedoch folgendes Ergebnis erhalten:
(Die untere Reihe ist dielektrisch mit einer Rauheit von 1,0 bis 0,0, die obere Reihe ist metallisch mit einer Rauheit von 1,0 bis 0,0)
Es gibt ein seltsames Highlight an den Rändern und einen Cut-Off um nl == 0. Ich konnte nicht wirklich herausfinden, woher das kommt. Ich verwende Unity als Referenz, um meine Renderings zu überprüfen, also habe ich ihre Shader-Quelle überprüft, um zu sehen, was sie verwenden und was ich sagen kann, dass ihr Geometrie-Term überhaupt nicht durch den Halbvektor parametrisiert wird! Also habe ich den gleichen Code ausprobiert, aber anstelle des Halbvektors die Makrooberflächennormale verwendet und das folgende Ergebnis erhalten:
Für mein ungeübtes Auge scheint dies dem gewünschten Ergebnis viel näher zu kommen. Aber ich habe das Gefühl, das ist nicht richtig? Die meisten Artikel, die ich lese, verwenden den halben Vektor, aber nicht alle. Gibt es einen Grund für diesen Unterschied?
Ich verwende den folgenden Code als Geometriebegriff:
float RayTracer::GeometryGGX(const Vector3& v, const Vector3& l, const Vector3& n, const Vector3& h, float a)
{
return G1GGX(v, h, a) * G1GGX(l, h, a);
}
float RayTracer::G1GGX(const Vector3& v, const Vector3& h, float a)
{
float NoV = Util::Clamp01(cml::dot(v, h));
float a2 = a * a;
return (2.0f * NoV) / std::max(NoV + sqrt(a2 + (1.0f - a2) * NoV * NoV), 1e-7f);
}
Und als Referenz ist dies meine normale Verteilungsfunktion:
float RayTracer::DistributionGGX(const Vector3& n, const Vector3& h, float alpha)
{
float alpha2 = alpha * alpha;
float NoH = Util::Clamp01(cml::dot(n, h));
float denom = (NoH * NoH * (alpha2 - 1.0f)) + 1.0f;
return alpha2 / std::max((float)PI * denom * denom, 1e-7f);
}