- 22, Oct 2024
- #1
Я все еще работаю над уравнениями BRDF. Теоретически все уравнения верны, но блики очень резкие. Я не уверен, является ли это результатом того, что я не использую освещение на основе изображений (сейчас я использую только карту окружения с функцией LOD). Я использую материалы отсюда: http://freepbr.com/c/base-materials/ - Я использую Specular/Gloss, но для преобразования материалов используется фрагментный шейдер.
Material Frag Shader (Отрывок) (В частности, шейдер Metalness-Roughness):
vec3 LightCalc(in vec3 Albedo, in vec4 WorldPos, in vec4 Specular, in vec3 Normal, in samplerCube envMap, in vec3 lightPos, in float lightAtten, in vec4 lightColor) { vec3 lightDir = WorldPos.xyz - lightPos; vec3 eyeDir = normalize(eyePos - WorldPos.xyz); vec3 eyeReflect = reflect(-eyeDir, Normal); float Distance = length(lightDir); lightDir = -normalize(lightDir); float Attenuation = clamp(1 - pow(Distance / lightAtten, 4), 0, 1); Attenuation = Attenuation*Attenuation/(Distance*Distance+1); vec3 AmbientColor = vec3(Albedo.xyz)*0.01; float Roughness = 1-Specular.a; float alpha = Roughness * Roughness; vec3 H = normalize(eyeDir + lightDir); float NL = clamp(dot(Normal, lightDir), 0, 1); float NH = clamp(dot(Normal, H), 0, 1); float NV = clamp(dot(Normal, eyeDir), 0, 1); float LH = clamp(dot(lightDir, H), 0, 1); float VH = clamp(dot(eyeDir, H), 0, 1); float lod = compute_lod(alpha, 1, NH); vec3 reflectDir = normalize(eyeReflect); vec3 reflectPix = textureLod(envMap, reflectDir, lod).rgb; float D = Light_D(alpha, NH); vec3 F = Light_F(clamp(Specular.rgb, 0.018, 0.95), LH); float Vis = Light_V(NL, NV, alpha); vec3 Spec = (D * F * Vis) * reflectPix; vec3 Diffuse = Light_Diffuse(NV, NL, Normal, alpha, Albedo.rgb, eyeDir, lightDir); vec3 lightModifier = lightColor.xyz*lightColor.w*Attenuation; return NL*(Spec + max(Diffuse, AmbientColor))*lightModifier; }
Функции освещения:
vec3 Light_F(in vec3 Specular, in float VH) {
// Fresnel Schlick
return Specular + (1-Specular) * pow(1-VH, 5.0f);
}
float Light_D(in float alpha, in float NH) {
// GGX
float alphaSqr = alpha*alpha;
float denom = NH * NH * (alphaSqr - 1) + 1;
return alphaSqr / (pi * denom * denom);
}
float Light_V( in float NL, in float NV, in float alpha ) {
// Frostbite's GGX
float Lambda_GGXV = NL * sqrt (( - NV * alpha + NV ) * NV + alpha );
float Lambda_GGXL = NV * sqrt (( - NL * alpha + NL ) * NL + alpha );
return 0.5f / ( Lambda_GGXV + Lambda_GGXL );
}
vec3 Light_Diffuse(in float NV, in float NL, in vec3 Normal, in float alpha, in vec3 Albedo, in vec3 eyeDir, in vec3 lightDir) {
// Oren-Nayar
float gamma = dot( eyeDir - Normal * NV, lightDir - Normal * NL);
float A = 1.0f - 0.5f * (alpha / (alpha + 0.57f));
float B = 0.45f * (alpha / (alpha + 0.09));
float diffAlpha = max( acos( NV ), acos( NL ) );
float diffBeta = min( acos( NV ), acos( NL ) );
float C = sin(diffAlpha) * tan(diffBeta);
return Albedo * (A + B * max( 0.0f, gamma ) * C) / pi;
}
Финальная функция освещения в отложенном рендерере:
float Roughness = baseSpecular.a;
if (uTexRoughEnabled == 1)
Roughness = texture(texRoughness, UV).r;
float Metalness = texture(texSpecular, UV).r;
// 1 - Roughness becomes Glossiness
specular = vec4(mix(vec3(0.4), albedo.rgb, Metalness), 1-Roughness);
albedo = vec4(mix(albedo.rgb, vec3(0), Metalness), 1-Roughness);
Не стесняйтесь указывать на любые ошибки, которые я допустил, даже если они не имеют отношения к проблеме. Я протестировал материалы в Unreal, и они выглядели правильно. Я сомневаюсь, что это происходит исключительно из-за отсутствия освещения на основе изображения. Я также сомневаюсь, что это проблема с использованием точечного освещения. Кроме того, если я сильно уменьшу шероховатость, она станет слишком темной, а высокая шероховатость не будет проблемой.
#glsl #brdf #specular #pbr