Saya mencoba menerapkan mikrofacet BRDF dalam raytracer saya tetapi saya mengalami beberapa masalah. Banyak makalah dan artikel yang saya baca mendefinisikan istilah geometri parsial sebagai fungsi tampilan dan setengah vektor: G1 (v, h). Namun, ketika menerapkan ini saya mendapat hasil sebagai berikut:
(Baris bawah adalah dielektrik dengan kekasaran 1.0 - 0.0, Baris atas adalah logam dengan kekasaran 1.0 - 0.0)
Ada highlight aneh di sekitar tepi dan cut-off di sekitar nl == 0. Saya benar-benar tidak tahu dari mana ini berasal. Saya menggunakan Unity sebagai referensi untuk memeriksa render saya, jadi saya memeriksa sumber shader mereka untuk melihat apa yang mereka gunakan dan dari apa yang saya tahu istilah geometri mereka tidak ditentukan oleh setengah vektor sama sekali! Jadi saya mencoba kode yang sama tetapi digunakan untuk permukaan makro normal, bukan setengah vektor dan mendapat hasil sebagai berikut:
Bagi mata saya yang tidak terlatih ini tampaknya jauh lebih dekat dengan hasil yang diinginkan. Tetapi saya merasa ini tidak benar? Mayoritas artikel yang saya baca menggunakan setengah vektor tetapi tidak semuanya. Apakah ada alasan untuk perbedaan ini?
Saya menggunakan kode berikut sebagai istilah geometri saya:
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);
}
Dan untuk referensi, ini adalah fungsi distribusi normal saya:
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);
}
sumber