Tangent Space Calculation in Vertex Shader

I’ve spent a fair amount of time fully understanding what the tangent space is good for and how it is calculated. I recently stumbled across a really decent paper [IPMwSI] explaining it in an excellent way.



After getting the basics finally right I looked at the way jME implements it and was a bit shocked to find it implemented wrong. The idea of the tangent space is to have two tangents pointing at the same directions as the texture coordinates. In order to have less vertex attributes the normal can be calculated as dot product of tangent and binormal. Though that only works if the object does not utilize mirrored textures. If it does use mirrored textures one must specify all three vectors as attributes: normal, tangend and bitangent.



Now I found that the normalmapping example does it the other way. It specifies the normal and tangent and calculates the binormal via the dot product.



http://jmonkeyengine.googlecode.com/svn/trunk/src/jmetest/data/images/normalmap.vert



/* Calculate tangent info - stored in colorbuffer */
vec3 normal = gl_NormalMatrix * gl_Normal;
vec3 tangent = gl_NormalMatrix * (gl_Color.xyz*2.0-1.0);
vec3 binormal = cross( normal, tangent );



I find this disturbing as this only works for texture mapping where the tangent and binormal are at 90 degrees to each other. This is bound to break with texture mappings of objects that are not as simple as a cube. I guess that's the reason why the poles of the sphere look really weird in the normal mapping example.

Computing Tangent Space Basis Vectors for an Arbitrary Mesh



Sorry. I don't have enough time to read the article you suggested.

But according to the article I found, it says

"It is not necessarily true that the tangent vectors are perpendicular to each other or to the normal vector, so the inverse of this matrix is not generally equal to its transpose. It is safe to assume, however, that the three vectors will at least be close to orthogonal, so using the Gram-Schmidt algorithm to orthogonalize them should not cause any unacceptable distortions."

So the shader would show acceptable result.

I'm using the shader for complex object like person model.

You're right. A sanely modeled object usually has texture coordinates that are close to orthogonal.



Though I find it limiting that it only allows right handed tangent spaces (no mirrored textures). I'm currently trying to render a model that utilizes mirrored textures so I can't calculate the Binormal in the shader and have to use a separate buffer for the Binormals.



For those who ever happen to stuble across this thread when looking for information about tangent space calculation:



(1) The vectors defining the tangent space - normal, tangent, binormal - are not neccesarily perpendicular to each other.

(2) It's usually safe to assume so, as texture mapping with non-perpendicular tangent and bitangent is very uncommon.

(3) With a mirrored textures the binormal can't be deduced by "normal x tangent". One has to provide a binormal vertex attribute or a vertex attribute telling the shader wether to create a binormal for a left- or right-handed coordinate system.



My best bet is that a separate vertex attribute for the bintangent is the most efficient way and besides it will also work for tangent spaces that are constructed by non orthogonal normal, tangent and binormal vectors.

Thank you for the information. :slight_smile:

Actually I had some trouble while using mirrored texture and normal map.

I didn't know why it happened and just modified texture coordinate to fix it.