Estoy tratando de implementar un microfacet BRDF en mi raytracer pero me encuentro con algunos problemas. Muchos de los artículos y artículos que he leído definen el término de geometría parcial en función de la vista y los medios vectores: G1 (v, h). Sin embargo, al implementar esto obtuve el siguiente resultado:
(La fila inferior es dieléctrica con rugosidad 1.0 - 0.0, la fila superior es metálica con rugosidad 1.0 - 0.0)
Hay un extraño resaltado alrededor de los bordes y un corte alrededor de nl == 0. Realmente no pude entender de dónde viene esto. Estoy usando Unity como referencia para verificar mis renders, así que verifiqué su fuente de sombreador para ver qué usan y, por lo que puedo decir, su término de geometría no está parametrizado en absoluto por el medio vector. Así que probé el mismo código pero usé macro superficie normal en lugar del medio vector y obtuve el siguiente resultado:
Para mi ojo inexperto, esto parece mucho más cercano al resultado deseado. Pero tengo la sensación de que esto no es correcto? La mayoría de los artículos que leo usan el medio vector, pero no todos. ¿Hay alguna razón para esta diferencia?
Yo uso el siguiente código como mi término de geometría:
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);
}
Y como referencia, esta es mi función de distribución normal:
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);
}