Verwendete Vertexformate in den OpenGL-Tutorials, Vertex-Attribute für einen GLSL Vertex Shader verfügbar machen

Alle 3D-Modelle bestehen aus einer mehr oder weniger große Anzahl von Vertices. Je nach Art und Verwendungszweck müssen für einen Vertex verschiedene Daten gespeichert werden. Dazu zählen unter anderem

  • die Position (legt die Gestalt (Geometrie) eines Objekts fest), 
  • die Normale (wichtig für Beleuchtungsberechnungen) sowie 
  • die Texturkoordinaten, die für die Texturierung der Oberfläche benötigt werden.

    Hier nun eine Übersicht über die einzelnen Formate, die in unseren OpenGL-Tutorials zum Einsatz kommen.


    Vertexformate für 3D-Modelle, die pro Vertex (im Vertex Shader) beleuchtet werden sollen:

    struct CSimpleTexturedVertexWithNormal
    {
        float tu, tv;
        float NormalX, NormalY, NormalZ;
        float PosX, PosY, PosZ;
    };

    struct CSimpleTexturedVertexWithNormalExt
    {
        // Über tw könnte man bsp. die zu verwendende Textur indizieren
        float tu, tv, tw;
        float NormalX, NormalY, NormalZ;
        float PosX, PosY, PosZ;
    };


    Vertexformate für 3D-Modelle, für die keinerlei Beleuchtungsberechnungen durchgeführt werden sollen:

    struct CSimpleTexturedVertex
    {
        float tu, tv;
        float x, y, z;
    };

    struct CSimpleDoubleTexturedVertex
    {
        float tu1, tv1;
        float tu2, tv2;
        float x, y, z;
    };


    Vertexformat für 3D-Modelle, die pro Pixel (im Fragment Shader) beleuchtet werden sollen:

    struct CTexturedVertexWithNormal_NM
    {
        // Über tw könnte man bsp. den Index der zu verwendenden Textur
        // festlegen:
        float tu, tv, tw;

        // die nachfolgenden 9 Variablen sind die Elemente der
        // Transformationsmatrix (Texture Space -> Model Space):
        float Perpendicular1X, Perpendicular1Y, Perpendicular1Z;
        float Perpendicular2X, Perpendicular2Y, Perpendicular2Z;
        float NormalX, NormalY, NormalZ;

        float PosX, PosY, PosZ;
    };


    Vertexformat für animierte 3D-Modelle, die pro Pixel (im Fragment Shader) beleuchtet werden sollen:

    struct CTexturedAnimatedVertexWithNormal_NM
    {
        // Über die Parameter tw und ta wird der Vertex an
        // einen Joint gebunden. tw speichert den Index der
        // zu verwendenden Matrix für die Transformation
        // der Position, ta speichert den Index der zu verwendenden
        // Matrix für die Transformation der Normale. Alternativ könnte
        // ta auch den Index der zu verwendenden Textur speichern:
        float tu, tv, tw, ta;

        // die nachfolgenden 9 Variablen sind die Elemente der
        // Transformationsmatrix (Texture Space -> Model Space):
        float Perpendicular1X, Perpendicular1Y, Perpendicular1Z;
        float Perpendicular2X, Perpendicular2Y, Perpendicular2Z;
        float NormalX, NormalY, NormalZ;

        float PosX, PosY, PosZ;
    };


    Vertexformat für 3D-Modelle, deren Vertices bereits in den Projektionsraum transformiert sind (Buchstaben bei der Textausgabe, Screenquad, das beim Post Processing verwendet wird):

    struct CScreenVertex
    {
        float tu, tv;

        // Viewportkoordinaten:
        float x, y, z, w;
    };


    Vertexformat für 3D-Modelle, die weder texturiert noch beleuchtet werden sollen:

    struct CSimpleVertex
    {
        float x, y, z;
    };


    Damit ein Vertex Shader die zu verarbeitenden Vertexdaten eines 3D-Modells korrekt interpretieren kann, benötigt er eine Liste – eine Art Spickzettel – mit den einzelnen Vertexattributen (Texturkoordinaten, Normale, Position, usw.) und ihrer Speicherreihenfolge. Im Vertexformat CSimpleTexturedVertexWithNormal werden beispielsweise zuerst die Texturkoordinaten, dann die Vertexnormale und als drittes die Vertexposition gespeichert. In Anlehnung an ihren Verwendungszweck wird diese Liste als Vertexattribut-Array bezeichnet. Mithilfe von glVertexAttribPointer() legt man die Position (Speicheradresse) eines bestimmten Vertexattributs (z.B. die Normale) innerhalb dieses Arrays fest.
    Nach einem glEnableVertexAttribArray()-Aufruf wird das zuvor spezifizierte Vertexattribut so lange beim Rendern berücksichtigt, bis schließlich die Funktion glDisableVertexAttribArray() aufgerufen wird.
    Dank der Erweiterung GL_ARB_explicit_attrib_location lassen sich die einzelnen Vertexattribute im OpenGL-Hauptprogramm und in den verwendeten Vertex Shadern mithilfe von Semantiken (symbolische Konstanten, z.B. #define ATTR_POSITION  0) identifizieren.


    INLINE void Set_Attributes_CSimpleTexturedVertexWithNormal(void)
    {
    // Speicherbedarf pro Vertex 32 Byte (8 float-Variablen)


    // Die Texturkoordinaten befinden sich an erster Stelle im Attribut-Array.
    // Der Speicheroffset beträgt somit 0 Byte:

    glVertexAttribPointer(ATTR_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, 32, (char*)0);
    glEnableVertexAttribArray(ATTR_TEXCOORD0);

    // Die Normale befindet sich an zweiter Stelle im Attribut-Array.
    // Der Speicheroffset beträgt 8 Byte, da die ersten 8 Byte von den Textur-
    // koordinaten belegt werden:

    glVertexAttribPointer(ATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, 32, (char*)8);
    glEnableVertexAttribArray(ATTR_NORMAL);

    // Die Position befindet sich an dritter Stelle im Attribut-Array.
    // Der Speicheroffset beträgt 20 Byte, da die ersten 8 Byte von den
    // Texturkoordinaten und die zweiten 12 Byte von der Normale belegt werden:

    glVertexAttribPointer(ATTR_POSITION, 3, GL_FLOAT, GL_FALSE, 32, (char*)20);
    glEnableVertexAttribArray(ATTR_POSITION);
    }

    INLINE void Reset_Attributes_CSimpleTexturedVertexWithNormal(void)
    {
        glDisableVertexAttribArray(ATTR_TEXCOORD0);
        glDisableVertexAttribArray(ATTR_NORMAL);
        glDisableVertexAttribArray(ATTR_POSITION);
    }


    Interessante Artikel