I'm trying to render the Sponza scene using the Cook-Torrance BRDF Model Plugged with the GGX Normal Distribution, Gemoetry Schlick and fresnel Schlick approximation and a punctual point light. When rendered I get these artifacts

final scene

I don't know why these fragments in the yellow boxes are shadowed although everything in the Gbuffer looks normal. Here is the positions map


diffuse map

enter image description here

normal map

enter image description here

roughness map

enter image description here

metallness map

enter image description here

and finally the Ambient Occlusion

enter image description here

and here the fragment shader used to render the scene

#version 440 core

const float PI = 3.14159265359f;

struct PointLight 
    vec3 light_position;
    vec3 light_intensity;
    float radius; 

uniform sampler2D position_map;
uniform sampler2D normal_map;
uniform sampler2D diffuse_map;
uniform sampler2D roughness_map;
uniform sampler2D metalness_map;
uniform sampler2D ao_map;
uniform PointLight pointlight; 

in vec2 o_uv; 

out vec4 final_color; 

// NDF
float GGX_Distribution(float roughness, vec3 normal, vec3 halfway)
    float numerator = pow(roughness, 4.0f); 
    float NdotH = max(dot(normal, halfway), 0.0f); 
    float denominator = PI * pow((NdotH * NdotH * (numerator - 1) + 1), 2.0f);
    return numerator / denominator;

// Schlick-GGX
float SchlickGGX(vec3 normal, vec3 dir, float roughness)
    float k_numerator = roughness + 1; 
    float k = (k_numerator * k_numerator) / 8.0f; 
    float numerator = max(dot(normal, dir), 0.0f); 
    float denominator = numerator * (1.0f - k) + k;

    return numerator / denominator; 

float GeometrySchlickGGX(vec3 normal, vec3 lightdir, vec3 viewdir, float roughness)
    return SchlickGGX(normal, lightdir, roughness) * SchlickGGX(normal, viewdir, roughness); 

vec3 F_Schlick(vec3 F0, vec3 lightdir, vec3 halfway)
    float LdotH = max(dot(lightdir, halfway), 0.0f); 
    return F0 + (1.0f - F0) * pow((1.0f - LdotH), 5.0f); 
vec3 PointLightIllum(PointLight pointlight, vec3 fragPos, float roughness,
                            vec3 diffuse, float metalness, vec3 normal)
    vec3 lightDir = normalize(pointlight.light_position - fragPos);

    vec3 viewDir = normalize(-fragPos);
    vec3 halfway = normalize(lightDir + viewDir);
    float d = length(pointlight.light_position - fragPos); 
    float attenuation = 1.0f / ((d * d) + 0.001f);

    float NdotL = max(dot(lightDir, normal), 0.0f); 
    float NdotV = max(dot(viewDir, normal), 0.0f); 

    vec3 F0 = vec3(0.04);
    F0 = mix(F0, diffuse, metalness);

    // Specular Reflections
    vec3 F = F_Schlick(F0, lightDir, halfway);

    // Shadowing and masking
    float G = GeometrySchlickGGX(normal, lightDir, viewDir, roughness);
    float D = GGX_Distribution(roughness, normal, halfway);

    vec3 numerator = F * G * D; 
    float denominator = 4.0f * NdotV * NdotL + 0.0001f;
    vec3 BRDF = numerator / denominator; 

    vec3 spec = BRDF * pointlight.light_intensity * attenuation * NdotL;
    vec3 diff = (diffuse / PI) * pointlight.light_intensity * attenuation * NdotL * (1.0f - metalness); 
    diff *= vec3(1.0f) - F;

    vec3 Lo = spec + diff; 

    return Lo;

void main()
    vec3 fragPos = texture(position_map, o_uv).rgb;
    vec3 normal = normalize(texture(normal_map, o_uv).rgb);
    vec3 diffuse = texture(diffuse_map, o_uv).rgb;
    float roughness = texture(roughness_map, o_uv).r; 
    float metalness = texture(metalness_map, o_uv).r; 
    float ao = texture(ao_map, o_uv).r;

    // Ambient occlusion
    float ambient_intensity = 0.2f; 
    vec3 ambient = diffuse * ambient_intensity * ao;

    vec3 direct = PointLightIllum(pointlight, fragPos, roughness, diffuse, metalness, normal);
    vec3 indirect = ambient; 

    final_color = vec4(indirect + direct, 1.0f);

the vertex shader is a simple shader where i just render a quad with the size of screen and use its UVs to sample the textures. Could Someone tell why i'm having this artifact and how to resolve it?

  • $\begingroup$ Is your camera at the origin? " vec3 viewDir = normalize(-fragPos);" $\endgroup$
    – pmw1234
    Commented Jul 11, 2022 at 14:26
  • $\begingroup$ yes i have a fixed camera centered at the origin $\endgroup$ Commented Jul 11, 2022 at 14:33

1 Answer 1


Well I'm embarrassed to say that but turns out the problem was with the format of the normals render target instead of making it GL_RGB32F I accidentally made it GL_RGB causing the normals to be clipped to range 0 -> 1 instead of -1 -> 1 causing some fragments to be shadowed due to incorrect lighting calculations.

  • 1
    $\begingroup$ Btw, you can use R10G10B10A2 format for normals to use less space than RGB32F (4 vs 12 bytes per pixel) while having more precision than with RGB8 format (10 vs 8 bits). You'll still have to manually remap normals from [-1,1] to [0,1] and back, though. $\endgroup$
    – lisyarus
    Commented Jul 12, 2022 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.