smooth tangent space vectors

After taking a look at Nvidia’s bump mapping tutorials (in particular
their md2bump demo), I’m having difficulty getting my bump mapping
code to work correctly. My problem appears to be in my tangent space
computation, which looks something like this:

//assume counter-clockwise winding of triangles
foreach triangle in mesh {
//find side vectors of triangle
vector a = triangle.vertex[ 1 ] - triangle.vertex[ 0 ];
vector b = triangle.vertex[ 2 ] - triangle.vertex[ 0 ];

//find s gradient
float aw = triangle.st[ 1 ].s - triangle.st[ 0 ].s;
float bw = triangle.st[ 2 ].s - triangle.st[ 0 ].s;

//find partial derivative
vector pd = aw * b - bw * a;
pd.normalize( );

//compute tangent and binormal for each vertex
foreach vertex in triangle {
//compute t (tangent) tangent
float t = dot( pd, vertex.normal );
vertex.t_tangent = pd - t * vertex.normal;
vertex.t_tangent.normalize( );

//compute s (binormal) tangent
vertex.s_tangent = cross( tmp, vertex.normal );

}
}

A couple of problems I’ve noticed: If vertex.normal is the face’s normal
then my mesh will look very faceted. This is expected.

http://www.vr.clemson.edu/~acnatha/tangent_0.jpg

If vertex.normal is a smoothed normal. The mesh looks nice, but some
faceting is still noticeable. Unfortunately, the faceting is still
noticeable enough to be annoying.

http://www.vr.clemson.edu/~acnatha/tangent_1.jpg

Here’s some pseudo code I use to smooth out the normals.

//assume all normals in the smooth_normals
//list start out at 0,0,0
list smooth_normals;
list num_normals;

foreach triangle in mesh {
//find side vectors of triangle
vector a = triangle.vertex[ 1 ] - triangle.vertex[ 0 ];
vector b = triangle.vertex[ 2 ] - triangle.vertex[ 0 ];

//compute normal
vector n = cross( a, b );

//QUESTION: is this normalization necessary?
n.normalize( );

foreach vertex in triangle {
//add to the smoothed normal for this vertex
smooth_normals[ vertex.normal_index ] += n;

//increment the number of normals we've used to smooth 
//this vertex
num_normals[ vertex.normal_index ] += 1;

}
}

for( n = 0; n < smooth_normal.size( ); ++n ) {
//divide the summed normal by the number of normals used to
//compute it
smooth_normals[ n ] /= num_normals[ n ];

//QUESTION: is this normalization necessary?
smooth_normals[ n ].normalize( );
}

In hopes of fixing the faceting, I’ve tried smoothing out the
tangent (s_tangent) and binormal (t_tangent) vectors. However, I’ve
yet to come up with nice results. I’ve tried computing the tangent
and binormals several different ways.

First, I used the vertex’s normal to compute the t_tangent
as above, adding and then averaging the t_tangents in hopes of smoothing
the tangent. After computing the smooth t_tangent, I then find the
cross product of the t_tangent and the vertex’s normal to find
the s_tangent (binormal). I’ve tried using both the face and smooth
normal for these computations.

My mesh is now smooth, but highlights are no longer consistent across
face boundaries!

http://www.vr.clemson.edu/~acnatha/tangent_2.jpg

(notice the knight’s right kneecap)

Second, I used the vertex’s normal to compute the t_tangent
as above, adding and then averaging the t_tangents in hopes of smoothing
the tangent. I did the same for the s_tangent. I’ve tried using
both the face and smooth normal for these computations.

Again, my mesh is now smooth, but highlights are no longer
consistent across face boundaries!

So, it seems I have a choice, either I’m left with a mesh that has a
slightly faceted look, or a mesh with incorrect highlights.

Am I going about smoothing the s and t tangent vectors incorrectly?

Is it even possible to smooth the s and t vectors (since it may not
create an orthonormal basis)? Reading through this forum suggest
that it is possible.

Any insights on what I’m doing wrong?

nathan

[This message has been edited by cournia (edited 03-26-2003).]

[This message has been edited by cournia (edited 03-26-2003).]

You have to be careful that the knight’s kneecap is not mirrored in texture space. The fix is to detect the discontinuity and duplicate the edge.

The latest version of nvmeshmender on www.nvidia.com/developer does this.

Also, you don’t need to divide by the # of smoothed normals, b/c you normalize the result right afterwards.