Suche…


Grundlagen der Texturierung

Eine Textur ist eine Form der Datenspeicherung, die einen bequemen Zugriff nicht nur auf bestimmte Dateneinträge ermöglicht, sondern auch auf Punkte, die mehrere Einträge vermischen (interpolieren).

In OpenGL können Texturen für viele Zwecke verwendet werden, meistens wird jedoch ein Bild einem Polygon (z. B. einem Dreieck) zugeordnet. Um die Textur einem Dreieck (oder einem anderen Polygon) zuzuordnen, müssen wir jedem Scheitelpunkt sagen, welchem ​​Teil der Textur er entspricht. Wir weisen jedem Scheitelpunkt eines Polygons eine Texturkoordinate zu, die dann zwischen allen Fragmenten in diesem Polygon interpoliert wird. Texturkoordinaten liegen in der Regel zwischen 0 und 1 in der X- und Y-Achse, wie in der folgenden Abbildung dargestellt:

Texturkoordinaten

Die Texturkoordinaten dieses Dreiecks würden folgendermaßen aussehen:

GLfloat texCoords[] = {
    0.0f, 0.0f,  // Lower-left corner  
    1.0f, 0.0f,  // Lower-right corner
    0.5f, 1.0f   // Top-center corner
};

Setzen Sie diese Koordinaten in VBO (Vertex Buffer Object) und erstellen Sie ein neues Attribut für den Shader. Sie sollten bereits mindestens ein Attribut für die Stützpunktpositionen haben, erstellen Sie ein anderes für die Texturkoordinaten.


Textur erzeugen

Zuerst müssen Sie ein Texturobjekt generieren, auf das eine ID verweist, die in einer vorzeichenlosen int- Textur gespeichert wird:

GLuint texture;
glGenTextures(1, &texture); 

Danach muss es gebunden werden, damit alle nachfolgenden Texturbefehle diese Textur konfigurieren:

glBindTexture(GL_TEXTURE_2D, texture); 

Bild wird geladen

Um ein Image zu laden, können Sie einen eigenen Image Loader erstellen oder eine Image-Ladebibliothek wie SOIL (Simple OpenGL Image Library) in c ++ oder TWL PNGDecoder in Java verwenden.

Ein Beispiel für das Laden eines Bildes mit SOIL wäre:

int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB); 

Nun können Sie dieses Bild dem Texturobjekt zuordnen:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

Danach sollten Sie das Texturobjekt lösen:

glBindTexture(GL_TEXTURE_2D, 0); 

Umbruchparameter für Texturkoordinaten

Wie oben zu sehen ist, hat die untere linke Ecke der Textur die UV-Koordinaten (st) (0, 0) und die obere rechte Ecke der Textur die Koordinaten (1, 1), aber die Texturkoordinaten eines Netzes können darin liegen beliebiger Bereich Um damit umgehen zu können, muss definiert werden, wie die Texturkoordinaten in die Textur eingefügt werden.

Der Umbruchparameter für die Texturkoordinate kann mit glTextureParameter mit GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T und GL_TEXTURE_WRAP_R .

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Die möglichen Parameter sind:

  • GL_CLAMP_TO_EDGE bewirkt, dass die Texturkoordinaten auf den Bereich [1 / 2N, 1 - 1 / 2N] geklemmt werden, wobei N die Größe der Textur in der Richtung ist.

  • GL_CLAMP_TO_BORDER macht dasselbe wie GL_CLAMP_TO_EDGE , aber in Fällen, in denen das Klemmen erfolgt, werden die abgerufenen GL_TEXTURE_BORDER_COLOR durch die von GL_TEXTURE_BORDER_COLOR angegebene Farbe GL_TEXTURE_BORDER_COLOR .

  • GL_REPEAT bewirkt, dass der ganzzahlige Teil der Texturkoordinate ignoriert wird. Die Textur ist gefliest .

Textur wiederholen

  • GL_MIRRORED_REPEAT : Wenn der ganzzahlige Teil der Texturkoordinate gerade ist, wird er ignoriert. Wenn der ganzzahlige Teil der Texturkoordinate ungerade ist, wird die Texturkoordinate auf 1 - Frac (s) gesetzt . fract (s) ist der gebrochene Teil der Texturkoordinate. Dadurch wird die Textur jedes zweite Mal gespiegelt .

Spiegelbeschaffenheit

  • GL_MIRROR_CLAMP_TO_EDGE bewirkt, dass die Textue-Koordinate wie für GL_MIRRORED_REPEAT für eine Wiederholung der Textur wiederholt wird, wobei die Koordinate wie in GL_CLAMP_TO_EDGE festgeklemmt GL_CLAMP_TO_EDGE .

Notieren Sie den Standardwert für GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T und GL_TEXTURE_WRAP_R ist GL_REPEAT .


Texturen anwenden

Als letztes müssen Sie die Textur vor dem Zeichnungsaufruf binden:

glBindTexture(GL_TEXTURE_2D, texture);

Textur und Framebuffer

Sie können ein Bild in einer Textur an einen Framebuffer anhängen, sodass Sie direkt auf diese Textur rendern können.

glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
                       GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D,
                       texture,
                       0);

Hinweis: In derselben Renderaufgabe können Sie nicht von derselben Textur lesen und schreiben, da undefiniertes Verhalten aufgerufen wird. Sie können jedoch glTextureBarrier() verwenden: glTextureBarrier() zwischen glTextureBarrier() .

Texturdaten lesen

Mit der Funktion glGetTexImage können Sie glGetTexImage :

char *outBuffer = malloc(buf_size);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glGetTexImage(GL_TEXTURE_2D,
              0,
              GL_RGBA,
              GL_UNSIGNED_BYTE,
              outBuffer);

Hinweis: Texturart und -format sind nur beispielhaft und können unterschiedlich sein.

PBOs verwenden

Wenn Sie einen Puffer binden GL_PIXEL_UNPACK_BUFFER die dann data Parameter in glTexImage2D wird ein Offset in diesem Puffer.

Dies bedeutet, dass das glTexImage2D nicht warten muss, bis alle Daten aus dem Anwendungsspeicher der Anwendung kopiert wurden, bevor es zurückkehren kann, wodurch der Aufwand im Haupt-Thread reduziert wird.

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*3, NULL, GL_STREAM_DRAW);
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

//write data into the mapped buffer, possibly in another thread.
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
memcpy(mappedBuffer, image, width*height*3);
SOIL_free_image(image);

// after reading is complete back on the main thread
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

PBOs leuchten jedoch vor allem dann, wenn Sie das Ergebnis eines Renderings in den Anwendungsspeicher zurücklesen müssen. Um Pixeldaten in einen Puffer zu lesen, binden Sie sie an GL_PIXEL_PACK_BUFFER Der Datenparameter von glGetTexImage wird dann in diesen Puffer versetzt:

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, NULL, GL_STREAM_COPY);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glGetTexImage(GL_TEXTURE_2D,
              0,
              GL_RGBA,
              GL_UNSIGNED_BYTE,
              null);
//ensure we don't try and read data before the transfer is complete
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

// then regularly check for completion
GLint result;
glGetSynciv(sync, GL_SYNC_STATUS, sizeof(result), NULL, &result);
if(result == GL_SIGNALED){
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
    void* mappedBuffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);

    //now mapped buffer contains the pixel data

    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);

}

Verwenden von Texturen in GLSL-Shadern

Der Vertex-Shader akzeptiert nur die Texturkoordinaten als Vertex-Attribut und leitet die Koordinaten an den Fragment-Shader weiter. Standardmäßig wird auch garantiert, dass das Fragment basierend auf seiner Position in einem Dreieck die richtig interpolierte Koordinate erhält:

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoordIn;

out vec2 texCoordOut;

void main()
{
    gl_Position = vec4(position, 1.0f);
    texCoordOut = texCoordIn;
}

Der Fragment-Shader akzeptiert dann die texCoord als Eingabevariable. Sie können dann dem Fragment-Shader eine Textur hinzufügen, indem Sie einen uniform sampler2D . Ein Fragment der Textur probieren wir eine integrierte Funktion verwenden texture , die zwei Parameter. Der erste ist die Textur, von der wir probieren möchten, und der zweite ist die Koordinate dieser Textur:

in vec2 texCoordOut;

out vec4 color;

uniform sampler2D image;

void main()
{
    color = texture(image, texCoordOut);
}

Beachten Sie, dass das image hier nicht die direkte Textur-ID ist. Es ist die ID der Textureinheit , die abgetastet wird. Texturen wiederum sind nicht direkt an Programme gebunden. Sie sind an Textureinheiten gebunden. Dies wird erreicht, indem zuerst die Textureinheit mit glActiveTexture wird und dann der Aufruf von glBindTexture diese bestimmte Textureinheit beeinflusst. Da die Standard-Textureinheit jedoch Textureinheit 0 , können Programme, die eine Textur verwenden, einfacher gemacht werden, indem dieser Aufruf weggelassen wird.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow