**comp.graphics.algorithms**

## Subject: **Re: tangent space for normal mapping**

"halex2000"

news:ZzG8g.5198$b5.88913@twister2.libero.it...

> 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

Reply

View All Messages in

**comp.graphics.algorithms**

path:

tangent space for normal mapping =>

Replies:

Re: tangent space for normal mapping

Copyright © 2006 WatermarkFactory.com. All Rights Reserved.