Jump to content
  • Advertisement
Sign in to follow this  

Tangent Space Mayhem

This topic is 4626 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

reading through tons of tutorials and sample code i tried everything but that stupid Tangent Space Matrix (TBN) does simply not work and i have no clue why. the current thing i have does this: (vertex program)
# compute the 3x3 transform from tangent space to object space ## matObjTan1 = normal % tangent; XPD matObjTan1.xyz, vertex.normal, vertex.texcoord[1]; ## matObjTan2 = normal; (alias) ## matObjTan0 = matObjTan1 % normal; XPD matObjTan0.xyz, matObjTan1, vertex.normal;
both the incoming normal and tangent are |x|=1 . my problem is that still it seems to not work. as trial-and-error gave me no solution i need somebody to give me a hint. thus what is true? 1) my code is correct (hence the error is somewhere else) 2) my code is not correct (hence what is wrong with it?) EDIT: my major problem here is also understanding the matrix. in this tutorial (http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.php) they use the 'inverse TBN', which i think i have here too, but they have 'negated' values in the matrix. reproducing those negated values though it looks even worse. i'm all out of ideas on this one, really.

Share this post

Link to post
Share on other sites
nice try but that is not my problem. mirrored UVs do not seem to be a problem for me as i wrote a special 'file format' to deal with this in a very easy (for both coder and artist) way.

my problem is that using the shader i get strange lighting problems.

as you can see the tangent seems to be mal-used. the normals and the lighting equations are all ok. if i render only with normals not using normal-mapping and TBN it looks ok (as ok as it can look with gourad shading only). using TBN and company things are broken.

RANT: i hate that this page has no IMAGE-TAGS!!!

Share this post

Link to post
Share on other sites
maybe there is problem in ur model's vertices or maybe there is problem in ur calculating the normals ...
try simple modle like sphere .

Share this post

Link to post
Share on other sites
Hm... First of all I want to compliment you on the image. Looks quite good, even with a few errant normals!

Second, are you orthogonalizing the tangents with the normal? I got similar artifacts when I disabled orthogonalization in my code.

//Orthoganalize the vectors
cVect3 tmpTan = curVert.tangent;
cVect3 tmpNorm = curVert.normal;
cVect3 tmpBitan = curVert.bitangent;

cVect3 newT = tmpTan - ( tmpNorm * tmpNorm.Dot(tmpTan) );
cVect3 newB = tmpBitan - ( tmpNorm * tmpNorm.Dot(tmpBitan) ) - ( newT * newT.Dot(tmpBitan) );


curVert.tangent = newT;
curVert.bitangent = newB;

Share this post

Link to post
Share on other sites
@all: nope, the normals are ok. turning on normal/tangent display shows both normals and tangents are perfect. furthermore i said that with normals only things look like they should (with normals only). hence i am 100% sure the normals are not the problem

@Toji: thx for the flowers... but there is more wrong with the graphics than just the tangent-problem (namely, shadow-volumes still create lot of troubles).

what i do is the following.

for my model i calculate on each frame (i don't know if 'skinning' normals/tangents is that much of a good idea speed wise) a face tangent and normals (normals are indexed in the face corners and not the same as positions). those normals and tangents are then normalized. i checked them beeing ok with graphical output not shown on the image and they are perfect.

the face tangent is calculated using (i think the same forumale you use) using a formula from this page with a slight alteration (which deals with the 'mirroring' problem).

now for the corners this yields a normal/tangent pair which is not necessary orthogonal, hence i orthogonalize them in my vertex-shader (to not waste CPU time on this one).

in general the algorithme seems to work as the terrain patches (the wall and ground) do look ok and have the normal-maps working. for those patches i use the same approach for calculating the tangents as for my objects.

now what i don't get is though why the output looks so crappy. if you look closely you see that the foot is outside the light range (ground is only ambient light), but still receives nearly full light strength at some places. so far i have seen this phenomena only if the TBN matrix is not normalized, but this is what i don't get. my input normal and tanget are both normalized and crossing them should yield again vectors of unit length. i also normalized the matrix explecitly afterwards and still have the same effect.

my vertex-program does this (beware, comments are old and off at some places).

# OpenGL Graphic Module Vertex Program
# Copyright (C) 2004, Plüss Roland ( roland@rptd.dnsalias.net )
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# input data
ATTRIB inPos = vertex.position; # position object space
ATTRIB inColor = vertex.color.primary; # white (+ alpha)
ATTRIB inTexPos = vertex.texcoord[0]; # texture coordinates
ATTRIB inNormal = vertex.normal; # face normal object space
ATTRIB inTangent = vertex.texcoord[1]; # face tangent in object space

# output data
OUTPUT outHPos = result.position; # homogenous position
OUTPUT outColor = result.color.front.primary; # color * (ambient + emissive)
OUTPUT outTexPos = result.texcoord[0]; # texture coordinates
OUTPUT outLightDir = result.texcoord[1]; # light-pos tangent space
OUTPUT outHalfDir = result.texcoord[2]; # half(lightdir+eye-pos) tangent space
OUTPUT outAtten = result.texcoord[3]; # attenuation

# constants
# eye
PARAM pEyePos = program.local[0]; # eye position in object space
# light
PARAM pLightPos = program.local[1]; # object space
PARAM pLightDir = program.local[2]; # object space
PARAM pLightColor = program.local[3];
PARAM pLightOptions = program.local[4]; # type, power, cutoff, spotexp

# opengl states
PARAM pMatTex1[4] = { state.matrix.texture[0] };
PARAM pMatMVP[4] = { state.matrix.mvp };

# variables
TEMP matObjTan0, matObjTan1, lightDir, t1, t2;
ATTRIB matObjTan2 = vertex.normal;

# calculate texture coordinates
## outTexPos = oglMatTex1 * inTexPos
DPH outTexPos.x, inTexPos, pMatTex1[0];
DPH outTexPos.y, inTexPos, pMatTex1[1];

# color is in_color
## outColor = inColor;
MOV outColor, inColor;

# compute the 3x3 transform from tangent space to object space
## matObjTan1 = normal % tangent;
XPD matObjTan1.xyz, vertex.normal, vertex.texcoord[1];
## matObjTan2 = normal; (alias)
## matObjTan0 = matObjTan1 % normal;
XPD matObjTan0.xyz, matObjTan1, vertex.normal;

# calculate light vector
## outLightDir.xyz = matObjTan * (lightPos - inPos).xyz;
SUB t1, pLightPos, inPos;
DP3 lightDir.x, matObjTan0, t1;
DP3 lightDir.y, matObjTan1, t1;
DP3 lightDir.z, matObjTan2, t1;
MOV outLightDir, lightDir;
DP3 lightDir.w, lightDir, lightDir;
MOV outAtten.x, lightDir.w;
RSQ lightDir.w, lightDir.w;
MUL lightDir.xyz, lightDir, lightDir.w;

# half light-view vector
## outHalfDir.xyz = ( outLightDir.xyz + (matObjTan * (eyePos.xyz-inPos.xyz) ) * 0.5;
SUB t1, pEyePos, inPos;
DP3 t2.x, matObjTan0, t1;
DP3 t2.y, matObjTan1, t1;
DP3 t2.z, matObjTan2, t1;
DP3 t2.w, t2, t2;
RSQ t2.w, t2.w;
MAD t1.xyz, t2, t2.w, lightDir;
MUL outHalfDir.xyz, t1, 0.5;

# attenuation
## outAtten.x = outLightDir.xyz * outLightDir.xyz;
# done above

# transform the vertex with the matrix
## outHPos = oglMatProj * (oglMatMdl * inPos);
DPH outHPos.x, inPos, pMatMVP[0];
DPH outHPos.y, inPos, pMatMVP[1];
DPH outHPos.z, inPos, pMatMVP[2];
DPH outHPos.w, inPos, pMatMVP[3];

# end of program

Share this post

Link to post
Share on other sites
Your tangents must be well conditioned across the triangle surface. This means that across any edge of a triangle, your tangent should not change direction very drastically (within a couple of degrees eg. 10-30 is normally fine)

A good way to visually inspect this is to render your tangents at each vertex as lines (as you would do with normals) and inspect the areas that are giving you problems. You will probably find cases where 2 neighbouring verts have wildly varying tangents.

Hope that helps...

Share this post

Link to post
Share on other sites
i rendered with normal/tangents shown and in the the problem areas outlined the tangents are (after normalizing) less than 1° apart from each other. i don't think that's the problem.

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!