Ok, so you are all excited about your new magic matrix. But if you haven’t realized yet, there is no way we can send face data to the graphics card. When we draw a face on the screen, we create vertices in a certain order to define a face, but there is no real face data.
So we have one last step. Splitting up the transformation matrices that we generated for each face, to each vertex that defines the face. Some of you who have generated vertex normals will be familiar with some techniques to do this. You can use any of these methods for the T, B vectors just as you do for the N vector. For the rest I will describe a basic technique here. You can always use more complex methods if the need calls for it.
A fairly simple and common method is to calculate the average of the vectors from all the faces that share that vertex. Example:
Taking the quad from Figure 1, lets say we have generated the Mwtmatrix for the two faces. Lets call the two Mwtmatrices M1wt for Face1,2,3 and M2wtfor Face2,4,3.
In order to calculate T, B, N for vertex 1, we do as follows
Here we divide by 2 because V2 is shared between 2 faces. Note: that the T, B, N vectors need to be re-normalized after taking their average.
Putting everything together in pseudo code
I will put everything I discussed in the previous two sections together into some pseudo code. I’ve kept the pseudo code as close to C/C++ as possible, so the majority will find it easy to understand.
Declarations:
Data types:
Vector3, Vector2, Vertex, Face, Matrix3, Mesh
Every vertex has two sub sections. P holds the position and T holds the texture coordinates at the vertex.
Every face consists of three integers that index the vertex list for the three vertices that define the face.
Matrix3 is a 3X3 matrix which contains 3 vectors, the Tangent, Binormal and Normal.
Mesh is made of a list of vertices and list of faces that index this vertex list. A mesh can also hold n matrices for the n vertices it has.
[] signifies an array
Vector3 =
{
Float X, Y, Z ;
}
Vector2 =
{
Float U, V ;
}
Vertex =
{
Vector3 P ;
Vector2 T ;
}
Normalize(Vector3) - Returns a normalized vector Cross(Vector3, Vector3) - Returns the cross product of two vectors
Standard vector arithmetic is assumed to work on a per component / sub component level.
Pseudo Code:
TangentSpaceFace
Description: The TangentSpaceFace function calculates the tangent space matrix for a Face F and returns a 3X3 tangent space matrix for that face.
Note: In order to keep things simple, I have not taken care of special cases where the difference between two vertices will result in the u component being 0.
TangentSpaceVertex Description: This function calculates the tangent space matrix for a vertex with index position VertexIndex based on the list of faces that index this vertex from FaceList. FaceMatrix is an array of tangent space matrices for the face list passed in.
Unfortunately I believe this is wrong aswell. Consider a simple case where E2-1.uv is 1,0 (so E2-1.xyz is already the tangent!), and E3-1.uv is an angled vector across the UV space.
http://www.terathon.com/code/tangent.html
http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.ph p
These 2 website have good explanations about tangent space.
Does any body know, if 2 vertex of a triangle have the same UV, then should I ignore that triangle, or ask art to change the UV? The determinant will become 0 in this case...
T = E2-1.xyz / E2-1.u
This formula does not seem correct. Wouldn't this just scale the edge?
I think the formula is supposed to be more like this(could be wrong though):
NE2-1 = Normalize(E2-1)
NE3-1 = Normalize(E3-1)
T = (NE2-1.xyz / E2-1.u) + (NE3-1.xyz / E3-1.u)
http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.ph
p
These 2 website have good explanations about tangent space.
Does any body know, if 2 vertex of a triangle have the same UV, then should I ignore that triangle, or ask art to change the UV? The determinant will become 0 in this case...