Come calcolare i vettori tangenti e bitangenti


9

Ho una trama caricata in three.js, quindi passata agli shader. Nello shader di vertice computo il normale e salvo in una variabile il vettore uv.

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

Come calcolo i vettori T e B?


2
vuoi l'algoritmo in generale o specificamente per la tua libreria preferita?
concept3d

Se riesco a calcolarlo con three.js, sarebbe meglio.
Ramy Al Zuhouri,

Risposte:


26

Prima di tutto, per ogni vertice 3D vi sono infiniti vettori tangenti e bi-tangenti. L'immagine seguente spiega perché esiste un numero infinito di spazi tangenti per ciascun vertice, la tangente e il bitangente possono avere qualsiasi direzione nel piano mostrato.

Numero infinito di spazi tanget per ciascun vertice

Quindi, per calcolare correttamente il più utile 1 spazio tangente , vogliamo che il nostro spazio tangente sia allineato in modo tale che l'asse x (la tangente) corrisponda alla direzione u nella mappa di rilievo e l'asse y (bitangente) corrisponda alla direzione v nella bump map, dovremmo già avere un normale del vertice che corrisponde già alla direzione Z nello spazio tangente.

(1) più utile perché alla fine vogliamo che i vettori normali vengano campionati dalla trama

Che sia meglio spiegato con le immagini, vogliamo che il nostro spazio tangente sia allineato come (u, v)mostrato di seguito.

inserisci qui la descrizione dell'immagine

Fonte dell'immagine sebbene non strettamente correlata alla computer grafica

In genere gli sviluppatori di grafica per computer usano (u,v)anche le coordinate di trama. Supponiamo che T sia la tangente e B sia il bitangente, ed P0è il nostro vertice bersaglio, che fa parte del triangolo(P0,P1,P2) .

Per prima cosa ricorda cosa volevamo fare, è calcolare tangente e bitanget che:

  1. T allineato con ue B allineato con v.
  2. T e B si trovano sul piano con il vertice normale (il piano mostrato nell'immagine sopra).

Il punto è che abbiamo già ipotizzato che T e B giacciono sullo stesso piano e corrispondano a U e V ora se possiamo conoscere i loro valori possiamo incrociare il prodotto e il terzo vettore per costruire una matrice di trasformazione dal mondo allo spazio tangente.

inserisci qui la descrizione dell'immagine

Dato che sappiamo che qualsiasi vettore 2D può essere scritto come una combinazione lineare di due vettori indipendenti 2 e poiché abbiamo già i punti del triangolo (bordi), mostrati nell'immagine sopra. Possiamo scrivere:

E1 = (u1-u0) T + (v1-v0) B

E2 = (u2-u0) T + (v2-v0) B

(2) in realtà è così che viene derivata la matrice di base

L'equazione di cui sopra può essere scritta in forma di matrice,

| E1x E1y E1z |   | deltaU1 deltaV1 | * | Tx Ty Tz |
| E2x E2y E2z | = | deltaU2 deltaV2 |   | Bx By Bz |

Risolvendo l'equazione delle matrici possiamo determinare i valori T e B e possiamo costruire una matrice di trasformazione.

Il codice sorgente completo 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;
}

Il codice sorgente completo e la derivazione sono disponibili qui .


E se non avessi un triangolo? Nel mio caso ho una trama che dovrebbe essere applicata su una sfera. Come adattarlo a questo caso?
Ramy Al Zuhouri,

@RamyAlZuhouri non è la sfera costruita dai triangoli? Basta passare sopra i vertici come nel codice. Se la tua sfera non è basata sul triangolo, questa è una storia completamente diversa.
concept3d

Sto usando three.js SphereGeometry (in javascript). Forse dovrei passare la proprietà del viso agli shader? La sfera che disegno ha 1089 vertici e 1084 facce.
Ramy Al Zuhouri,

1
calcoli lo spazio tangente e poi passi le tangenti agli shader. E dovresti avere accesso a faccia / vertici per calcolare lo spazio tangente.
concept3d

Nel mio caso avrò 1084 tangenti, come posso mappare le tangenti con i vertici?
Ramy Al Zuhouri,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.