Jak obliczyć wektory styczne i bitowe

9

Mam teksturę załadowaną w pliku Three.js, a następnie przekazaną do shaderów. W module cieniującym wierzchołki obliczam wartość normalną i zapisuję w zmiennej wektor 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>

Jak obliczyć wektory T i B?

Ramy Al Zuhouri
źródło
2
czy chcesz algorytm ogólnie, czy specjalnie dla wybranej biblioteki?
concept3d
Gdybym mógł to obliczyć za pomocą Three.js, byłoby lepiej.
Ramy Al Zuhouri

Odpowiedzi:

26

Przede wszystkim na każdy wierzchołek 3D przypadają nieskończone wektory styczne i dwu-styczne. Poniższy obraz wyjaśnia, dlaczego istnieje nieskończona liczba przestrzeni stycznych dla każdego wierzchołka, styczna i bitangent mogą mieć dowolny kierunek w pokazanej płaszczyźnie.

Nieskończona liczba splotów dla każdego wierzchołka

Aby właściwie obliczyć najbardziej użyteczną 1 przestrzeń styczną, chcemy, aby nasza przestrzeń styczna była wyrównana w taki sposób, aby oś x (styczna) odpowiadała kierunkowi u na mapie nierówności, a oś y (bitangent) odpowiadała kierunkowi v na mapie wypukłości powinniśmy już mieć normalną wierzchołek, który już odpowiada kierunkowi Z w przestrzeni stycznej.

(1) najbardziej przydatne, ponieważ w końcu chcemy, aby normalne wektory były próbkowane z tekstury

Najlepiej to wyjaśnić obrazami, chcemy, aby nasza przestrzeń styczna była wyrównana, jak (u, v)pokazano poniżej.

wprowadź opis zdjęcia tutaj

Źródło obrazu, choć nie jest ściśle związane z grafiką komputerową

W grafice komputerowej programiści zwykle używają (u,v)również zwanych współrzędnymi tekstury. Zakładamy, że T jest styczną, a B jest bitangentem i P0jest naszym docelowym wierzchołkiem, który jest częścią trójkąta (P0,P1,P2).

Najpierw pamiętajmy, co chcieliśmy zrobić, to obliczyć styczną i bitanget, które:

  1. T wyrównane u i B wyrównane v.
  2. T i B leżą w płaszczyźnie z wierzchołkiem normalnym (płaszczyzna pokazana na powyższym obrazku).

Chodzi o to, że już założyliśmy, że T i B leżą w tej samej płaszczyźnie i odpowiadają teraz U i V, jeśli znamy ich wartości, możemy przekroczyć iloczyn i trzeci wektor, aby skonstruować macierz transformacji ze świata do przestrzeni stycznej.

wprowadź opis zdjęcia tutaj

Biorąc pod uwagę, że wiemy, że dowolny wektor 2D można zapisać jako liniową kombinację dwóch niezależnych wektorów 2 i ponieważ mamy już punkty trójkąta (krawędzie), pokazane na powyższym obrazie. Możemy pisać:

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

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

(2) tak właśnie wyprowadza się macierz podstawową

Powyższe równanie można zapisać w postaci macierzy,

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

Rozwiązując równanie macierzowe, możemy wyznaczyć wartości T i B, możemy zbudować macierz transformacji.

Pełny kod źródłowy w 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;
}

Pełny kod źródłowy i wyprowadzenie można znaleźć tutaj .

concept3d
źródło
Co jeśli nie mam trójkąta? W moim przypadku mam teksturę, którą należy nałożyć na kulę. Jak dostosować go do tego przypadku?
Ramy Al Zuhouri
@RamyAlZuhouri nie jest budowaną kulą z trójkątów? Po prostu zapętlamy wierzchołki jak w kodzie. Jeśli twoja kula nie jest oparta na trójkącie, to zupełnie inna historia.
concept3d
Używam SphereGeometry three.js (w javascript). Może powinienem przekazać właściwość twarzy shaderom? Narysowana przeze mnie sfera ma 1089 wierzchołków i 1084 ściany.
Ramy Al Zuhouri,
1
obliczasz przestrzeń styczną, a następnie przekazujesz styczne do shaderów. I powinieneś mieć dostęp do twarzy / wierzchołków, aby obliczyć przestrzeń styczną.
concept3d
W moim przypadku będę miał 1084 stycznych, jak zmapować styczne wierzchołkami?
Ramy Al Zuhouri