Calculate tangent from normal?

Started by
9 comments, last by cignox1 14 years, 5 months ago
Is it possible to calculate a tangent from a normal? I am trying to do normal mapping in a software renderer I am making (for fun and learning). Normally (pun intended) in HLSL I would use the : NORMAL0 and : TANGENT0 semantics to get this information from the vertex stream and then generate a TBN (for going from tangent to world space) matrix doing something like: output.tangentToWorld[0] = mul(input.tangent, World); output.tangentToWorld[1] = mul(cross(input.tangent,input.normal), World); output.tangentToWorld[2] = mul(input.normal, World); Then I can easily use this to bring the tangent space normal from my texture map into world space doing something like: float3 normalFromMap = tex2D(NormalMapSampler, input.texCoord); normalFromMap = mul(normalFromMap, input.tangentToWorld); normalFromMap = normalize(normalFromMap); Ive got normals at each vertex in my software render stream but Im missing the tangents! How could I calculate these? [Edited by - richardmonette on November 6, 2009 9:05:12 AM]
Advertisement
There are infinitely many vectors that you can use as tangents, as it can be any vector perpendicular to the normal. You can find one by calculating the cross-product of the normal and an arbitrary vector that isn't parallel to the normal.

[Edited by - Erik Rufelt on November 4, 2009 4:03:12 PM]
Here's what I've come up with (based off this guide http://www.ozone3d.net/tutorials/mesh_deformer_p2.php):

Vec3 tangent;

Vec3 c1 = cross(normal, Vec3(0.0, 0.0, 1.0));
Vec3 c2 = cross(normal, Vec3(0.0, 1.0, 0.0));

if( len(c1) > len(c2) )
{
tangent = c1;
}
else
{
tangent = c2;
}

normalizeSelfFAST(tangent);

Vec3 bitangent = cross(tangent, normal);

This seems to be working pretty well (produces the correct visual result). Is this a good solution or can you see any improvements?
It's a good solution.
Usually you build your tangents/bitangents such that they match the uv coordinates, but I don't know for sure what you need, so the suggested solution may be enough.
How do you "match" tangents / bitangents to UVs?
Yeah, picking arbitrary perpendicular tangents isn't going to work, at all. That's not the most important property of tangents/bi-tangents. The key thing is that the tangent is the vector that points in the direction of increasing 'U', and the bi-tangent points in the direction of increasing 'V'.

Imaging looking at the polygon, head-on, in space. Then imagine rotating (about the normal) so that the texture co-ordinate gradients are increasing precisely along your X and Y axes. That co-ordinate system is the tangent-space for that polygon.

This is important, because the normal maps are stored *in that space*. So you need to know how it's oriented to transform the normals back into world space (or whatever) to do lighting.
Thanks for the post. Definitely clears this up, at least on the conceptual level.

So I've got my normals (transformed into world space). I know that once I've got a tangent (which should be increasing down the U axis) I can just cross product that with my normal to get my bi-tangent.

But I'm still kind of stuck on how to implement something that will give me the correct tangent. Is there a good reference on how to handle that?
What information do you have, and what information do you need?
Do you have a triangle with texture coordinates for each vertex, and a normal to that, and want to calculate the tangent so that it matches the direction of the first texture coordinate?
"Do you have a triangle with texture coordinates for each vertex, and a normal to that, and want to calculate the tangent so that it matches the direction of the first texture coordinate?"

Correct, Ive got a triangle, normal at each vertex, UV at each vertex.

Id like to generate the tangent at that vertex.

Here's what I am thinking might work:

1. Get the U direction using the adjacent vertices.
2. Calculate the plane which is described by the normal
3. Project the U direction onto this plane

This topic is closed to new replies.

Advertisement