Normal map lighting bug in bottom right quadrant
- by Ryan Capote
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
If I use flat normals (z normal = 1.0), it seems to be working fine:
normals for the tile sheet:
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;
}