Физически основанный шейдер не дает желаемых результатов
За последние ~2-3 недели я узнал о физическом затенении, и я просто не могу обернуть свою голову вокруг некоторых проблем, которые у меня есть.
Шейдер Фрагментов
#version 430
#define PI 3.14159265358979323846
// Inputs
in vec3 inputNormal;
vec3 fNormal;
// Material
float reflectance = 1.0; // 0 to 1
float roughness = 0.5;
vec3 specularColor = vec3(1.0, 1.0, 1.0); // f0
// Values
vec3 lightVector = vec3(1, 1, 1); // Light (l)
vec3 eyeVector = vec3(2.75, 1.25, 1.25); // Camera (v)
vec3 halfVector = normalize(lightVector + eyeVector); // L + V / |L + V|
out vec4 fColor; // Output Color
// Specular Functions
vec3 D(vec3 h) // Normal Distribution Function - GGX/Trowbridge-Reitz
{
float alpha = roughness * roughness;
float alpha2 = alpha * alpha;
float NoH = dot(fNormal, h);
float finalTerm = ((NoH * NoH) * (alpha2 - 1.0) + 1.0);
return vec3(alpha2 / (PI * (finalTerm * finalTerm)));
}
vec3 Gsub(vec3 v) // Sub Function of G
{
float k = ((roughness + 1.0) * (roughness + 1.0)) / 8;
return vec3(dot(fNormal, v) / ((dot(fNormal, v)) * (1.0 - k) + k));
}
vec3 G(vec3 l, vec3 v, vec3 h) // Geometric Attenuation Term - Schlick Modified (k = a/2)
{
return Gsub(l) * Gsub(v);
}
vec3 F(vec3 v, vec3 h) // Fresnel - Schlick Modified (Spherical Gaussian Approximation)
{
vec3 f0 = specularColor; // right?
return f0 + (1.0 - f0) * pow(2, (-5.55473 * (dot(v, h)) - 6.98316) * (dot(v, h)));
}
vec3 specular()
{
return (D(halfVector) * F(eyeVector, halfVector) * G(lightVector, eyeVector, halfVector)) / 4 * ((dot(fNormal, lightVector)) * (dot(fNormal, eyeVector)));
}
vec3 diffuse()
{
float NoL = dot(fNormal, lightVector);
vec3 result = vec3(reflectance / PI);
return result * NoL;
}
void main()
{
fNormal = normalize(inputNormal);
fColor = vec4(diffuse() + specular(), 1.0);
//fColor = vec4(D(halfVector), 1.0);
}
До сих пор мне удавалось исправлять некоторые вещи, и теперь я получаю лучший результат.
Однако теперь кажется очевидным, что подсветка слишком велика; это происходит от нормальной функции распределения (зеркальная D).1 ответ:
Ваша кодировка GGX / Trowbridge-Reitz неверна:
Vec3 NxH = fNormal * h;
Звезда * означает термин за термином продукт, где вы хотите точечный продукт
Также
Float alphaTerm = (alpha * alpha-1.0) + 1.0;
Не является правильным, так как формула умножает
n.m
на(alpha * alpha - 1.0)
перед добавлением 1.0. Ваша формула равна Альфа*Альфа!Попробуйте:
// Specular vec3 D(vec3 h) // Normal Distribution Function - GGX/Trowbridge-Reitz { float alpha = roughness * roughness; float NxH = dot(fNormal,h); float alpha2 = alpha*alpha; float t = ((NxH * NxH) * (alpha2 - 1.0) + 1.0); return alpha2 / (PI * t * t); }
Во многих других местах вы используете
*
вместоdot
. Вам нужно исправьте все это. Кроме того, проверьте свои формулы, многие из них кажутся неправильными.