J'essaie d'implémenter un BRDF microfacet dans mon raytracer mais je rencontre des problèmes. Beaucoup d'articles et d'articles que j'ai lus définissent le terme de géométrie partielle en fonction de la vue et des demi-vecteurs: G1 (v, h). Cependant, lors de l'implémentation, j'ai obtenu le résultat suivant:
(La rangée inférieure est diélectrique avec une rugosité de 1,0 à 0,0, la rangée supérieure est métallique avec une rugosité de 1,0 à 0,0)
Il y a un point culminant étrange sur les bords et une coupure autour de nl == 0. Je ne pouvais pas vraiment comprendre d'où cela venait. J'utilise Unity comme référence pour vérifier mes rendus, j'ai donc vérifié leur source de shader pour voir ce qu'ils utilisent et d'après ce que je peux dire, leur terme de géométrie n'est pas du tout paramétré par le demi-vecteur! J'ai donc essayé le même code mais utilisé pour macro surface normale au lieu du demi-vecteur et a obtenu le résultat suivant:
À mon œil non averti, cela semble beaucoup plus proche du résultat souhaité. Mais j'ai le sentiment que ce n'est pas correct? La majorité des articles que j'ai lus utilisent le demi-vecteur mais pas tous. Y a-t-il une raison à cette différence?
J'utilise le code suivant comme terme de géométrie:
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);
}
Et pour référence, voici ma fonction de distribution normale:
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);
}
la source