Her şeyden önce, her 3D tepe noktası için sonsuz teğet ve iki teğet vektörler vardır. Aşağıdaki görüntü, her köşe için neden sonsuz sayıda teğet boşluğunun olduğunu açıklar, teğet ve bitanjant, gösterilen düzlemde herhangi bir yöne sahip olabilir.
Bu nedenle, en kullanışlı 1 teğet boşluğunu doğru bir şekilde hesaplamak için , teğet alanımızın x ekseni (teğet) yumru haritasındaki u yönüne ve y ekseni (bitanjant) v yönüne karşılık gelecek şekilde hizalanmasını istiyoruz yumru haritasında, teğet uzaydaki Z yönüne zaten karşılık gelen tepe noktasının normaline sahip olmalıyız.
(1) en kullanışlı çünkü sonunda normal vektörlerin dokudan örneklenmesini istiyoruz
En iyi resimlerle açıklanabilir, teğet alanımızın (u, v)
aşağıda gösterildiği gibi hizalanmasını istiyoruz .
Bilgisayar grafikleri ile tam olarak ilgili olmasa da görüntünün kaynağı
Bilgisayar grafiklerinde geliştiriciler genellikle (u,v)
doku koordinatları olarak da bilinir. T'nin tanjant olduğunu ve B'nin bitanjant P0
olduğunu ve üçgenin bir parçası olan hedef tepe noktamız olduğunu varsayacağız (P0,P1,P2)
.
Öncelikle ne yapmak istediğimizi hatırlayın, tanjant hesaplamak ve bunu iki noktadan ayırmaktır:
- T u ile hizalıdır ve B v ile hizalıdır.
- T ve B düzlemde tepe noktası normal şekilde (yukarıdaki görüntüde gösterilen düzlem) yer alır.
Mesele şu ki, T ve B'nin aynı düzlemde bulunduğunu ve şimdi U ve V'ye karşılık geldiğini varsaydık, eğer değerlerini bilebilirsek, dünyadan teğet uzaya bir dönüşüm matrisi oluşturmak için ürünü ve üçüncü vektörü geçebiliriz.
Herhangi bir 2D vektörün iki bağımsız vektörün 2 doğrusal bir kombinasyonu olarak yazılabileceğini bildiğimiz ve yukarıdaki resimde gösterildiği gibi üçgen noktalara (kenarlara) sahip olduğumuz göz önüne alındığında . Yazabiliriz:
E1 = (u1-u0) T + (v1-v0) B
E2 = (u2-u0) T + (v2-v0) B
(2) aslında temel matris böyle elde edilir
Yukarıdaki denklem bir matris biçiminde yazılabilir,
| E1x E1y E1z | | deltaU1 deltaV1 | * | Tx Ty Tz |
| E2x E2y E2z | = | deltaU2 deltaV2 | | Bx By Bz |
Matris denklemini çözerek T ve B değerlerini belirleyebiliriz, bir dönüşüm matrisi oluşturabiliriz.
C ++ 'da tam kaynak kodu
#include "Vector4D.h"
struct Triangle
{
unsigned short index[3];
};
void CalculateTangentArray(long vertexCount, const Point3D *vertex, const Vector3D *normal,
const Point2D *texcoord, long triangleCount, const Triangle *triangle, Vector4D *tangent)
{
Vector3D *tan1 = new Vector3D[vertexCount * 2];
Vector3D *tan2 = tan1 + vertexCount;
ZeroMemory(tan1, vertexCount * sizeof(Vector3D) * 2);
for (long a = 0; a < triangleCount; a++)
{
long i1 = triangle->index[0];
long i2 = triangle->index[1];
long i3 = triangle->index[2];
const Point3D& v1 = vertex[i1];
const Point3D& v2 = vertex[i2];
const Point3D& v3 = vertex[i3];
const Point2D& w1 = texcoord[i1];
const Point2D& w2 = texcoord[i2];
const Point2D& w3 = texcoord[i3];
float x1 = v2.x - v1.x;
float x2 = v3.x - v1.x;
float y1 = v2.y - v1.y;
float y2 = v3.y - v1.y;
float z1 = v2.z - v1.z;
float z2 = v3.z - v1.z;
float s1 = w2.x - w1.x;
float s2 = w3.x - w1.x;
float t1 = w2.y - w1.y;
float t2 = w3.y - w1.y;
float r = 1.0F / (s1 * t2 - s2 * t1);
Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r);
Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r);
tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;
tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;
triangle++;
}
for (long a = 0; a < vertexCount; a++)
{
const Vector3D& n = normal[a];
const Vector3D& t = tan1[a];
// Gram-Schmidt orthogonalize
tangent[a] = (t - n * Dot(n, t)).Normalize();
// Calculate handedness
tangent[a].w = (Dot(Cross(n, t), tan2[a]) < 0.0F) ? -1.0F : 1.0F;
}
delete[] tan1;
}
Tam kaynak kodu ve türetme burada bulunabilir .