# Tangent and BiTangent equation?

This topic is 4193 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi all! anyone can help me find a function other than: http://www.terathon.com/code/tangent.html < --- i just cant figure this one... that can compute Tangents and BiTangent for any given mesh with known uvs? thx

##### Share on other sites
That is pretty straightforward, simple code. Perhaps you might want to borrow Eric's book from a library, and read the text that describes the math behind the code?

##### Share on other sites
i didnt kown about the book, it would help.

maybe someone can help me figure this one out then, if it is not too much trouble...

there is 2 thing i dont understand:

first:

why does he use a vector4 to find the tangents, what is the w for?

second:

i was expecting a *vector3 for the tangents and another one for the bitangents... where are the bitangents?

##### Share on other sites
There is no hard requirement to precompute and cache the bitangent, since you can compute it using the already-stored normal and tangent vectors. Yes, would perhaps save runtime (in GPU or wherever) to cache the bitangents, but that would require more storage, and perhaps more data sent across the AGP or PCI-Express bus in a texture.... One makes a tradeoff decision! I think nVidia in their developer docs suggest just computing the bitangent in a shader.

The w is part of a homogeneous vector. It is use to enable graphics engines to treat vectors (as in direction vectors, normal vectors, etc.) and positions (location that is measured relative to some fixed coordinate origin) in a uniform manner in code. For a reasonable introduction to homogeneous coordinates, see the following:

OpenGL Red Book - Appendix F

##### Share on other sites
you were straight on the ball with this post!

thx a million!

##### Share on other sites
humm, im trying to make a version for quads also...
for (Int i = 0; i < l_mesh->GetQuadCount(); ++i)			{				Int i1 = l_quad[i].a;				Int i2 = l_quad[i].b;				Int i3 = l_quad[i].c;				Int i4 = l_quad[i].d;				const Vector3 &v1 = m_Vertex[i1];				const Vector3 &v2 = m_Vertex[i2];				const Vector3 &v3 = m_Vertex[i3];				const Vector3 &v4 = m_Vertex[i4];				const Vector2 &w1 = m_UV[0][i1];				const Vector2 &w2 = m_UV[0][i2];				const Vector2 &w3 = m_UV[0][i3];				const Vector2 &w4 = m_UV[0][i4];				Float x1 = v2.x - v1.x;				Float x2 = v3.x - v1.x;				Float x3 = v4.x - v1.x;				Float y1 = v2.y - v1.y;				Float y2 = v3.y - v1.y;				Float y3 = v4.y - v1.y;				Float z1 = v2.z - v1.z;				Float z2 = v3.z - v1.z;				Float z3 = v4.z - v1.z;				Float s1 = w2.x - w1.x;				Float s2 = w3.x - w1.x;				Float s3 = w4.x - w1.x;				Float t1 = w2.y - w1.y;				Float t2 = w3.y - w1.y;				Float t3 = w4.y - w1.y;				Float r = 1.0f / (s1 * t2 - s2 * t1);				Vector3 l_dir				(					(t2 * x1 - t1 * x2) * r,					(t2 * y1 - t1 * y2) * r,					(t2 * z1 - t1 * z2) * r				);				l_temp[i1] += l_dir;				l_temp[i2] += l_dir;				l_temp[i3] += l_dir;				l_temp[i4] += l_dir;			}

im wondering what r and l_dir will be now?... any hint would be welcome!

##### Share on other sites
In this particular case, the w-coordinate of the tangent is just being used to store a handedness value. It doesn't have anything to do with the tangent itself, but it tells you which way the bitangent is pointing with respect to the normal and tangent.

I don't think there's a straightforward way to extend the tangent calculation to quads. You can't be sure that the tangent directions are the same for each group of three vertices.

##### Share on other sites
Oh great, Eric all mighty!

I ve choose to make Tangents and BiTangents members of my primitives!

that said I use the following:

for (Int i = 0; i < m_VertexCount; ++i)
{
// Gram-Schmidt orthogonalize.
m_Tangent[i] = (m_Tangent[i] - m_Normal[i] * m_Normal[i].DotProduct(m_Tangent[i])).Normalize();
m_BiTangent[i] = (m_Normal[i].CrossProduct(m_Tangent[i])).Normalize();
}

is this correct for the BiTangents? works fine with a plane... I ll just like to be sure!

thx eric!

##### Share on other sites
Yes, your code will work if all your triangles use a right-handed mapping. You don't need to normalize the bitangent if the normal and tangent are already normalized and orthogonal. If you're using 4D tangents with the handedness in the w-coordinate, then you should multiply the bitangent by tangent.w after the cross product (to flip its direction in the left-handed case).

[Edited by - Eric Lengyel on June 14, 2006 6:36:09 PM]

##### Share on other sites
omg... tangents and bitangents nailed down!

thank you so much!

##### Share on other sites
Hi all!

I ve re opened this thread because I actualy do need the handedness of the Tangents and the BiTangents... Im not 100% sure yet but I ll use them to calculate relief mapping: geometry minus displacement alpha...

So I did convert them to Vector4:

so I ve got this:
	for (Int i = 0; i < m_VertexCount; ++i)	{		const Vector3 &t = Vector3(m_Tangent[i].x, m_Tangent[i].y, m_Tangent[i].z);		const Vector3 &n = m_Normal[i];		// Gram-Schmidt orthogonalize.		m_Tangent[i] = (t - n * n.DotProduct(t)).Normalize();		// Calculate handedness.		m_Tangent[i].w = (n.CrossProduct(t).DotProduct(l_tan[i]) < 0.0F) ? -1.0F : 1.0F;		m_BiTangent[i] = n.CrossProduct(Vector3(m_Tangent[i].x, m_Tangent[i].y, m_Tangent[i].z));		m_BiTangent[i].w = ???;	}

my question is... how do I calculate the BiTangent handedness?

hope eric is around ;)

Thx

##### Share on other sites
Hi --

There is no separate handedness for the bitangent. The handedness applies to the whole tangent frame. If you're going to store both tangents and bitangents in vertex arrays, then you don't need to store a 4-component tangent, so they'll both be 3D. Just use the handedness value to calculate the bitangent's direction after the cross product:

bitangent = cross(normal, tangent) * handedness

Now, if you want to save memory and only pass 3D normals and 4D tangents to the GPU, then put the handedness value into the 4th coordinate of your tangent, and do this in the vertex shader:

float3 bitangent = cross(normal, tangent.xyz) * tangent.w;

##### Share on other sites
right, of course!

I m trying to translate a relief mapping shader from cg to glsl... here is what confused me:

cg
// scale and curvature
OUT.scale=float3(IN.tangent.w,IN.binormal.w,depth)/tile;
OUT.curvature=IN.curvature;

They use Vector4 to store tangents and bitangents, here is what the paper says:

In the proposed approach, each vertex of the polygonal
model is enhanced with two coefficients representing a quadric
surface that locally approximates the object’s geometry at the vertex.
Such coefficients are computed during a pre-processing stage
using a least-squares fitting algorithm and are interpolated during
rasterization.

I thought handedness could be related...

thx again eric!

regards

TBN Derivation

##### Share on other sites
Just to chime in: You don't NEED an orthonormal basis for your tangent basis. You could keep the vectors as-is and generate your normal map based on that basis instead (or rather, the inverse). This MAY improve quality throughout your pipeline, assuming that all the tools and rendering use the same basis.

##### Share on other sites

This topic is 4193 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628697
• Total Posts
2984273

• 20
• 9
• 13
• 13
• 11