We already have the mesh, with all transforms performed, and set up as a display list, in the gl.Unit callout. All we need to do is run one further bit of code, per triangle (not per vertex, no need to run it three times):
Code: Select all
void CalculateTBNMatrix(const CVector *pvTriangle, const CVector2 *pvTexCoords, CVector *pvTBNMatrix)
{
// Calculate the tangent basis for each vertex of the triangle
// UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has
// been removed as it was redundant (the entire TBN matrix was calculated three times
// instead of just one).
//
// Please note, that this function relies on the fact that the input geometry are triangles
// and the tangent basis for each vertex thus is identical!
//
// We use the first vertex of the triangle to calculate the TBN matrix, but we could just
// as well have used either of the other two. Try changing 'i' below to 1 or 2. The end
// result is the same.
int i = 0;
// Calculate the index to the right and left of the current index
int nNextIndex = (i + 1) % 3;
int nPrevIndex = (i + 2) % 3;
// Calculate the vectors from the current vertex to the two other vertices in the triangle
CVector v2v1 = pvTriangle[nNextIndex] - pvTriangle[i];
CVector v3v1 = pvTriangle[nPrevIndex] - pvTriangle[i];
// The equation presented in the article states that:
// c2c1_T = V2.texcoord.x ├óÔé¼ÔÇ£ V1.texcoord.x
// c2c1_B = V2.texcoord.y ├óÔé¼ÔÇ£ V1.texcoord.y
// c3c1_T = V3.texcoord.x ├óÔé¼ÔÇ£ V1.texcoord.x
// c3c1_B = V3.texcoord.y ├óÔé¼ÔÇ£ V1.texcoord.y
// Calculate c2c1_T and c2c1_B
float c2c1_T = pvTexCoords[nNextIndex].x - pvTexCoords[i].x;
float c2c1_B = pvTexCoords[nNextIndex].y - pvTexCoords[i].y;
// Calculate c3c1_T and c3c1_B
float c3c1_T = pvTexCoords[nPrevIndex].x - pvTexCoords[i].x;
float c3c1_B = pvTexCoords[nPrevIndex].y - pvTexCoords[i].y;
float fDenominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B;
if (ROUNDOFF(fDenominator) == 0.0f)
{
// We won't risk a divide by zero, so set the tangent matrix to the identity matrix
pvTBNMatrix[0] = CVector(1.0f, 0.0f, 0.0f);
pvTBNMatrix[1] = CVector(0.0f, 1.0f, 0.0f);
pvTBNMatrix[2] = CVector(0.0f, 0.0f, 1.0f);
}
else
{
// Calculate the reciprocal value once and for all (to achieve speed)
float fScale1 = 1.0f / fDenominator;
// T and B are calculated just as the equation in the article states
CVector T, B;
T = CVector((c3c1_B * v2v1.x - c2c1_B * v3v1.x) * fScale1,
(c3c1_B * v2v1.y - c2c1_B * v3v1.y) * fScale1,
(c3c1_B * v2v1.z - c2c1_B * v3v1.z) * fScale1);
B = CVector((-c3c1_T * v2v1.x + c2c1_T * v3v1.x) * fScale1,
(-c3c1_T * v2v1.y + c2c1_T * v3v1.y) * fScale1,
(-c3c1_T * v2v1.z + c2c1_T * v3v1.z) * fScale1);
gl_Uniform(Shader,"Tangent",T);
gl_Uniform(Shader,"Binormal",B);
}
}
Then we can have bumpmapping and other shader techniques that require the TBN matrix working. There is no way around doing this per triangle, per object, but adding this to Spring should be fairly straightforward, I would think.
A complete article about how this is used, and a functional example, can be seen here, but I don't think that we need the vast majority of that code- we already have the code to do the drawing, set up the lights, etc., all we need is an additional switch in the gl.Unit callout code that returns these specific values, and something that deals with the name of "Shader" appropriately, which is probably trivial.