Erstens gibt es für jeden 3D-Scheitelpunkt unendlich viele Tangenten- und Bi-Tangentenvektoren. Das folgende Bild erklärt, warum es für jeden Scheitelpunkt unendlich viele Tangentenräume gibt. Tangente und Bitangente können in der gezeigten Ebene eine beliebige Richtung haben.
Also, um die nützlichste 1 richtig zu berechnen Tangentenraum , möchten wir, dass unser Tangentenraum so ausgerichtet wird, dass die x-Achse (die Tangente) der u-Richtung in der Bump-Map und die y-Achse (Bitangens) der v-Richtung entspricht In der Bump-Map sollten wir bereits eine Normalen des Scheitelpunkts haben, die bereits der Z-Richtung im Tangentenraum entspricht.
(1) am nützlichsten, weil wir am Ende wollen, dass normale Vektoren aus der Textur abgetastet werden
Das lässt sich am besten mit Bildern erklären, wir wollen unseren Tangentenraum wie (u, v)
unten gezeigt ausgerichtet wird.
Quelle des Bildes, obwohl nicht eng mit Computergrafik verbunden
In der Computergrafik verwenden Entwickler normalerweise (u,v)
auch Texturkoordinaten. Wir nehmen an, dass T die Tangente und B die Bitangente ist und P0
unser Zielscheitelpunkt ist, der Teil des Dreiecks ist(P0,P1,P2)
.
Denken Sie zunächst daran, was wir tun wollten, ist, Tangente und Bitanget zu berechnen, die:
- T ausgerichtet mit u und B ausgerichtet mit v.
- T und B liegen in der Ebene mit der Scheitelpunktnormalen (der im obigen Bild gezeigten Ebene).
Der Punkt ist, dass wir bereits angenommen haben, dass T und B in derselben Ebene liegen und jetzt U und V entsprechen. Wenn wir ihre Werte kennen, können wir das Produkt und den dritten Vektor kreuzen, um eine Transformationsmatrix von der Welt zum Tangentenraum zu konstruieren.
Vorausgesetzt, wir wissen, dass jeder 2D-Vektor als lineare Kombination zweier unabhängiger Vektoren 2 geschrieben werden kann und da wir bereits die im obigen Bild gezeigten Dreieckspunkte (Kanten) haben. Wir können schreiben:
E1 = (u1-u0) T + (v1-v0) B.
E2 = (u2-u0) T + (v2-v0) B.
(2) Auf diese Weise wird die Basismatrix abgeleitet
Die obige Gleichung kann in einer Matrixform geschrieben werden,
| E1x E1y E1z | | deltaU1 deltaV1 | * | Tx Ty Tz |
| E2x E2y E2z | = | deltaU2 deltaV2 | | Bx By Bz |
Durch Lösen der Matrixgleichung können wir T- und B-Werte bestimmen und eine Transformationsmatrix erstellen.
Der vollständige Quellcode in C ++
#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;
}
Den vollständigen Quellcode und die Ableitung finden Sie hier .