Hello.
I'm trying to implement normal mapping. I've been following this: http://ogldev.atspace.co.uk/www/tutorial26/tutorial26.html
The problem is that my tangent vectors appear rather obviously wrong. But only one of them, never both. Here's my code for calculating the tangents:
this.makeTriangle = function(a, b, c)
{
var edge1 = VectorSub(b.pos, a.pos);
var edge2 = VectorSub(c.pos, a.pos);
var deltaU1 = b.texCoords[0] - a.texCoords[0];
var deltaV1 = b.texCoords[1] - a.texCoords[1];
var deltaU2 = c.texCoords[0] - a.texCoords[0];
var deltaV2 = c.texCoords[1] - a.texCoords[1];
var f = 1.0 / (deltaU1 * deltaV2 - deltaU2 * deltaV1);
var vvec = VectorNormal([
f * (deltaV2 * edge1[0] - deltaV1 * edge2[0]),
f * (deltaV2 * edge1[1] - deltaV1 * edge2[1]),
f * (deltaV2 * edge1[2] - deltaV1 * edge2[2]),
0.0
]);
var uvec = VectorNormal([
f * (-deltaU2 * edge1[0] - deltaU1 * edge2[0]),
f * (-deltaU2 * edge1[1] - deltaU1 * edge2[1]),
f * (-deltaU2 * edge1[2] - deltaU1 * edge2[2]),
0.0
]);
if (VectorDot(VectorCross(a.normal, uvec), vvec) < 0.0)
{
uvec = VectorScale(uvec, -1.0);
};
/*
console.log("Normal: ");
console.log(a.normal);
console.log("UVec: ");
console.log(uvec);
console.log("VVec: ");
console.log(vvec);
*/
this.emitVertex(a, uvec, vvec);
this.emitVertex(b, uvec, vvec);
this.emitVertex(c, uvec, vvec);
};
My vertex shader:
precision mediump float;
uniform mat4 matProj;
uniform mat4 matView;
uniform mat4 matModel;
in vec4 attrVertex;
in vec2 attrTexCoords;
in vec3 attrNormal;
in vec3 attrUVec;
in vec3 attrVVec;
out vec2 fTexCoords;
out vec4 fNormalCamera;
out vec4 fWorldPos;
out vec4 fWorldNormal;
out vec4 fWorldUVec;
out vec4 fWorldVVec;
void main()
{
fTexCoords = attrTexCoords;
fNormalCamera = matView * matModel * vec4(attrNormal, 0.0);
vec3 uvec = attrUVec;
vec3 vvec = attrVVec;
fWorldPos = matModel * attrVertex;
fWorldNormal = matModel * vec4(attrNormal, 0.0);
fWorldUVec = matModel * vec4(uvec, 0.0);
fWorldVVec = matModel * vec4(vvec, 0.0);
gl_Position = matProj * matView * matModel * attrVertex;
}
And finally the fragment shader:
precision mediump float;
uniform sampler2D texImage;
uniform sampler2D texNormal;
uniform float sunFactor;
uniform mat4 matView;
in vec2 fTexCoords;
in vec4 fNormalCamera;
in vec4 fWorldPos;
in vec4 fWorldNormal;
in vec4 fWorldUVec;
in vec4 fWorldVVec;
out vec4 outColor;
vec4 calcPointLight(in vec4 normal, in vec4 source, in vec4 color, in float intensity)
{
vec4 lightVec = source - fWorldPos;
float sqdist = dot(lightVec, lightVec);
vec4 lightDir = normalize(lightVec);
return color * dot(normal, lightDir) * (1.0 / sqdist) * intensity;
}
vec4 calcLights(vec4 pNormal)
{
vec4 result = vec4(0.0, 0.0, 0.0, 0.0);
${CALC_LIGHTS}
return result;
}
void main()
{
vec4 surfNormal = vec4(cross(vec3(fWorldUVec), vec3(fWorldVVec)), 0.0);
vec2 bumpCoords = fTexCoords;
vec4 bumpNormal = texture(texNormal, bumpCoords);
bumpNormal = (2.0 * bumpNormal - vec4(1.0, 1.0, 1.0, 0.0)) * vec4(1.0, 1.0, 1.0, 1.0);
bumpNormal.w = 0.0;
mat4 bumpMat = mat4(fWorldUVec, fWorldVVec, fWorldNormal, vec4(0.0, 0.0, 0.0, 1.0));
vec4 realNormal = normalize(bumpMat * bumpNormal);
vec4 realCameraNormal = matView * realNormal;
float intensitySun = clamp(dot(normalize(realCameraNormal.xyz), normalize(vec3(0.0, 0.0, 1.0))), 0.0, 1.0) * sunFactor;
float intensity = clamp(intensitySun + 0.2, 0.0, 1.0);
outColor = texture(texImage, fTexCoords) * (vec4(intensity, intensity, intensity, 1.0) + calcLights(realNormal));
//outColor = texture(texNormal, fTexCoords);
//outColor = 0.5 * (fWorldUVec + vec4(1.0, 1.0, 1.0, 0.0));
//outColor = vec4(fTexCoords, 1.0, 1.0);
outColor.w = 1.0;
}
Here is the result of rendering an object, showing its normal render, the uvec, vvec, and texture coordinates (each commented out in the fragment shader code):
Normal map itself:
The uvec, as far as I can tell, should not be all over the place like it is; either this, or some other mistake, causes the normal vectors to be all wrong, so you can see on the normal render that for example there is a random dent on the left side which should not be there. As far as I can tell, my code follows the math from that tutorial. I use right-handed corodinates.
So what could be wrong?