Jump to content
  • Advertisement
Sign in to follow this  
Dynx

Tangent space calculation

This topic is 3547 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone, I implemented normal mapping on RenderMonkey where it worked perfectly fine but when I transferred it over to my framework I had artifacts with both diffuse and specular terms so I started to think that there are issues with my tangent space computation. I am stuck and cannot continue because I need to make sure that my framework works correctly before going on to some of the advanced topics that I was hoping to study during the next couple days I have. I need any tiny help or suggestion that you guys can give. The function below adds a single polygon to a mesh. I am not quite sure whether this works for polygons with more than 3 vertices but right now I only work with triangles so it shouldn't matter. V0,V1,V2 are the vertices of the triangle and S and T are texture coordinates and I am solving the following system: V1-V0 = (S1-S0)TAN - (T1-T0)BITAN V2-V0 = (S2-S0)TAN - (T2-T0)BITAN -compute face normal -compute face tangent -for each vertex in the polygon ----compute the new average of the normal/tangent/bitangent of the vertex in the mesh -add polygon to the mesh I do all vertex computations in eye space and I am sure that my view matrix is ok as the specular term on another shader applied to the ball in the picture works fine. Click for screenshot
void 
Mesh::addPolygon( Polygon p )
{
	//Calculate face normal
	Vector<int>* indices = p.getIndices();
	Vec3D vA = vertexList_[ (*indices)[0] ].position;
	Vec3D vB = vertexList_[ (*indices)[1] ].position;
	Vec3D vC = vertexList_[ (*indices)[2] ].position;

	Vec3D normal = cross( vB - vA, vC - vA );
	normal.normalize();

	p.setNormal( normal );

	//Calculate tangent/bitangent
	Vec3D Q1 = vB - vA;
	Vec3D Q2 = vC - vA;
	Q1.normalize();
	Q2.normalize();

	Vec2D vAtexCoord = vertexList_[ (*indices)[0] ].texCoord;
	Vec2D vBtexCoord = vertexList_[ (*indices)[1] ].texCoord;
	Vec2D vCtexCoord = vertexList_[ (*indices)[2] ].texCoord;

	float S1 = vBtexCoord.x - vAtexCoord.x;
	float T1 = vBtexCoord.y - vAtexCoord.y;
	float S2 = vCtexCoord.x - vAtexCoord.x;
	float T2 = vCtexCoord.y - vAtexCoord.y;

	float det = 1.0f / ( S1 * T2 - S2 * T1 );

	Vec2D r1( T2, -T1 );

	Vec3D tangent( det * dot( r1, Vec2D( Q1.x, Q2.x ) ),
		       det * dot( r1, Vec2D( Q1.y, Q2.y ) ),
		       det * dot( r1, Vec2D( Q1.z, Q2.z ) ) );
	tangent.normalize();

	Vec3D bitangent = cross( normal, tangent );
	bitangent.normalize();

	//Update vertex normals
	for( uInt i = 0; i < indices->size(); i++ )
	{
		Vertex *v = &vertexList_[(*indices)];

		v->normal = v->normal + normal;
		v->normal.normalize();

		v->tangent = v->tangent + tangent;
		v->tangent.normalize();

		v->bitangent = v->bitangent + bitangent;
		v->bitangent.normalize();
	}

	polygonList_.push_back(p);
}




Share this post


Link to post
Share on other sites
Advertisement
There are some things looking suspect to me:

(1) Why are Q1 and Q2 being normalized?
(2) Is it guaranteed that the order of vertices A, B, and C is always the same (i.e. ever clockwise or else ever counterclockwise) for all added polygons?
(3) The averaging at the end of the routine iterates over the vertices of the current polygon. Is it guaranteed that the vertex normal vectors are appropriately initialized before?
(4) The averaging performs an immediate normalization of the sum. Is it guaranteed that one and only one summation is done (or else the summarized vectors are not weighted equally)?
(5) After averaging, the normal, tangent and bi-tangent may no longer be pairwise orthogonal if you add more than a single vector to an initial 0.

Share this post


Link to post
Share on other sites
I separated averaging/normalization from the function that adds a polygon to a mesh and it now gets called only once at the end when there is no more polygon to add. And it's only for my use right now, so yes I make sure that vertices are only ordered counter-clockwise and that no vertex is added after the tangents are calculated.

The problem could also be that I was reusing parts of my previous shader which does the light-view vector calculations in view space and the above TBN matrix is for object-to-tangent space transformation but again I multiply it by the inverse-transpose of modelview matrix so that shouldn't be a problem. Ah just rambling on here this is taking too much time..


void
Mesh::addPolygon( Polygon p )
{
//Calculate face normal
Vector<int>* indices = p.getIndices();
Vec3D vA = vertexList_[ (*indices)[0] ].position;
Vec3D vB = vertexList_[ (*indices)[1] ].position;
Vec3D vC = vertexList_[ (*indices)[2] ].position;

Vec3D normal = cross( vB - vA, vC - vA );
normal.normalize();

p.setNormal( normal );

//Calculate tangent/bitangent
Vec3D Q1 = vB - vA;
Vec3D Q2 = vC - vA;

Vec2D vAtexCoord = vertexList_[ (*indices)[0] ].texCoord;
Vec2D vBtexCoord = vertexList_[ (*indices)[1] ].texCoord;
Vec2D vCtexCoord = vertexList_[ (*indices)[2] ].texCoord;

float S1 = vBtexCoord.x - vAtexCoord.x;
float T1 = vBtexCoord.y - vAtexCoord.y;
float S2 = vCtexCoord.x - vAtexCoord.x;
float T2 = vCtexCoord.y - vAtexCoord.y;

float det = 1.0f / ( S1 * T2 - S2 * T1 );

Vec2D r1( T2, -T1 );

Vec3D tangent( det * dot( r1, Vec2D( Q1.x, Q2.x ) ),
det * dot( r1, Vec2D( Q1.y, Q2.y ) ),
det * dot( r1, Vec2D( Q1.z, Q2.z ) ) );

tangent.normalize();

p.setTangent( tangent );

polygonList_.push_back(p);
}

void
Mesh::computeTangentSpace()
{
for( uInt i = 0; i < polygonList_.size(); i++ )
{
Vector<int> *indices = polygonList_.getIndices();

Vec4D normal = polygonList_.getNormal();
Vec4D tangent = polygonList_.getTangent();
Vec4D bitangent = cross( normal, tangent );
bitangent.normalize();

for( uInt j = 0; j < indices->size(); j++ )
{
Vertex *v = &vertexList_[(*indices)[j]];

v->normal = v->normal + normal;
v->tangent = v->tangent + tangent;
v->bitangent = v->bitangent + bitangent;
}
}

for( uInt i = 0; i < vertexList_.size(); i++ )
{
Vertex *v = &vertexList_;
v->normal.normalize();
v->tangent.normalize();
v->bitangent.normalize();
}
}


Share this post


Link to post
Share on other sites
Would anyone care to check the vertex shader below to see if there is a problem that I can't see? Past 5 days I've been working on this and I am in shock and very close to frustration that I can't get it to work.

lightPosition is multiplied by the view matrix in the application and I am using the code above to calculate the tangents.

Thanks a lot


uniform vec3 lightPosition;

varying vec3 lightDirection;
varying vec3 viewDirection;
varying vec2 texcoord;
varying float d;

attribute vec3 tangent;

void main(void)
{
gl_Position = ftransform();

vec4 vertPosition = gl_ModelViewMatrix * gl_Vertex;

texcoord = gl_MultiTexCoord0.xy;

vec3 n = gl_NormalMatrix * gl_Normal;
vec3 t = gl_NormalMatrix * tangent;
vec3 b = cross( n, t );

vec3 lightVector = lightPosition - vertPosition.xyz;
float l = length( lightVector );

lightDirection.x = dot( lightVector, t );
lightDirection.y = dot( lightVector, b );
lightDirection.z = dot( lightVector, n );

float k0 = 0.001;
float k1 = 0.0001;
float k2 = 0.0002;

d = max( 0.0, 1.0 / ( k0 + k1 * l + k2 * l * l ) );

viewDirection = -vertPosition.xyz ;

viewDirection.x = dot( viewDirection, t );
viewDirection.y = dot( viewDirection, b );
viewDirection.z = dot( viewDirection, n );
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!