Contents
Messing with Tangent Space
 
 
Printer-Friendly VersionPrinter-Friendly Version
 
Latest News
spacer View All spacer
 
November 22, 2009
 
Video Game Watchdog National Institute On Media And The Family Shutting Down [11]
 
Modern Warfare 2 Infinity Ward's 'Most Successful PC Version' Yet [12]
 
New Tech, Design Details Of Project Natal To Emerge At Gamefest In February
spacer
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
November 22, 2009
 
Trion Redwood City
Sr. Evnironment Modeler
 
Trion Redwood City
Sr. Environment Artist
 
Sucker Punch Productions
3D Environment Artist
 
Sucker Punch Productions
Network Programmer
 
Sucker Punch Productions
Character Artist
 
Sucker Punch Productions
Texture Artist
 
Monolith Productions
Sr. Software Engineer, Engine - Monolith Productions - #113767
 
Sony Online Entertainment
Brand Manager
spacer
Latest Features
spacer View All spacer
 
November 22, 2009
 
arrow Upping The Craft: Susan O'Connor On Games Writing [6]
 
arrow Small Developers: Minimizing Risks in Large Productions - Part II [7]
 
arrow iPhone Piracy: The Inside Story [48]
 
arrow And Yet It Grows: Analyzing the Size and Growth of the European Game Market [5]
 
arrow NPD: Behind the Numbers, October 2009 [13]
 
arrow Reflecting On Uncharted 2: How They Did It [5]
 
arrow Sponsored Feature: Rasterization on Larrabee -- Adaptive Rasterization Helps Boost Efficiency
 
arrow Postmortem: Wadjet Eye's The Blackwell Convergence [2]
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
November 22, 2009
 
Time Fcuk
 
Accepting the Inherent Value of Games
 
Planckogenesis, Part II: Song Structure & Gravy Train [1]
spacer
About
spacer News Director:
Leigh Alexander
Features Director:
Christian Nutt
Editor At Large:
Chris Remo
Advertising:
John 'Malik' Watson
Recruitment/Education:
Gina Gross
 
Features
  Messing with Tangent Space
by Siddharth Hegde
5 comments
Share RSS
 
 
July 16, 2007 Article Start Previous Page 3 of 7 Next
 

Creating the tangent space matrix for a vertex

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 Mwt matrix for the two faces. Lets call the two Mwt matrices M1wt for Face1,2,3 and M2wt for Face2,4,3.

Advertisement

In order to calculate T, B, N for vertex 1, we do as follows

V1.Mwt.T = M1wt.T / 1
V1.M
wt.B = M1wt.B / 1
V1.M
wt.N = M1wt.N / 1

We divide by 1 because V1 is used only by 1 face.

T, B, N values for vertex 2 are as follows

V2.Mwt.T = (M1wt.T + M2wt.T) / 2
V2.M
wt.B = (M1wt.B + M2wt.B) / 2
V2.M
wt.N = (M1wt.N + M2wt.N) / 2

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 ;
}

Face =
{
Integer A, B, C ;
}

Matrix3 =
{
Vector3 T, B, N ;
}
Mesh =
{
Vertex VertexList[] ;
Face FaceList[] ;
Matrix3 TSMarixList[] ;
}

Predefined Functions:

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.

Matrix3 TangentSpaceFace(Face F, Vertex3 VertexList[])
{
Matrix3 ReturnValue ;

Vertex E21 = VertexList[F.B] - VertexList[F.A] ;
Vertex E31 = VertexList[F.C] - VertexList[F.A] ;

ReturnValue.N = Cross(E21.P, E31.P) ;
ReturnValue.N = Normalize(ReturnValue.N) ;

ReturnValue.T = E21.P / E21.T.u ;
ReturnValue.T = Normalize(ReturnValue.T) ;

ReturnValue.B = Cross(ReturnValue.T, ReturnValue.N) ;

return ReturnValue ;
}

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.

Matrix3 TangentSpaceVertex(Integer VertexIndex, Face FaceList[], Matrix3 FaceMatrix[])
{
Integer Count = 0 ;
Integer i = 0 ;
Matrix3 ReturnValue = ((0, 0, 0), (0, 0, 0), (0, 0, 0)) ;

ForEach ( Face in FaceList as CurrFace )
{
If(CurrFace.A == VertexIndex or CurrFace.B == VertexIndex or CurrFace.C == VertexIndex)
{
ReturnValue.T += FaceMatrix[i].T ;
ReturnValue.B += FaceMatrix[i].B ;
ReturnValue.N += FaceMatrix[i].N ;
++Count ;
}

++i ;
}

if (Count > 0)
{
ReturnValue.T = ReturnValue.T / Count ;
ReturnValue.B = ReturnValue.B / Count ;
ReturnValue.N = ReturnValue.N / Count ;

ReturnValue.T = Normalize(ReturnValue.T) ;
ReturnValue.B = Normalize(ReturnValue.B) ;
ReturnValue.N = Normalize(ReturnValue.N) ;
}

return ReturnValue ;
}

TangentSpaceMesh
Description: This calculates the tangent space matrices for the vertices in the Mesh M

TangentSpaceMesh(Mesh M)
{

Matrix3 FaceMatrix[M.FaceList.Count()] ;
Interger i ;

ForEach Face in M.FaceList as ThisFace
{
FaceMatrix[i] = TangentSpaceFace(ThisFace, M.VertexList) ;
}

For(i=0; i {
M.TSMarixList[i] = TangentSpaceVertex(i, M.FaceList, FaceMatrix) ;
}

}

 
Article Start Previous Page 3 of 7 Next
 
Comments

Kiran Sudhakara
profile image
Step 2: Calculate the T vector
T = E2-1.xyz / E2-1.u

This formula does not seem correct. Wouldn't this just scale the edge?

David Larsson
profile image
Responce to Kiran's comment:

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)

Kiran Sudhakara
profile image
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.

Shih-Kai Lai
profile image
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...

Julian Hainsworth
profile image
No two vertices should have the exact same UV-Coords, if this is a problem with your meshes you should see your artist


none
 
Comment:
 


Submit Comment