I am trying to implement PBR renderer. My specular highlight has desaturated color (especially in grazing angles) and escapes my light volume bounding sphere. Why is this happening?
The function I use to calculate GGX specular:
vec3 shadingSpecularGGX(vec3 N, vec3 V, vec3 L, float roughness, vec3 F0)
{
vec3 H = normalize(V + L);
float dotLH = max(dot(L, H), 0.0);
float dotNH = max(dot(N, H), 0.0);
float dotNL = max(dot(N, L), 0.0);
float dotNV = max(dot(N, V), 0.0);
float alpha = roughness * roughness;
// D (GGX normal distribution)
float alphaSqr = alpha * alpha;
float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
float D = alphaSqr / (denom * denom);
// no pi because BRDF -> lighting
// F (Fresnel term)
float F_a = 1.0;
float F_b = pow(1.0 - dotLH, 5); // manually?
vec3 F = mix(vec3(F_b), vec3(F_a), F0);
// G (remapped hotness, see Unreal Shading)
float k = (alpha + 2 * roughness + 1) / 8.0;
float G = dotNL / (mix(dotNL, 1, k) * mix(dotNV, 1, k));
return D * F * G / 4.0;
}
And then in I merge it together with diffuse lambert term:
float lambert = max(0.0, dot(lightDir, normal));
vec3 diffuse = albedo * (1 - metallic);
vec3 specular = mix(vec3(0.04), albedo, metallic) * light.color;
float distance = length(light.position - worldPos);
float attenuation = clamp(1.0 / (distance * distance * light.atten.quadratic + distance * light.atten.linear + light.atten.constant), 0.0, 1.0);
gl_FragColor.rgb = (diffuse * lambert * light.color * light.intensity) + shadingSpecularGGX(normal, viewDir, lightDir, roughness, specular) * light.intensity;
gl_FragColor.rgb *= attenuation;
gl_FragColor.a = 1.0;
The specular highlight has colors when viewing from top, but as the camera moves closer to the ground, the colors start to wash out.
Is this correct behavior? Because when looking at photos of wet asphalt, the colors of reflections seem to be preserved.
I managed to get the colored reflections, by changing the F0
color to light.color
vec3 specular = mix(light.color, albedo * light.color, metallic);
but I've read, that the F0 value should be for non-metals about 0.04 and my specular reflection escapes my bounding sphere.