Normal mapping: tangents vectors clearly incorrect

Started by
4 comments, last by dpadam450 5 years, 7 months ago

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):

RenderIssue.png.2778d7261c04032663c82e4e5cba1aa0.png

Normal map itself:

normals.png.ac287df908e524b97c7c8099deca890c.png

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?

Advertisement

Bump?

To be 100% honest I have no idea what you are trying to show us in that very low res screenshot nor do I have any idea which data you mapped to the colors and I suspect that I'm not alone.

For example I would expect to see at most 2 color channel involved in the debug view of texture coordinates but you seem to have the 3 channels involved, including solid pink spots that suggest that you sample the same position everywhere but your normal render doesn't say the same thing?

Also I'm familiar with normal / binormal / tangent but I have no idea what is a "uvec" or "vvec" for you?

On 9/14/2018 at 5:20 PM, ChuckNovice said:

To be 100% honest I have no idea what you are trying to show us in that very low res screenshot nor do I have any idea which data you mapped to the colors and I suspect that I'm not alone.

For example I would expect to see at most 2 color channel involved in the debug view of texture coordinates but you seem to have the 3 channels involved, including solid pink spots that suggest that you sample the same position everywhere but your normal render doesn't say the same thing?

 Also I'm familiar with normal / binormal / tangent but I have no idea what is a "uvec" or "vvec" for you?

The commented-out last parts of the fragment shader show how the data is mapped to colors. So for example the texture coordinates have all blue set to full.

uvec and vvec are the tangent and bitangent.

Have you tried the full pipline with a single triangle or quad with a texture on it? Rotate the uv's 90 degrees and see if it still works...

You have to step by step debug  this. There are lots of things that could go wrong. Start with something very simple. As stated, we don't know what we are looking at. Get a simple normal map and simple geometry and figure it out.  I've had to do the same types of things in my project.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

This topic is closed to new replies.

Advertisement