# Re: tangent space for normal mapping

"halex2000" <powernews@xxxxxxxxx> wrote in message
news:ZzG8g.5198\$b5.88913@xxxxxxxxxxxxxxxxxxxxx
I need to create the inverse TBN matrix for normal mapping in Shaders, but
I'm confused about the math. Could someone help me? (note that my math
skills sucks)
-My mesh has averaged normal among shared vertices. I calculate tangent
and bitangent correctly for triangle normal, but now I need to make them
orthogonal. Can I simply do as I did for normals, that is average the
tangent and bitangent among shared vertices? Will the three vectors be
orthogonal?
-When I have the TBN matrix I need to invert it. I've read that since TBN
is orthonormal, I can simplly transpose it. Is this correct?

You asked this in comp.graphics.api.opengl and, apparently, in
the forums at gamedev.net. It is admirable that you have such
enthusiasm for wanting to work with computer graphics and
shaders. I must say, though, that every time the question is
posed--"I want to know about the math topic FooBar, but my
math skills suck"--I have to wonder if the poster's time is better
spent learning the math skills first before attempting programming
that requires those skills.

As I had mentioned in the opengl newsgroup, one of your goals
is to produce a set of vertex tangents that correspond to a
"continuous" tangent vector field over the surface that your mesh
represents. A standard approach is to think of the vertices as
samples from a smooth parametric surface P(u,v), where (u,v)
are texture coordinates for the texture to which you will apply the
normal mapping. The partial derivative T = dP/du is a tangent
vector to the surface at a vertex. If N is a *surface* normal,
choose the bitangent to be B = Cross(N,T). I had supplied a link
to a calculus-based explanation for computing dP/du at a vertex
of a triangle in the mesh,
http://www.geometrictools.com/Documentation/BumpTangent.pdf
The end result is an equation that is relatively easy to implement.

The problems in practice are (1) you have a unit-length *vertex*
normal N', which is not necessarily a surface normal relative to the
parameterization by (u,v), and (2) this algorithm produces a
vector T that is not necessarily unit length or perpendicular
to N'. You project out the N' component in T and then normalize
the result,
T = T - Dot(T,N')*N'
T' = T/Length(T)
Now you have unit-length vectors N' and T' that are perpendicular.
Choose B' = Cross(N',T'), another unit-length vector perpendicular
to N' and T'.

Here is an implementation of the algorithm for producing T for a
triangle with vertex positions P0, P1, P2 and corresponding texture
coordinates (u0,v0), (u1,v1), and (u2,v2). The projection and
normalization steps are easy enough to apply to the output of
this function.

bool SimpleBumpMapEffect::ComputeTangent (const Vector3f& rkPos0,
const Vector2f& rkTCoord0, const Vector3f& rkPos1,
const Vector2f& rkTCoord1, const Vector3f& rkPos2,
const Vector2f& rkTCoord2, Vector3f& rkTangent)
{
// Compute the change in positions at the vertex P0.
Vector3f kDP1 = rkPos1 - rkPos0;
Vector3f kDP2 = rkPos2 - rkPos0;

if (Mathf::FAbs(kDP1.Length()) < Mathf::ZERO_TOLERANCE
|| Mathf::FAbs(kDP2.Length()) < Mathf::ZERO_TOLERANCE)
{
// The triangle is very small, call it degenerate.
return false;
}

// Compute the change in texture coordinates at the vertex P0 in the
// direction of edge P1-P0.
float fDU1 = rkTCoord1[0] - rkTCoord0[0];
float fDV1 = rkTCoord1[1] - rkTCoord0[1];
if (Mathf::FAbs(fDV1) < Mathf::ZERO_TOLERANCE)
{
// The triangle effectively has no variation in the v texture
// coordinate.
if (Mathf::FAbs(fDU1) < Mathf::ZERO_TOLERANCE)
{
// The triangle effectively has no variation in the u
coordinate.
// Since the texture coordinates do not vary on this triangle,
// treat it as a degenerate parametric surface.
return false;
}

// The variation is effectively all in u, so set the tangent vector
// to be T = dP/du.
rkTangent = kDP1/fDU1;
return true;
}

// Compute the change in texture coordinates at the vertex P0 in the
// direction of edge P2-P0.
float fDU2 = rkTCoord2[0] - rkTCoord0[0];
float fDV2 = rkTCoord2[1] - rkTCoord0[1];
float fDet = fDV1*fDU2 - fDV2*fDU1;
if (Mathf::FAbs(fDet) < Mathf::ZERO_TOLERANCE)
{
// The triangle vertices are collinear in parameter space, so treat
// this as a degenerate parametric surface.
return false;
}

// The triangle vertices are not collinear in parameter space, so choose
// the tangent to be dP/du = (dv1*dP2-dv2*dP1)/(dv1*du2-dv2*du1)
rkTangent = (fDV1*kDP2-fDV2*kDP1)/fDet;
return true;
}

--
Dave Eberly
http://www.geometrictools.com

.

## Relevant Pages

• Dealing with Degrees and Radians
... I'm trying to determine the length of the opposite leg of a triangle ... However it seems Math is set in radians ... (at least, I'm getting negative numbers returned from tangent, and I ...
(comp.lang.java.help)
• tangent space for normal mapping
... I'm confused about the math. ... Can I simply do as I did for normals, ... tangent and bitangent among shared vertices? ... -When I have the TBN matrix I need to invert it. ...
(comp.graphics.algorithms)
• Re: Spiralling Triangle Strip
... > I assume you mean you need to create vertex normals, ... > length 1.0) before storing it in your vertex buffer otherwise you will get ... >> found any information on how to do this with a triangle list or triangle ... >>>>order of the vertices in a triangle strip important when using ...
(microsoft.public.win32.programmer.directx.managed)
• Re: Tangent for 3D vectors
... I need the formula to calculate tangent for 3D ... there are actually two normals so you have to know how to set up the ... throttle) into the tangent PLANE of the ground. ... If D is the normalized direction vector, T is your thrust scalar and N ...
(comp.programming)
• Re: Spiralling Triangle Strip
... "Kevin Spencer" wrote in message ... >> I assume you mean you need to create vertex normals, ... >> plane normal for each triangle that the vertex is a part of and then ... >> length 1.0) before storing it in your vertex buffer otherwise you will ...
(microsoft.public.win32.programmer.directx.managed)