Home » Community » Forums » Graphics Programming and Theory » Calculate tangent from normal?
  Intel sponsors gamedev.net search:   
[Control Panel] [Register] [Bookmarks] [Who's Online] [Active Topics] [Stats] [FAQ] [Search]

Add Forum to Favorites |  Send Topic To a Friend | View Forum FAQ | Track this topic


 Last Thread Next Thread 
 Calculate tangent from normal?
Post New Topic  Post Reply 
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]

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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]

 User Rating: 1538   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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?

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

It's a good solution.

 User Rating: 1538   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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.

 User Rating: 1365   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

How do you "match" tangents / bitangents to UVs?

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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.

 User Rating: 1253   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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?

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

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?

 User Rating: 1538   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

"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

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Give a look to this, hope it helps

 User Rating: 1365   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

All times are ET (US)

Post Reply
 Last Thread Next Thread 
Forum Rules:
You may not post new threads
You may post replies
You may not edit your posts
You may not use HTML in your posts
Jump To:
Administrative Options: