Problems with tangent to world space conversion

Started by
2 comments, last by Buckeye 9 years, 1 month ago

I added normal mapping to my project a while back, which seemed to work as intended so I didn't think much about it until now that I tried to also add specular mapping. This did not look right at all and after some debugging it seems that my normals (sampled from a normal map) don't get converted into world space properly after all.

So here is how I'm reading the normals:


float3x3 matIT = transpose(float3x3(normalize(IN.tangent), normalize(IN.binormal), normalize(IN.normal));
float3  normal = NormalMap.Sample(DSampler, IN.texcoord).xyz * 2 - 1; // Convert to -1 .. +1 range
normal = normalize(normal.x * matIT[0] + normal.y * matIT[1] + normal.z * matIT[2]); // Bring into world space

The IN.normal, IN.tangent and IN.binormal come from the per-vertex input data and are multiplied by the rendered mesh's world matrix prior to being sent to the pixel shader (where the above calculations occur).

The odd thing is that this does yield properly looking normal mapping results, but when I try to use these normals for specular highlights it is off.

Rendering the output normal vector of a spinning cube further suggests that for example the vertices facing upwards (after rotation by mutation of its world matrix) will have the correct, upwards facing normal direction for 4 faces but not all 6 as I can only imagine it should if this was working properly.

The fact that the cube normals do indeed change when rotating (albeit not always correctly) suggests that it shouldn't be a mere oversight of the above actually transforming the normal into object space instead of world space either.

It is times like these I regret I didn't take some extra math courses when I had the chance...

Any help or pointers would be greatly appreciated. smile.png

Advertisement

It seems you have 4 or 5 questions. You may want to take them one at a time, as solving one problem may fix others.

Also, the words you're using to describe the problem(s) are confusing.


Rendering the output normal vector of a spinning cube further suggests that for example the vertices facing upwards (after rotation by mutation of its world matrix) will have the correct, upwards facing normal direction for 4 faces but not all 6 as I can only imagine it should if this was working properly.

Can you clarify what "mutation of a matrix" means technically?

Also, it's confusing as you mention "THE" output normal vector for a cube. Do you really mean the output normal for each vertex (presumably 24 or them)? Also, one would normally expect a cube to have 6 face normals, facing +X, -X, +Y, -Y, +Z and -Z. However, you mention "upward facing normal direction for 4 faces.." Upward implies pointing in the direction of the world up direction. Are you using the word "upward" when you really mean "outward" (i.e., perpendicular to the face)?

Some other notes:

Because you're calculating the vertex normal/tangent/binormal in the vertex shader, the pixel shader gets as input the linearly interpolated normal/tangent/binormal vectors across the face. Is that what you want?

Without any further information on your program, WRT to the specular highlights: your code is incorrect, the data you're using to calculate the specular contribution is incorrect, or both. wink.png

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

You may be right, I just threw that post together quickly before making lunch so it may not have the best wording.

Can you clarify what "mutation of a matrix" means technically?

I simply meant that the rotation is achieved by altering the rotation part of the mesh's world matrix. This might be obvious but I typed it out in the hopes of avoiding misinterpretations not the other way around. wink.png

Also, it's confusing as you mention "THE" output normal vector for a cube.

Let's rephrase it as vectors then.

I was refering to the fact that all normals (from the normal map) should on the whole be affected by the rotation such that they would align with the cube's orientation.

So that rotating it 90 degrees around the X axis would cause its front face's normals to go from facing the negative Z axis to the positive Y axis instead (generally speaking since the normal map isn't a solid blue (full Z normal with no other directional influence), but you get the point).

Edit: here I'm referring to the normals transformed into world space.

Are you using the word "upward" when you really mean "outward" (i.e., perpendicular to the face)?

Ah yes, I meant that the world space normal would be expected to be facing "upwards" (along the positive Y axis) for the top face of the cube.

The 4 faces meant that when rotating the cube, its final world normal tended to point in this fashion for 4 of the 6 faces when that face was the top one after rotation. I think the back face had a 0 normal (which doesn't make much sense) while one of the side faces when rotated upwards tended towards facing negative X.

This is all just based on visual observation when having the pixel shader return the world normal as a rgb colour by the way.

But yes, in conclusion I guess that the normals weren't facing outward as intended for these faces in that particular rotation. They did however look sensible with other (or no) world matrix rotation.


Because you're calculating the vertex normal/tangent/binormal in the vertex shader, the pixel shader gets as input the linearly interpolated normal/tangent/binormal vectors across the face. Is that what you want?

They're essentially just passed through from the vertex data of the mesh. This was done because I figured I'd rather pay for some more memory usage than to have to recalculate vectors that will never change on each render in the shader.


Without any further information on your program, WRT to the specular highlights: your code is incorrect, the data you're using to calculate the specular contribution is incorrect, or both.

Well my code is the suspect as of now anyway, unless this data is incorrect with regards to normals / tangents / binormals for a cube?


	// Front face
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, -yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf);
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, -yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));

	// Back face
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, -yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, -yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));

	// Top face
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));

	// Bottom face
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, -yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, -1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, -yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, -1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, -yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, -1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, -yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(0.0f, -1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));

	// Left face
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, -yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(-xhs, -yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(-1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, -1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));

	// Right face
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, -yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, yhs, -zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));
	vert.SetMember<XMFLOAT3>("POSITION",	0, XMFLOAT3(xhs, -yhs, zhs));
	vert.SetMember<DWORD>	("COLOR",	0, 0xffffffff);
	vert.SetMember<XMFLOAT2>("TEXCOORD",	0, XMFLOAT2(1.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("NORMAL",	0, XMFLOAT3(1.0f, 0.0f, 0.0f));
	vert.SetMember<XMFLOAT3>("TANGENT",	0, XMFLOAT3(0.0f, 0.0f, 1.0f));
	vert.SetMember<XMFLOAT3>("BINORMAL",	0, XMFLOAT3(0.0f, 1.0f, 0.0f));
	vert.CopyData(vbuf + (vertOffset += vertSize));

    // Index buffer into the vertices above
    DWORD ibuf[] = {
        /* Front face */
        0, 1, 2, 
        0, 2, 3, 
        
        /* Back face */
        4, 5, 6, 
        4, 6, 7, 
        
        /* Top face */
        8, 9, 10, 
        8, 10, 11, 
        
        /* Bottom face */
        12, 13, 14, 
        12, 14, 15, 
        
        /* Left face */
        16, 17, 18, 
        16, 18, 19, 
        
        /* Right face */
        20, 21, 22, 
        20, 22, 23
    }; 

Basically my main question was whether my attempt at building a tangent to world space matrix was incorrect since that's what I'm guessing is wrong.

Unfortunately your responses confused things even more. However, to answer your specific question:


my main question was whether my attempt at building a tangent to world space matrix was incorrect

It appears to be of the correct form. It's common to build a matrix from the tangent, binormal and normal, and transform the result of the normal map sample using that matrix.

E.g.,


float3 B = cross(T, N);
column_major float3x3 matTBN = { T, B, N };
float3 mapNorm = normMap.Sample( samAnisotropic, Input.texCoords).rgb * 2.0 - 1.0;
mapNorm = mul ( mapNorm, matTBN );

N.B., just guessing from your vertex data, it appears your binormal may be in the wrong direction. I.e., T x N should = B, not -B.

You might try using normalize( -IN.tangent ) in your pixel shader, just to see what happens.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement