View Full Version : Lighting errors with normal mapping

02-03-2015, 12:02 AM
I am having some lighting errors trying to implement normal mapping. I am using a spotlight, with its position at the camera, and its direction in the same direction the camera is facing. Everything looks fine if I am using the vertex attribute normals (NormalMatrix*attribVertexNormals).

My normal matrix is the upper 3x3 model view matrix. Here it is with the vertex normals (spotlight aiming on corner of cube):
And here it is when trying to normal map:

My vertex shader:

void main()
vec3 n = normalize(uNormalMatrix * vec4(VertexNormal,1.0)).xyz; //normal
vec3 t = normalize(uNormalMatrix * vec4(VertexTangent,1.0)).xyz; //tangent
vec3 b = normalize(cross(n, t)); //bitangent
if (dot(cross(n, t), b) < 0.0f) // check handedness
t = t * -1.0f;

fTBN = mat3(t.x,b.x,n.x, // my tbn matrix, pass to fragment shader and multiply lightdir and eyedir for normal mapping
fNormal = n; // use this in fragment shader if not normal mapping, otherwise use normal map
fTexcoord = VertexTexcoord;
fPosition = (uViewMatrix*uModelMatrix*vec4(VertexPosition,1.0) ).xyz;
gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * vec4(VertexPosition, 1);
Fragment shader:

vec3 spotLight(vec3 diffT, vec3 specT, vec3 ddnT)
float spotCutoff = 20;
float exponent = 1;

vec3 LightDir = normalize(fTBN*(vec3(uLightPosition) - fPosition)); // normal mapping
vec3 EyeDir = fTBN*normalize(-fPosition); // normal mapping

//vec3 LightDir = normalize(vec3(uLightPosition) - fPosition); // not normal mapping
//vec3 EyeDir = normalize(-fPosition); // not normal mapping

vec3 spotLightDir = normalize(fTBN*uLightDir); // normal mapping
//vec3 spotLightDir = normalize(uLightDir); // not normal mapping

float angle = acos(dot(-LightDir,spotLightDir));
float cutOff = radians(clamp(spotCutoff,0.0,90.0));

if(angle < cutOff)
float spotFactor = pow(dot(-LightDir,spotLightDir),exponent);
vec3 h = normalize(EyeDir+LightDir);
return uLightIntensity*uKa +
uKd*diffT*max(dot(LightDir, ddnT), 0.0) +
return uLightIntensity*uKa;
void main() {

vec2 parallaxCoords = fTexcoord; // parallax occlusion mapping not yet implemented

vec3 diffC = texture2D(diff, parallaxCoords.st * uTileAmount.x).rgb;
vec3 specC = texture2D(spec, parallaxCoords.st * uTileAmount.y).rgb;

vec3 ddnC = 2.0*texture2D(ddn, parallaxCoords.st * uTileAmount.z).rgb - 1.0; // normal mapping
//vec3 ddnC = normalize(fNormal); // not normal mapping

fragColour = vec4(spotLight(diffC,specC,ddnC),1.0);


I have a flat normal map (0.5,0.5,1.0) for testing purposes when normal maps are on.

02-03-2015, 04:16 AM
is fTBN orthogonal, i.e. are n and t perpendicular?

Also, you should probably be transforming VertexTangent by uViewMatrix*uModelMatrix rather than by uNormalMatrix. The whole point of using a normal matrix which is the inverse-transpose of the model-view matrix is to ensure that normals are perpendicular to tangents even when the model-view matrix isn't orthogonal. Of course, this won't actually matter if your model-view matrix is actually orthogonal (comprised from translation, rotation and uniform scaling, with no shear or non-uniform scaling).

Personally, I'd perform the spot cut-off calculation in eye space rather than surface (TBN) space.

02-03-2015, 11:54 PM
When you multiply a normal vector by a matrix, is should have 0 in the 4th component, not 1. If you happen to have something in the last column of your matrix, you are transforming points, not normal.


vec3 n = normalize(uNormalMatrix * vec4(VertexNormal,1.0)).xyz; //normal
vec3 t = normalize(uNormalMatrix * vec4(VertexTangent,1.0)).xyz; //tangent

should be

vec3 n = normalize(uNormalMatrix * vec4(VertexNormal,0.0)).xyz; //normal
vec3 t = normalize(uNormalMatrix * vec4(VertexTangent,0.0)).xyz; //tangent

Also, I agree with what GClements is saying

02-04-2015, 06:41 AM
Thanks guys, it works now. I used the gram schimdt process and made fTBN orthogonal and I fixed my matrix vector multiplication.