3

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.

Specular highlight is colored When viewed from grazing angle, the color is washed out

Is this correct behavior? Because when looking at photos of wet asphalt, the colors of reflections seem to be preserved.

enter image description here

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.

Matej Kormuth
  • 2,139
  • 3
  • 35
  • 52
  • Is there a reason why you multiply the specular term with the light intensity and not with the light color? – BDL Oct 23 '16 at 23:12
  • I multiply specular in this line: `vec3 specular = mix(vec3(0.04), albedo, metallic) * light.color; `. In case of metallic material, the albedo is metalic tint. The light.intesity is just float value specifying the intensity of light. However it was in these cases 1.0, so it shouldn't change anything – Matej Kormuth Oct 24 '16 at 06:33
  • @BDL Apperently multiplying with color in the line with `* light.intensity` solves my problem. If you want to write answer, I'll accept it. – Matej Kormuth Oct 25 '16 at 06:57

0 Answers0