Normal map lighting bug in bottom right quadrant

Posted by Ryan Capote on Game Development See other posts from Game Development or by Ryan Capote
Published on 2014-06-02T18:51:27Z Indexed on 2014/06/02 21:49 UTC
Read the original article Hit count: 282

Filed under:
|
|
|

I am currently working on getting normal maps working in my project, and have run into a problem with lighting. As you can see, the normals in the bottom right quadrant of the lighting isn't calculating the correct direction to the light or something.

Best seen by the red light

lighting bug

If I use flat normals (z normal = 1.0), it seems to be working fine:

flat normals

normals for the tile sheet:

normals

Shader:

#version 330

uniform sampler2D uDiffuseTexture;
uniform sampler2D uNormalsTexture;
uniform sampler2D uSpecularTexture;
uniform sampler2D uEmissiveTexture;
uniform sampler2D uWorldNormals;
uniform sampler2D uShadowMap;

uniform vec4 uLightColor;
uniform float uConstAtten;
uniform float uLinearAtten;
uniform float uQuadradicAtten;
uniform float uColorIntensity;

in vec2 TexCoords;
in vec2 GeomSize;

out vec4 FragColor; 

float sample(vec2 coord, float r) {
    return step(r, texture2D(uShadowMap, coord).r);
}

float occluded() {
   float PI = 3.14;

   vec2 normalized = TexCoords.st * 2.0 - 1.0;
   float theta = atan(normalized.y, normalized.x);
   float r = length(normalized);
   float coord = (theta + PI) / (2.0 * PI);

   vec2 tc = vec2(coord, 0.0);
   float center = sample(tc, r);

   float sum = 0.0;

   float blur = (1.0 / GeomSize.x) * smoothstep(0.0, 1.0, r);

   sum += sample(vec2(tc.x - 4.0*blur, tc.y), r) * 0.05;
   sum += sample(vec2(tc.x - 3.0*blur, tc.y), r) * 0.09;
   sum += sample(vec2(tc.x - 2.0*blur, tc.y), r) * 0.12;
   sum += sample(vec2(tc.x - 1.0*blur, tc.y), r) * 0.15;

   sum += center * 0.16;

   sum += sample(vec2(tc.x + 1.0*blur, tc.y), r) * 0.15;
   sum += sample(vec2(tc.x + 2.0*blur, tc.y), r) * 0.12;
   sum += sample(vec2(tc.x + 3.0*blur, tc.y), r) * 0.09;
   sum += sample(vec2(tc.x + 4.0*blur, tc.y), r) * 0.05;

   return sum * smoothstep(1.0, 0.0, r); 
}

float calcAttenuation(float distance) {
    float linearAtten = uLinearAtten * distance;
    float quadAtten = uQuadradicAtten * distance * distance;

    float attenuation = 1.0 / (uConstAtten + linearAtten + quadAtten);

    return attenuation;
}

vec3 calcFragPosition(void) {
    return vec3(TexCoords*GeomSize, 0.0);
}

vec3 calcLightPosition(void) {
    return vec3(GeomSize/2.0, 0.0);
}

float calcDistance(vec3 fragPos, vec3 lightPos) {
    return length(fragPos - lightPos);
}

vec3 calcLightDirection(vec3 fragPos, vec3 lightPos) {
    return normalize(lightPos - fragPos);
}

vec4 calcFinalLight(vec2 worldUV, vec3 lightDir, float attenuation) {
    float diffuseFactor = dot(normalize(texture2D(uNormalsTexture, worldUV).rgb), lightDir);

    vec4 diffuse = vec4(0.0);
    vec4 lightColor = uLightColor * uColorIntensity;

    if(diffuseFactor > 0.0) {
        diffuse = vec4(texture2D(uDiffuseTexture, worldUV.xy).rgb, 1.0);
        diffuse *= diffuseFactor;
        lightColor *= diffuseFactor;
    } else {
        discard;
    }

    vec4 final = (diffuse + lightColor);

    if(texture2D(uWorldNormals, worldUV).g > 0.0) {
         return final * attenuation; 
    } else {
        return final * occluded();
    }
}

void main(void) {
    vec3 fragPosition = calcFragPosition();
    vec3 lightPosition = calcLightPosition();

    float distance = calcDistance(fragPosition, lightPosition);    
    float attenuation = calcAttenuation(distance);

    vec2 worldPos = gl_FragCoord.xy / vec2(1024, 768);
    vec3 lightDir = calcLightDirection(fragPosition, lightPosition); 

    lightDir = (lightDir*0.5)+0.5;

    float atten = calcAttenuation(distance);
    vec4 emissive = texture2D(uEmissiveTexture, worldPos); 
    FragColor = calcFinalLight(worldPos, lightDir, atten) + emissive;
}

© Game Development or respective owner

Related posts about opengl

Related posts about glsl