Sto cercando di implementare un microfacet BRDF nel mio raytracer ma sto riscontrando alcuni problemi. Molti dei documenti e degli articoli che ho letto definiscono il termine di geometria parziale in funzione della vista e dei mezzi vettori: G1 (v, h). Tuttavia, durante l'implementazione ho ottenuto il seguente risultato:
(La riga inferiore è dielettrica con rugosità 1,0 - 0,0, la riga superiore è metallica con rugosità 1,0 - 0,0)
C'è uno strano punto culminante intorno ai bordi e un taglio intorno a nl == 0. Non riuscivo davvero a capire da dove venisse. Sto usando Unity come riferimento per controllare i miei rendering, quindi ho controllato la loro fonte di shader per vedere cosa usano e da quello che posso dire che il loro termine di geometria non è affatto parametrizzato dal mezzo vettore! Quindi ho provato lo stesso codice ma ho usato la macro superficie normale invece del mezzo vettore e ho ottenuto il seguente risultato:
A mio avviso non allenato questo sembra molto più vicino al risultato desiderato. Ma ho la sensazione che non sia corretto? La maggior parte degli articoli che leggo usano il mezzo vettore ma non tutti. C'è una ragione per questa differenza?
Uso il seguente codice come termine di geometria:
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);
}
E per riferimento, questa è la mia normale funzione di distribuzione:
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);
}