Computing tangents

Started by
16 comments, last by cignox1 17 years, 10 months ago
From what I understood, in order to do normal map bump mapping I need to build up the inverse of the TBN (orthonormal, so this is easy), use it to transform the light position and then apply the lighting equation. To compute the TBN I need normal, tangent and bitangent vectors, then in the vertex shader I transform them with modelview matrix and build the transpose of the TBN. I can calculate the bitangent multiplying the normal and the tangent in the shader. My question is, how do I compute the tangent in the first place? Normals are easy, but what about tangents? Thank you! [edit: fixed your thread title. -Superpig]
Advertisement
Do not forget that TBN(Tangent,Binormal,and Normal)represents the X,Y,Z as Orthonormal which means 90 degree apart. So based on that information in order to get The Tangent you can do Binormal Cross Normal. If you are using D3D you can also used the D3DXCreateTangent to Calculate your TBN. Once i get that calculate it i do in the Vertex Shader/Pixel Shader like so.
float4x4 WorldView;float4x4 WorldViewProjection;float4x4 World;float4 lposition={0,0,1.0f,1.f}; //Point Lighttexture diffuse;texture normal;sampler2D diffusesampler=sampler_state{Texture=(diffuse);MinFilter=Linear;MagFilter=Linear;MipFilter=Linear;};sampler2D normalsampler=sampler_state{Texture=(normal);MinFilter=Linear;MagFilter=Linear;MipFilter=Linear;};struct VS_INPUT{float4 p:POSITION;float2 tex0:TEXCOORD0;float2 tex1:TEXCOORD1;float4 tangent:TANGENT;float4 binormal:BINORMAL;float4 normal:NORMAL;}struct VS_OUTPUT{float4 p:POSITION;float2 tex0:TEXCOORD0;float2 tex1:TEXCOORD1;float3 lhtPos:TEXCOORD2;}VS_OUTPUT BumpShader(VS_INPUT inp){VS_OUTPUT v_out=(VS_OUTPUT)0;v_out.p=mul(inp.p,WorldViewProjection);v_out.tex0=inp.tex0;v_out.tex1=inp.tex1;//Convert from local to world.float3 localvertextoworld=mul(inp.p,World);float3 ldiff= normalize (lposition-localvertextoworld);float3x3 tbnMatrix=float3x3(inp.tangent,inp.binormal,inp.normal);tbnMatrix[0]=mul(tbnMatrix[0],WorldView);tbnMatrix[1]=mul(tbnMatrix[1],WorldView);tbnMatrix[2]=mul(tbnMatrix[2],WorldView);v_out.lhtPos=mul(tbnMatrix,ldiff);v_out.lhtPos=normalize(v_out.lhtPos);}float4 BumpPixelShader(VS_OUTPUT ot){float4 d=tex2D(diffusesampler,ot.tex0);float4 n=2.0f*tex2D(normalsampler,ot.tex1).rgb-1.f;float dif=saturate(dot(n*v_out.lhtPos));return dif*d;}technique s{pass p0{Lighting=TRUE;vertexshader=compile vs_2_0 BumpShader();pixelshader=compile ps_2_0 BumpPixelShader();}}


[Edited by - BornToCode on May 7, 2006 1:37:23 PM]
Well if you use D3D you can just use the D3DXComputeTangentFrameEx() function..this is an extrememely useful function, never leave home without it :)
I dont know if OpenGl has a similar function..

Thank you, but I use opengl. I've found some code to calculate the tangent, but it's faster to understand how to code it myself than trying to figure it out whats'up in the code and then modify it to fit my needs :-)
take a look at nvMeshMender. Not only will it generate the TBN frames at each vertex, but it will fix mesh problems which can cause severe artifacts when normal mapping (such as cylindrical mappings that wrap around).
Since source code for this problem for OpenGL is easy to find (for example, check the Irrlicht sources for inspiration), I'll explain the mechanics. In general a tangent only requires to be perpendicular to the normal, so an arbitrary vector perpendicular to the normal could be chosen. The binormal then simply is cross(normal, tangent). However, since you wish to use these for bumpmapping, there are additional requirements to the tangent and binormal.

They will be used to determine the direction of the texture to properly interpret the normal values stored in the texture. This means that tangent and binormal should be alligned with the direction of the texturecoordinates. Therefore, in this context, the tangent and binormal are usually referred to as s tangent and t tangent, corresponding to the s and t texture directions the correspond to. Hence, to calulate the tangent and binormals for the 3 vertices of a bumpmapped triangle, we need the values of the 3 vertices, their respective normals and their texture coordinates.

For a more thourough explanaition and the important formulas I suggest this webpage: Bump Mapping Using CG. The part describing the theory is not specific to CG and can be applied to any shader type.

Tom
Thank you all, now I have many different implementations of the algorithm, and some more general description of it. I wil try to figure it out from them.
Thank you again!

EDIT: I've just read the article "Bump mapping using GC" and perhaps I'm able to understand things with this article. I've one question though: In the algorithm the normal is computed with a cross product between tangent and bitangent. But in the general case the normal is already there, that is the mesh already has normals (perhaps averaged among triangles sharing vertices). How should I behave in this case? Should I rotate my resulting tangent to be perpendicular to the normal? How do I perform this?
Thank you.

[Edited by - cignox1 on May 9, 2006 12:42:13 PM]
Usually you do it the other way round,
you have the normal, calculate the tangent and the bitangent is computed via the cross product.

If you use your algorithm right, you usually should get a tangent that is perpendicualar to the normal (think of the three axis of a coordinate system), pointing whitin the plane, your triangle describes, in the direction in which the s or x coordinate of your texture increases.

Hope this helps for understanding (-;
Quote:Original post by cignox1
Thank you all, now I have many different implementations of the algorithm, and some more general description of it. I wil try to figure it out from them.
Thank you again!

EDIT: I've just read the article "Bump mapping using GC" and perhaps I'm able to understand things with this article. I've one question though: In the algorithm the normal is computed with a cross product between tangent and bitangent. But in the general case the normal is already there, that is the mesh already has normals (perhaps averaged among triangles sharing vertices). How should I behave in this case? Should I rotate my resulting tangent to be perpendicular to the normal? How do I perform this?
Thank you.


Usually, generating normals works like this:
1. calculate normals for triangles
2. calculate normals per vertex for smooth shading (as yous said, often by taking the average vector of all normals of the triangles meeting in that vertex)

I believe that when also using s and t tangents, the process is similar:
1. calculate normal and s and t vectors for the triangles (s and t tangents simply being the actual directions of the texture coordinates in the plane of the triangle)
2. calculate normals, s and t tangents per vertex for smooth shading (this time getting 3 average vectors instead of 1)

If, for example, the normals come from a model file, they already went through step 1 and 2. You can then either do the calculation only for the tangents (which may or may not look weird depending on how much your algorithm for obtaining the smooth vectors differs from the one used when creating the model) or you can throw away the normals and do the entire thing yourself.

Tom
The concise description of tangent calculation is as follows:
The normal, tu, and tv axes of a surface form a coordinate basis. We require an orthonormal basis to do any kind of transformations. So by orthonormalizing these axes, we get normal, tangent, and binormal vectors that represent an orthonormal basis matrix that can be used to transform from object space to the local tangent space that our surface occupies.

Depending on how comfortable with linear algebra you are, that either makes perfect sense, or you have no idea what the hell I just said.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

This topic is closed to new replies.

Advertisement