# Tangent problem

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

## Recommended Posts

I am implimenting normal mapping in my program and must calculate the tangent for use in the shader. So i used terathon.com's method of calculating the tangents, along with code to average the tangents of vertices that are shared among mayn faces (I'm using VA at the moment). And here is the code:
void nrgObject::makeTanArray(){
float x1, x2, y1, y2, z1, z2, s1, s2, t1, t2, r, NdotT, BdotT;
NORMAL  sdir, tdir, tTan, NcrossT;
TANGENT tempTangent;
std::vector<TANGENT> allTangents;

// for each triangle
std::vector<GEOM_INDEX>::size_type triIndex = std::vector<GEOM_INDEX>::size_type(0);
while(triIndex < index.size()){
GEOM_INDEX tV2 = index[triIndex];

x1 = rVerts[tV2.v2].x - rVerts[tV2.v1].x;
x2 = rVerts[tV2.v3].x - rVerts[tV2.v1].x;
y1 = rVerts[tV2.v2].y - rVerts[tV2.v1].y;
y2 = rVerts[tV2.v3].y - rVerts[tV2.v1].y;
z1 = rVerts[tV2.v2].z - rVerts[tV2.v1].z;
z2 = rVerts[tV2.v3].z - rVerts[tV2.v1].z;

s1 = rVerts[tV2.v2].u - rVerts[tV2.v1].u;
s2 = rVerts[tV2.v3].u - rVerts[tV2.v1].u;
t1 = rVerts[tV2.v2].v - rVerts[tV2.v1].v;
t2 = rVerts[tV2.v3].v - rVerts[tV2.v1].v;

r = 1.0f / (s1*t2 - s2*t1);

sdir.i = (t2*x1 - t1*x2)*r;
sdir.j = (t2*y1 - t1*y2)*r;
sdir.k = (t2*z1 - t1*z2)*r;

tdir.i = (s1*x2 - s2*x1)*r;
tdir.j = (s1*y2 - s2*y1)*r;
tdir.k = (s1*z2 - s2*z1)*r;

// perform Gram-Schmidt orthogonalize for each vertex of face
// sdir - normal
tTan.i = sdir.i - rVerts[tV2.v1].i;
tTan.j = sdir.j - rVerts[tV2.v1].j;
tTan.k = sdir.k - rVerts[tV2.v1].k;
// dot(normal, sdir)
NdotT = (rVerts[tV2.v1].i * sdir.i) + (rVerts[tV2.v1].j * sdir.j)
+ (rVerts[tV2.v1].k * sdir.k);
// (sdir - n)*NdotT
tTan.i *= NdotT;
tTan.j *= NdotT;
tTan.k *= NdotT;

// normalize
tTan.i /= sqrtf((tTan.i * tTan.i) + (tTan.j * tTan.j) + (tTan.k * tTan.k));
tTan.j /= sqrtf((tTan.i * tTan.i) + (tTan.j * tTan.j) + (tTan.k * tTan.k));
tTan.k /= sqrtf((tTan.i * tTan.i) + (tTan.j * tTan.j) + (tTan.k * tTan.k));

// normal X sdir = Bitangent
NcrossT.i = rVerts[tV2.v1].j*sdir.k - rVerts[tV2.v1].k*sdir.j;
NcrossT.j = rVerts[tV2.v1].k*sdir.i - rVerts[tV2.v1].i*sdir.k;
NcrossT.k = rVerts[tV2.v1].i*sdir.j - rVerts[tV2.v1].j*sdir.i;

// dot(bitangent, tdir)
BdotT = (NcrossT.i * tdir.i) + (NcrossT.j * tdir.j)
+ (NcrossT.k * tdir.k);

tempTangent.s = tTan.i;
tempTangent.t = tTan.j;
tempTangent.r = tTan.k;
tempTangent.h = (BdotT < 0.0f) ? -1.0f : 1.0f; // handedness
tempTangent.vert = tV2.v1; // vertex tangetn belongs to
allTangents.push_back(tempTangent);  // add it to vector of tangents
// which come out to # of faces
// times 3 (trianlge)

// repeat the code above for the other two vertices

triIndex++;
}

// for each face (each index points to 3 vertices to make on face)
triIndex = std::vector<GEOM_INDEX>::size_type(0);
while(triIndex < index.size()){
GEOM_INDEX tV2 = index[triIndex];
int tanCount;

std::vector<TANGENT> tempTan;
std::vector<TANGENT>::size_type aTans;

// rVerts[iterator].h was set to -2.0 since handedness can't equal anything
// other then 1.0 or 1.0, so if the vertex's tangent wasn't computed,
// compute it
if(rVerts[tV2.v1].h == -2.0f){
// reset variavles
tempTangent.s = 0.0f;
tempTangent.t = 0.0f;
tempTangent.r = 0.0f;
tempTangent.h = -1.0f;
//tempTangent.vert = -1.0f;
tempTan.clear();
aTans = std::vector<TANGENT>::size_type(0);
tanCount = 0;

// search through vector for all tangents that belong to the current vertex
while(aTans < allTangents.size()){
TANGENT tT = allTangents[aTans];
// if the index numbers match, add it to the vector used to average
// the tangents
if(tT.vert == tV2.v1)
tempTan.push_back(tT);
aTans++;
}

// for all of the tangents of the vertex...
aTans = std::vector<TANGENT>::size_type(0);
for(aTans = 0; aTans <  tempTan.size(); aTans++){
tempTangent.s += tempTan[aTans].s;
tempTangent.t += tempTan[aTans].t;
tempTangent.r += tempTan[aTans].r;
// um, not sure if this is right :S
tempTangent.h *= tempTan[aTans].h;
tanCount++; // keep count of the number of tangents
}

// average the components
tempTangent.s /= float(tanCount);
tempTangent.t /= float(tanCount);
tempTangent.r /= float(tanCount);

// set the current vertex's tangent info
rVerts[tV2.v1].s = tempTangent.s;
rVerts[tV2.v1].t = tempTangent.t;
rVerts[tV2.v1].r = tempTangent.r;
rVerts[tV2.v1].h = tempTangent.h;
}

// same as above for the other 2 vertices would go here

triIndex++;
}
}


Sorry for the lack of vector classes. I then pass those tangents in the vertex array via GL_TEXTURE_COORD_ARRAY. Then, in the vertex shader, I calculate the bitangent, multipling it by the handedness. In the fragment shader, I use the normal map as the normal of the fragment. My shader code (note: code taken from an online tutorial and modified): Vert shader:
varying vec4 lightDir;
varying vec3 normal, halfVector, spotDir;

void main()
{
vec3 tempLight;
// computing TBN matrix for tangent space ****************************************************
vec3 v_Normal = normalize(gl_NormalMatrix*gl_Normal); // normal to eye space
vec3 v_Tangent = normalize(gl_NormalMatrix*gl_MultiTexCoord7.xyz); // tangent to eye space
vec3 v_Binormal = cross(v_Normal, v_Tangent) * gl_MultiTexCoord7.w; // binormal to eye space

mat3 tangentBasis = mat3( // in column major order
v_Tangent.x, v_Binormal.x, v_Normal.x,
v_Tangent.y, v_Binormal.y, v_Normal.y,
v_Tangent.z, v_Binormal.z, v_Normal.z);

// compute light vector ***********************************************************************
vec4 ecPos, bb;
vec3 aux;

ecPos = gl_ModelViewMatrix * gl_Vertex;
aux = vec3(gl_LightSource[1].position-ecPos);
tempLight = aux;

// compute normal and half vector **************************************************************
normal = normalize(gl_NormalMatrix * gl_Normal);// vertex to eye coordinates
halfVector = normalize(gl_LightSource[1].halfVector.xyz);

// convert coordinates to tangent space ********************************************************
tempLight = tangentBasis * tempLight;
halfVector = tangentBasis * halfVector;
spotDir = tangentBasis * gl_LightSource[1].spotDirection;

// pass texture coords to fragment shader ******************************************************
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;

// putting distance in w component of light ****************************************************
lightDir = vec4(tempLight, 0.0);
lightDir.w = length(aux);

// convert vertex position *********************************************************************
gl_Position = ftransform();
}


varying vec4 lightDir;
varying vec3 normal, halfVector, spotDir;

uniform sampler2D tex;
uniform sampler2D norm;

void main()
{
vec3 n,l,halfV;
vec4 texel;
float NdotL,NdotHV;
float att;
float spotEffect;
float dist;

// retrieve material parameters ***************************************************************
vec4 color = gl_FrontLightModelProduct.sceneColor;
vec4 ambient = gl_FrontLightProduct[1].ambient;
vec4 diffuse = gl_FrontLightProduct[1].diffuse;
vec4 specular = gl_FrontLightProduct[1].specular;

// compute normals from normal map ************************************************************
vec2 tuv = vec2(gl_TexCoord[1].s, gl_TexCoord[1].t);
n = 2.0 * (texture2D(norm, tuv).rgb - 0.5);
n = normalize(n);
//n = normalize(normal);

// compute light ******************************************************************************
l = normalize(lightDir.xyz);
dist = lightDir.w;

NdotL = max(dot(n,l),0.0);

if (NdotL > 0.0)
{
spotEffect = dot(normalize(spotDir), normalize(-l));
if (spotEffect > gl_LightSource[1].spotCosCutoff)
{
spotEffect = pow(spotEffect, gl_LightSource[1].spotExponent);
att = spotEffect / (gl_LightSource[1].constantAttenuation +
gl_LightSource[1].linearAttenuation * dist +

color += att * (diffuse * NdotL + ambient);

halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += att * specular * pow(NdotHV, gl_FrontMaterial.shininess);
}
}

// apply texture ******************************************************************************
texel = texture2D(tex,gl_TexCoord[0].st);
color *= texel;

// set fragment color *************************************************************************
gl_FragColor = color;
}


The result is that the entire object is tinted blue; there is no bump; on a cube object, only 2 faces of the six light up, and before those two faces light up, there is a flicker or black snow when it gets to a certain angle. Other objects also light wierdly. Here are some examples: note: the light stays in the same postion of (-3.0, 4.0, -5.0) http://img.photobucket.com/albums/v296/dante4016/cube1.jpg http://img.photobucket.com/albums/v296/dante4016/cube2.jpg http://img.photobucket.com/albums/v296/dante4016/octo.jpg http://img.photobucket.com/albums/v296/dante4016/sphere.jpg The yellow and magenta bars you see are just from photoshop; don't know why it does that sometimes. One more thing is that when I don't multiple the bitangent by the handedness, the same thing happens except I don't get the black snow flicker, it just lights up the entire face in one frame or so. Being that the shader is from a tutorial, I think the problem lies in the tangent code (very sorry that it's a bit messy), but I'm not sure where. Any ideas what the problem could be?

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 10
• 11
• 13
• 9
• 11
• ### Forum Statistics

• Total Topics
634090
• Total Posts
3015432
×