Как расчитать правильный Tangent Space?
Ниже представлены два варианта просчёта Tangent Space (Пространство касательных).
Вариант 1
Вариант 2
Вариант 1
Здесь
vPosition - позиции вершин
indexes - массив индексов
vVec3Tangent - массив тангентов
vVec3Binormal - массив бинормалей
vTexCoords[0] - массив текстурных координат
void DIndexedEntity::GenerateTangent(bool genBiNor)
{
if (!VertexFormat->vec3tangent || !VertexFormat->texcoords
|| !indexCreated || !verticesCreated)
return;
D3DXVECTOR3 tangent, bitangent;
DWORD v0, v1, v2;
ZeroMemory( vVec3Tangent, CountVertices*sizeof(D3DXVECTOR3) );
if (genBiNor&&VertexFormat->vec3binormal)
ZeroMemory(vVec3Binormal,CountVertices*sizeof(D3DXVECTOR3));
for(DWORD j=0; j<(DWORD)CountFaces; j+=3)
{
if (!index32)
{
v0 = indexes[j];
v1 = indexes[j+1];
v2 = indexes[j+2];
}else{
v0 = indexes32[j];
v1 = indexes32[j+1];
v2 = indexes32[j+2];
}
D3DXVECTOR3 Q = vPosition[v2] - vPosition[v0];
D3DXVECTOR3 P = vPosition[v1] - vPosition[v0];
float s1 = vTexCoords[0][v1].x - vTexCoords[0][v0].x;
float t1 = vTexCoords[0][v1].y - vTexCoords[0][v0].y;
float s2 = vTexCoords[0][v2].x - vTexCoords[0][v0].x;
float t2 = vTexCoords[0][v2].y - vTexCoords[0][v0].y;
float tmp = 0.0f;
if(fabs(s1*t2 - s2*t1) <= 0.0001f)
{
tmp = 1.0f;
}
else
{
tmp = 1.0f/(s1*t2 - s2*t1);
}
tangent.x = (t1*Q.x - t2*P.x);
tangent.y = (t1*Q.y - t2*P.y);
tangent.z = (t1*Q.z - t2*P.z);
tangent *= tmp;
D3DXVec3Normalize (&tangent, &tangent);
vVec3Tangent[v0]+=tangent;
vVec3Tangent[v1]+=tangent;
vVec3Tangent[v2]+=tangent;
if (genBiNor&&VertexFormat->vec3binormal)
{
bitangent.x = (s1*Q.x - s2*P.x);
bitangent.y = (s1*Q.y - s2*P.y);
bitangent.z = (s1*Q.z - s2*P.z);
bitangent *= tmp;
D3DXVec3Normalize (&bitangent, &bitangent);
vVec3Binormal[v0]+=bitangent;
vVec3Binormal[v1]+=bitangent;
vVec3Binormal[v2]+=bitangent;
}
}
for(DWORD j=0; j<(DWORD)CountVertices; j++)
{
D3DXVec3Normalize(&vVec3Tangent[j],&vVec3Tangent[j]);
if (genBiNor&&VertexFormat->vec3binormal)
D3DXVec3Normalize(&vVec3Binormal[j],&vVec3Binormal[j]);
}
needUpdate=true;
}
Но даже так тангент-спейс не всегда расчитывается совсем правильно, лучше его загружать вместе с моделькой, сделанной в хорошем редакторе.
Вариант 2
Updated by Blew_zc:
void CalcTangentBasis(const vector3D &p1, const vector3D &p2, const vector3D &p3,
const vector2D &t1, const vector2D &t2, const vector2D &t3,
vector3D &tangent, vector3D &binormal )
{
vector3D e1 = p2 - p1;
vector3D e2 = p3 - p1;
vector2D et1 = t2 - t1;
vector2D et2 = t3 - t1;
tangent = 0.0f;
binormal = 0.0f;
float tmp = 0.0;
if (fabsf(et1.x*et2.y - et1.y*et2.x)<0.0001f)
tmp = 1.0f;
else
tmp = 1.0 / (et1.x*et2.y - et1.y*et2.x);
tangent = (e1 * et2.y - e2 * et1.y) * tmp;
binormal = (e2 * et1.x - e1 * et2.x) * tmp;
tangent.normalize();
binormal.normalize();
}
void CMeshes::CalcTB ()
{
for (unsigned int i=0;i<numvertices;i++)
{
Vertices [i].tangent = 0.0;
Vertices [i].binormal = 0.0;
}
for (unsigned int i=0;i<(numindices / 3);i++)
{
unsigned int a = Indices [i * 3 + 0];
unsigned int b = Indices [i * 3 + 1];
unsigned int c = Indices [i * 3 + 2];
vector3D bin, tan;
CalcTangentBasis ( Vertices [a].position,
Vertices [b].position,
Vertices [c].position,
Vertices [a].tcoord,
Vertices [b].tcoord,
Vertices [c].tcoord,
tan, bin);
Vertices [a].tangent += tan;
Vertices [b].tangent += tan;
Vertices [c].tangent += tan;
Vertices [a].binormal += bin;
Vertices [b].binormal += bin;
Vertices [c].binormal += bin;
}
for (unsigned int i=0;i<numvertices;i++)
{
Vertices [i].tangent.normalize();
Vertices [i].binormal.normalize();
vector3D tmpT = Vertices [i].tangent;
vector3D tmpB = Vertices [i].binormal;
vector3D tmpN = Vertices [i].normal;
vector3D newT = tmpT - ((tmpN & tmpT) * tmpN);
vector3D newB = tmpB - ((tmpN & tmpB) * tmpN) - ((newT & tmpB)*newT);
newT.normalize ();
newB.normalize ();
Vertices [i].tangent = newT;
Vertices [i].binormal = newB;
float lenT = newT.length ();
float lenB = newB.length ();
if (lenT <= 0.0001 || lenB <= 0.0001)
{
if (lenT > 0.5)
Vertices [i].binormal = tmpN ^ Vertices [i].tangent;
else if (lenB > 0.5)
Vertices [i].tangent = Vertices [i].binormal ^ tmpN;
else
{
vector3D xAxis (1.0, 0.0, 0.0);
vector3D yAxis (0.0, 1.0, 0.0);
vector3D startAxis;
if ((xAxis & tmpN) < (yAxis & tmpN))
startAxis = xAxis;
else
startAxis = yAxis;
Vertices [i].tangent = tmpN ^ startAxis;
Vertices [i].binormal = tmpN ^ Vertices [i].tangent;
}
}
else if ((Vertices [i].binormal & Vertices [i].tangent)> 0.9999)
Vertices [i].binormal = tmpN ^ Vertices [i].tangent;
}
}