Fragen zu Tangent-Space bei Normal-Mapping
-
Wie gehe ich beim Normal-Mapping im Tangent-Space vor?
Ich habe ein Beispiel gesehen, wo im Vertexshader aus Normale, Tangente und Binormale im Weltkoordinatensystem eine Drehmatrix gebastelt wird, um Lichtrichtung und Blickrichtung ins Tangentenkoordinatensystem zu bringen. Diese werden dann interpoliert im Fragmentshader verwendet.
Ist diese Interpolation korrekt?
Es ändert sich zwischen den Vertices ja die Blickrichtung und die Lichtrichtung im Weltkoordinatensystem und die Drehmatrix. Somit ändern sich ja zwei Faktoren für Lichtrichtung und Blickrichtung im Tangentenkoordinatensystem, weswegen die Interpolation ja falsch sein könnte.Die zweite Frage ist, wie berechne ich die Tangente(soll in Richtung der 1. Texturkoordinate sein)?
Relativ einfach erhalte ich den Vektor, welcher in der Dreiecksebene liegt. Wenn ich die Flächennormale verwenden würde, wäre das in Ordnung.
Aber da ich geglättete Normalen verwende, stehen diese nicht normal auf das Dreieck. Somit muss ich die berechnete Tangente noch verändern.Wie erhalte ich am besten eine normal auf die Normale stehende in Richtung der 1. Texturkoordinate zeigende Tangente?
-
Zu Frage 1: Diese Interpolation scheint korrekt zu sein.
So sieht mein Vertexshader fürs Normalmapping aus:
attribute vec3 tangent; //The inverse tangent to the geometry
attribute vec3 binormal; //The inverse binormal to the geometry
varying vec4 passcolor; //The vertex color passed
varying vec3 LightDirTangent; //The transformed light direction, to pass to the fragment shadervarying vec4 diffuse,ambientGlobal,ambient;
varying vec3 halfVector,lightDir,normal;
varying float dist;void main()
{
vec4 ecPos;
vec3 aux;normal = normalize(gl_NormalMatrix * gl_Normal);
passcolor = gl_Color; //Put the color in a varying variable
gl_Position = ftransform(); //Put the vertex in the position passed
mat3 rotmat = mat3(tangent,binormal,gl_Normal); //Construct a 3x3 matrix from the geometry’s inverse tangent, binormal, and normalecPos = gl_ModelViewMatrix * gl_Vertex;
aux = vec3(gl_LightSource[0].position - ecPos);
lightDir = normalize(aux);dist = length(aux);
halfVector = normalize(gl_LightSource[0].halfVector.xyz);
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;/* Compute the diffuse, ambient and globalAmbient terms /
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;/ The ambient terms have been separated since one of them suffers attenuation*/
ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;LightDirTangent = gl_NormalMatrix * rotmat * normalize(aux); //Rotate the light into tangent space
LightDirTangent=normalize(LightDirTangent); //Normalize the light
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; //Use the first set of texture coordinates in the fragment shader
}Zu Frage 2:
Ich berechne die Normal-, Tangent- und Binormalvektoren für jeden Vertex so, indem ich ERST für jedes Dreieck die Vektoren N,T,B berechne, dann interpoliere ich alle 3 Vektoren mit den Nachbardreiecken.
So berechne ich die N,T,B-Vektoren für mein Dreieck(V[0] bis V[2] sind die Eckpunkte)
int i = 0;
// Calculate the index to the right and left of the current index
int nNextIndex = (i + 1) % 3;
int nPrevIndex = (i + 2) % 3;// Calculate the vectors from the current vertex to the two other vertices in the triangle
Vektor v2v1 = V[1].pos - V[0].pos;
Vektor v3v1 = V[2].pos - V[0].pos;// The equation presented in the article states that:
// c2c1_T = V2.texcoord.x – V1.texcoord.x
// c2c1_B = V2.texcoord.y – V1.texcoord.y
// c3c1_T = V3.texcoord.x – V1.texcoord.x
// c3c1_B = V3.texcoord.y – V1.texcoord.y// Calculate c2c1_T and c2c1_B
float c2c1_T = V[1].texcoordU - V[0].texcoordU;
float c2c1_B = V[1].texcoordV - V[0].texcoordV;// Calculate c3c1_T and c3c1_B
float c3c1_T = V[2].texcoordU - V[0].texcoordU;
float c3c1_B = V[2].texcoordV - V[0].texcoordV;float fDenominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B;
if (Math.Round(fDenominator) == 0.0f)
{
// We won't risk a divide by zero, so set the tangent matrix to the identity matrix
tTangent = new Vektor(1, 0, 0);
bTangent = new Vektor(0, 1, 0);
nTangent = new Vektor(0, 0, 1);
}
else
{
// Calculate the reciprocal value once and for all (to achieve speed)
float fScale1 = 1.0f / fDenominator;// T and B are calculated just as the equation in the article states
Vektor T, B, N;
T = new Vektor((c3c1_B * v2v1.x - c2c1_B * v3v1.x) * fScale1,
(c3c1_B * v2v1.y - c2c1_B * v3v1.y) * fScale1,
(c3c1_B * v2v1.z - c2c1_B * v3v1.z) * fScale1);B = new Vektor((-c3c1_T * v2v1.x + c2c1_T * v3v1.x) * fScale1,
(-c3c1_T * v2v1.y + c2c1_T * v3v1.y) * fScale1,
(-c3c1_T * v2v1.z + c2c1_T * v3v1.z) * fScale1);// The normal N is calculated as the cross product between T and B
N = Vektor.Kreuzprodukt(T, B);
// Calculate the reciprocal value once and for all (to achieve speed)
float fScale2 = 1.0f / ((T.x * B.y * N.z - T.z * B.y * N.x) +
(B.x * N.y * T.z - B.z * N.y * T.x) +
(N.x * T.y * B.z - N.z * T.y * B.x));// Calculate the inverse if the TBN matrix using the formula described in the article.
// We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix
tTangent.x = Vektor.Kreuzprodukt(B, N).x * fScale2;
tTangent.y = -Vektor.Kreuzprodukt(N, T).x * fScale2;
tTangent.z = Vektor.Kreuzprodukt(T, B).x * fScale2;
tTangent = Vektor.Normiere(tTangent);bTangent.x = -Vektor.Kreuzprodukt(B, N).y * fScale2;
bTangent.y = Vektor.Kreuzprodukt(N, T).y * fScale2;
bTangent.z = -Vektor.Kreuzprodukt(T, B).y * fScale2;
bTangent = Vektor.Normiere(bTangent);nTangent.x = Vektor.Kreuzprodukt(B, N).z * fScale2;
nTangent.y = -Vektor.Kreuzprodukt(N, T).z * fScale2;
nTangent.z = Vektor.Kreuzprodukt(T, B).z * fScale2;
nTangent = Vektor.Normiere(nTangent);Geht das so?