gl.UnitTBN

gl.UnitTBN

Requests for features in the spring code.

Moderator: Moderators

Post Reply
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

gl.UnitTBN

Post by Argh »

Basically, this would be a version of gl.Unit(), the Lua callout, but it would also include the tangent and binormal, which would be returned, per vertex, to Uniform vec3s in the GLSL shader, named Tangent and Binormal.

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);
	}
}
The last two lines set the Uniform... Shader refers to the shader in use at the time that this callout runs. Assuming that you have a Shader in use, and it has the Uniform vec3s defined correctly, then this should work.

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.
Post Reply

Return to “Feature Requests”