# Normal Mapping

## Recommended Posts

schupf    221
Hello, I have a little question about some HLSL VS code that performs tangent space normal mapping. This is the VS:
VS_OUTPUT VS(float4 Pos : POSITION, float2 Tex : TEXCOORD, float3 Normal : NORMAL, float3 Tangent : TANGENT  ) {
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Pos = mul(Pos, matWorldViewProj);	// transform Position

// compute the 3x3 tranform matrix to transform from world space to tangent space
float3x3 worldToTangentSpace;
worldToTangentSpace[0] = mul(Tangent, matWorld);                 // A
worldToTangentSpace[1] = mul(cross(Tangent, Normal), matWorld);  // B
worldToTangentSpace[2] = mul(Normal, matWorld);                  // C

Out.Tex = Tex;
float4 PosWorld = mul(Pos, matWorld);
Out.Light = mul(worldToTangentSpace, vecLightDir); 	// D
Out.View = mul(worldToTangentSpace, vecEye - PosWorld);
return Out;
}


These are my questions: 1. Normally (in DirectX) the tangent space frame at each vertex is oriented in this way: the tangent vector points to the "right" (the direction where the u-texcoords go), the normal vector points away from the polygon (the normal vector is perpendicular to the polygon) and the binormal vector points downwards (in the direction of the v-texcoords). So for example lets say we have a cube ([-1,1] on all axis), assembled from 8 vertices. The T,N,B vectors for the front,top,left vertex would be: T= (1,0,0),N=(0,0,-1),B=(0,-1,0). The second ingredient we need for normal mapping is a texture with normal vectors. the normal of the normal map are defined relative to the TBN frame. So if a vector with coordinates (1,0,0) is stored int he map he points to the right. A vector of (0,0,1) would points out of the texture. Are all my statements in this paragraph correct? Please correct me if I am wrong! 2. I don't understand line B in the code. I know that lines A through C build the world-to-tangent-space matrix. Line A basically sets the first row of the column to the world space tangent (aka tangent x-axis). Line C obviously sets the z-axis. Line B constructs the tangent space y-axis (the axis that points downwards). But why does the code use cross(Tangent, Normal)? DirectX uses a LH coordinate system, thus TxN would point UPWARDS (T points to the right, N out of the polygon). But shouldn't the tangent space y-axis point DOWNWARDS? Does this code assume a downward y-axis? 3. The author of the code uses worldToTangentSpace as the first parameter of function mul() to get a free transpose of the matrix, doesnt he? Because the TBN axis have to be placed in the COLUMNS of the matrix. Is this correct?

##### Share on other sites
ender_341    136
the cross product takes to 3D vectors and outputs a new vector that is perpendicular to both of them, so line B is taking the tangent and normal and crossing them to calculate the binormal at runtime so that it doesn't take up bandwidth between the CPU and GPU.

##### Share on other sites
JohnnyCode    1046

1. TBN matrix is designed to transform unit vectors (length= 1), so to speak it transforms only direction vectors to texture space (rotates them). You can not transform a position vector in object space to texture space with TBN. In texture space are defined the actual normals (xR,yG,zB) .

2. You are computing a binormal vector by doing cross operation on normal vector and tangent vector (you get a perpendicular vector to them two).

3. Tangent,binormal,normal should be in object space, and you move vectors from world space to object's space by object's world inverse matrix. You then can move this vector from object space to texture space by TBN matrix.

So in pixel shader you have light direction vector in texture space and can dot it with normal in texture.

##### Share on other sites
schupf    221
Uhm guys, did you even read my posting? None of you gave answers to my specific questions (I know what a TNB matrix and the cross product is...)

##### Share on other sites
Einstone    126
The result worldToTangentSpace in the code is a RH matrix. In vertex shader, it can be either LH or RH. This space matrix will be passed down to the pixel shader that's where you need to know whether the passed down matrix is LH or RH and whether the normal map used is LH or RH. Normal maps are commonly baked into RH space, so generating a RH space matrix in vertex shader would be prefered.

##### Share on other sites
JohnnyCode    1046
Quote:
 Original post by schupfDirectX uses a LH coordinate system, thus TxN would point UPWARDS (T points to the right, N out of the polygon). But shouldn't the tangent space y-axis point DOWNWARDS? Does this code assume a downward y-axis?

for this manner you need to compute "handedness" of the tangent and normal, I use 4float vectors for tangent, the fourth scalar is handedness for the tangent(1 or -1)(it multiplies binormal).

Quote:
 3. The author of the code uses worldToTangentSpace as the first parameter of function mul() to get a free transpose of the matrix, doesnt he? Because the TBN axis have to be placed in the COLUMNS of the matrix. Is this correct?

Yes, if you switch parameters of mul() function you get a transposed transformation.