Sharing tangents between faces

So, I read the stuff about how
to generate tangets for a face given the
texture coordinates, and it works fine.

Now, since they are calculated per face, i get X tangents for each vertex, used in X faces, and I need to somehow melt them together.

My first thought was to just average them for all faces using the vertex, but I am unsure if it’s a safe way.

When adding all the tangents for a given vertex their sum could be the zero vector, which leaves me in trouble?

Another thing is the interpolation across the triangle, it must be possible to generate a case where the tangent i v0 is t, and in v1 is -t… which would give me another headache, cause interpolation of it would go through (0,0,0).

How can I solve these problems?

Apparently Nvidia’s meshmender does something to solve some of these problems, but there is close to no documentation of excatly what it does and how it does it.

Any help & pointers to documents are greatly appreciated.

>>Now, since they are calculated per face, i get X tangents for each vertex, used in X faces, and I need to somehow melt them together.<<

just add all the 3x3 matrices together + and normalize the result (orthonormalize) it works on all meshes ive tried.

You should be able to share a tangent basis iff you can share the normal and texture coordinate for the vertex. Thus, you should calculate your tangent basis after you’ve already normalized your vertex arrays.

My way of finding an orthonormal basis is similar to zed: add 'em all up and then orthonormalize (starting out with the normal as “fixed”). You actually only need to orthonormalize S (X in your case) because T should be N x S. If S is (close to) zero, then use an arbitrary vector (I use X). If X is too close to the normal, use another arbitrary vector (I use Y).

While “picking an arbitrary vector” might look bad, the reason you’re getting problems is probably that you already have an inversion at that point, which will look bad no matter what. You might as well make your code deal with it in a manner which doesn’t divide by zero :slight_smile:

There is a special case where you can’t share Tangent basis per vertex, and that is when you “clone” texture space for similar geometry.

Take for instance a cylinder, it has two circles (one top and one bottom), we may want to make efficient use of texture space and map all four half-circles onto one half-circle in the texture map.

In this case two half circles share normals and one tangent vector, but the other tangent goes in the opposite direction.

I try to cover all cases by using 3 tangent basis for each triangle.

I only average tangent basis at vertices if
their tangents are less than 90 degs apart.
(i.e.
if (Tri_S dot Neighbour_S > 0) && (Tri_T dot Neighbour_T > 0)
then average them)

Note: the tangent basis at vertices are still
orthogonalized to the smoothed vertex normal.

By the way, on your request for sources:

I use “Mathematics for 3D Game Programming”
by Eric Lengyel.

This book is pretty good and worth buying IMHO.

The tangent space calculation in this book
is the most robust of the ones I’ve tried…

Alright, thanks for your replies.

Seems there is two solutions

  1. When the tangent gets close to zero, use cross(normal,X) (or cross(normal,Y) if that one is close to 0 too

  2. check if the angles are close enough before averaging.

  1. is easiest, 2. is safest.

But since it appears that 1. works fine, I will try that.

oh yeah, 2. makes more vertices too.

Thanks, Jonas