Wie man Tangenten- und Bitangensvektoren berechnet

9

Ich habe eine Textur in three.js geladen und dann an die Shader übergeben. Im Vertex-Shader berechne ich die Normalen und speichere den UV-Vektor in einer Variablen.

<script id="vertexShader" type="x-shader/x-vertex">

                varying vec3 N,P;
                varying vec2 UV;

                void main() {
                    gl_Position= projectionMatrix * modelViewMatrix * vec4(position,1.0);
                    P= position;
                    N= normalMatrix * vec3(normal);
                    UV= uv;
                }
            </script>
            <script id="fragmentShader" type="x-shader/x-fragment">

                varying vec3 N,P;
                varying vec2 UV;
                uniform sampler2D texture;

                void main() {
                    gl_FragColor= texture2D(texture,UV);
                }

            </script>

Wie berechne ich die T- und B-Vektoren?

Ramy Al Zuhouri
quelle
2
Möchten Sie den Algorithmus allgemein oder speziell für die Bibliothek Ihrer Wahl?
Konzept3d
Wenn ich es mit three.js berechnen kann, wäre es besser.
Ramy Al Zuhouri

Antworten:

26

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.

Unendlich viele Tangettenräume für jeden Scheitelpunkt

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.

Geben Sie hier die Bildbeschreibung ein

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 P0unser 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:

  1. T ausgerichtet mit u und B ausgerichtet mit v.
  2. 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.

Geben Sie hier die Bildbeschreibung ein

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 .

concept3d
quelle
Was ist, wenn ich kein Dreieck habe? In meinem Fall habe ich eine Textur, die auf eine Kugel angewendet werden sollte. Wie kann man es an diesen Fall anpassen?
Ramy Al Zuhouri
@ RamyAlZuhouri ist die Kugel nicht aus Dreiecken aufgebaut? Sie durchlaufen einfach die Eckpunkte wie im Code. Wenn Ihre Kugel nicht auf Dreiecken basiert, ist das eine ganz andere Geschichte.
Konzept3d
Ich verwende three.js SphereGeometry (in Javascript). Vielleicht sollte ich das Gesichtseigentum an die Shader weitergeben? Die Kugel, die ich zeichne, hat 1089 Eckpunkte und 1084 Flächen.
Ramy Al Zuhouri
1
Sie berechnen den Tangentenraum und übergeben die Tangenten dann an die Shader. Und Sie sollten Zugriff auf Flächen / Eckpunkte haben, um den Tangentenraum zu berechnen.
Konzept3d
In meinem Fall habe ich 1084 Tangenten. Wie ordne ich die Tangenten den Eckpunkten zu?
Ramy Al Zuhouri