Я намагаюся реалізувати мікропрограму BRDF у своєму raytracer, але я стикаюся з деякими проблемами. Чимало прочитаних статей та статей визначають термін часткової геометрії як функцію перегляду та піввікторів: G1 (v, h). Однак, реалізуючи це, я отримав такий результат:
(Нижній ряд діелектрик із шорсткістю 1,0 - 0,0, верхній ряд - металік із шорсткістю 1,0 - 0,0)
Існує дивна родзинка по краях і обріз навколо nl == 0. Я не міг реально зрозуміти, звідки це походить. Я використовую Unity як орієнтир, щоб перевірити свої рендери, тому я перевірив їх джерело шейдерів, щоб побачити, що вони використовують, і з того, що я можу сказати, їх термін геометрії взагалі не параметризований половинним вектором! Тому я спробував той самий код, але використовував макрос поверхню нормально замість половинного вектора і отримав такий результат:
Моєму нетренованому оці це здається набагато ближчим до бажаного результату. Але у мене таке відчуття, що це не правильно? Більшість статей, які я читаю, використовують половинний вектор, але не всі. Чи є причина цієї різниці?
Я використовую такий код як мій термін геометрії:
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);
}
Для довідки, це моя нормальна функція розподілу:
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);
}