Tangent space matrix

Unfadable 101 Oct 09, 2005 at 02:17

I read a paper on deriving the tangent space matrix and was wondering what if any effect does handedness(left vs right) and vertex winding order have on the outcome of tangent and binormal.

I’m in a left-handed system and for a quad with normal (0, 0, -1), my tangent comes out to (-1, 0, 0), and my binormal is (0, -1, 0). The UVs are mapped to the four corresponding corners of the texture, not inverted or anything like that.

Seems like tangent and binormal should be positive in this case, so I’m fishing around for hints to try and understand.


                 D3DXVECTOR3 v2v1(  m_vertices[indices[1]].x - m_vertices[indices[0]].x,
                m_vertices[indices[1]].y - m_vertices[indices[0]].y,
                m_vertices[indices[1]].z - m_vertices[indices[0]].z);

        D3DXVECTOR3 v3v1(   m_vertices[indices[2]].x - m_vertices[indices[0]].x,
                    m_vertices[indices[2]].y - m_vertices[indices[0]].y,
                    m_vertices[indices[2]].z - m_vertices[indices[0]].z);

        float s1 = m_vertices[indices[1]].U - m_vertices[indices[0]].U; 
        float s2 = m_vertices[indices[1]].V - m_vertices[indices[0]].V; 
        float t1 = m_vertices[indices[2]].U - m_vertices[indices[0]].U;     
        float t2 = m_vertices[indices[2]].V - m_vertices[indices[0]].V;

        float det = 1.f / (s1 * t2 - t1 * s2);

        D3DXVECTOR3 t = det * (v2v1*t2) - (v3v1*s2);
        D3DXVECTOR3 b = det * (-t1*v2v1) + (v3v1*s1);

6 Replies

Please log in or register to post a reply.

Unfadable 101 Oct 09, 2005 at 03:14

After thinking about it some, it looks like my tangent space matrix switched handedness on me. Jumped to right-handed but I’m working in left.

I reversed my wind order and cross-product calculation and both t and b are positive now. Is this correct?

corey 101 Oct 09, 2005 at 03:31

The winding will affect the direction that the quad is facing, yes.


Unfadable 101 Oct 09, 2005 at 04:32

Hmm, my question seems a little silly now that i look back at it.

Still would love to hear some input though.

elengyel 101 Oct 21, 2005 at 21:28

What was the paper that you read? Your s and t variables are a little twisted from the original source of this procedure, but you’re usage appears to be consistent, so it should work. There is a problem with your last two lines, however – they should be:

D3DXVECTOR3 t = det * (v2v1*t2 - v3v1*s2);
D3DXVECTOR3 b = det * (-t1*v2v1 + v3v1*s1);


Unfadable 101 Dec 02, 2005 at 00:06

It’s been a little while since I’ve found time to work on this but everything looks really sweet now. I do have a couple of questions:

So I changed my code to this.

float s1 = m_vertices[indices[1]].U - m_vertices[indices[0]].U;
float s2 = m_vertices[indices[2]].U - m_vertices[indices[0]].U;

float t1 = m_vertices[indices[1]].V - m_vertices[indices[0]].V;
float t2 = m_vertices[indices[2]].V - m_vertices[indices[0]].V;

D3DXVECTOR3 t = (det * ((v2v1*t2) - (v3v1*t1)));
D3DXVECTOR3 b = (det * ((-s2*v2v1) + (v3v1*s1)));

1) Now, it turns out that occasionally in my sphere model, the normalized averaged b is the same as the normal. This sort of makes sense if you think of the averaged binormal for the middle vertex in a tri-fan. Does this make sense to anyone else?

If so, then is the purpose of the generated b just to determine handedness of the basis vectors? (and we just cross normal and tangent to get the correct b)

2) Most stuff I’ve read calculate the Binormal from Tangent and Normal in the vertex shader. I was thinking of storing it with each vertex and avoiding the cross-product and multiply calculation. So besides the extra per-vertex memory overhead and use of texture coord, is there any other downside to doing this?


Reedbeta 167 Dec 02, 2005 at 00:23

The binormal never ought to come out to the same as the normal unless they’re both 0 (in which case you have bigger problems)…they’re supposed to be perpendicular, after all =D

Generally, you probably oughtn’t to average the tangent bases over adjacent triangles if they are too different from one another, but split the model instead. The reason is that bases ought to be continuously varying across a surface, and the three vertices of a triangle therefore ought to have similiar bases (i.e. angle between the three tangents is less than some tolerance, etc). This is because your vertex shader will be transforming the light and view vectors into the tangent basis at each point, and these vectors will be linearly interpolated across the surface of the triangles. If the three vertex bases are too different, the light and view vectors near the interior of the triangle won’t make any sense.

If you think about it for a minute, you’ll see that there’s no way to continuously define a basis at each point on a sphere (in mathematics, this is known as the property that “you can’t comb hair on a sphere”). And therefore, the same thing happens for all surfaces that are topologically equivalent to a sphere, which a large number of typical character or object models are. Thus you have to cut the models in pieces so that the tangent basis can vary continuously at each piece, but doesn’t match up along the boundaries between them. It’s similiar to the corresponding problem with texture coordinates.