Ricerca…


Nozioni di base di texturing

Una texture è una forma di archiviazione dei dati che consente un comodo accesso non solo a particolari voci di dati, ma anche di campionare i punti mescolando (interpolando) più voci insieme.

Nelle trame OpenGL possono essere utilizzate per molte cose, ma più comunemente è mappare un'immagine a un poligono (per esempio un triangolo). Per mappare la trama a un triangolo (o un altro poligono) dobbiamo dire a ogni vertice quale parte della trama corrisponde. Assegniamo una coordinata di trama a ciascun vertice di un poligono e verrà quindi interpolata tra tutti i frammenti di quel poligono. Le coordinate della trama in genere vanno da 0 a 1 negli assi xe come mostrato nell'immagine seguente:

coordinate della trama

Le coordinate della trama di questo triangolo sono simili a questo:

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

Inserisci tali coordinate in VBO (oggetto buffer vertice) e crea un nuovo attributo per lo shader. Dovresti già avere almeno un attributo per le posizioni dei vertici, quindi crearne un altro per le coordinate della trama.


Generazione di texture

La prima cosa da fare sarà generare un oggetto texture a cui farà riferimento un ID che verrà memorizzato in una trama int unsigned:

GLuint texture;
glGenTextures(1, &texture); 

Dopodiché deve essere associato in modo tale che tutti i comandi di texture successivi configureranno questa texture:

glBindTexture(GL_TEXTURE_2D, texture); 

Caricamento immagine

Per caricare un'immagine è possibile creare il proprio caricatore di immagini oppure utilizzare una libreria di caricamento dell'immagine come SOIL (libreria di immagini OpenGL semplice) in c ++ o PNGDecoder di TWL in java.

Un esempio di caricamento dell'immagine con SOIL potrebbe essere:

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

Ora puoi assegnare questa immagine all'oggetto texture:

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

Dopodiché dovresti sciogliere l'oggetto texture:

glBindTexture(GL_TEXTURE_2D, 0); 

Avvolgi il parametro per le coordinate della trama

Come visto sopra, l'angolo in basso a sinistra della trama ha le coordinate UV (st) (0, 0) e l'angolo in alto a destra della trama ha le coordinate (1, 1), ma le coordinate della trama di una mesh possono essere in qualsiasi intervallo. Per gestirlo, è necessario definire in che modo le coordinate della trama vengono avvolte sulla trama.

Il parametro wrap per la coordinata della trama può essere impostato con glTextureParameter usando GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T e 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);

I parametri possibili sono:

  • GL_CLAMP_TO_EDGE fa sì che le coordinate della trama vengano bloccate nell'intervallo [1 / 2N, 1 - 1 / 2N] , dove N è la dimensione della trama nella direzione.

  • GL_CLAMP_TO_BORDER fa lo stesso di GL_CLAMP_TO_EDGE , ma nei casi in cui il clamping, i dati di texel recuperati vengono sostituiti con il colore specificato da GL_TEXTURE_BORDER_COLOR .

  • GL_REPEAT fa in modo che la parte intera della coordinata della trama sia ignorata. La trama è piastrellata .

ripetere la trama

  • GL_MIRRORED_REPEAT : Se la parte intera della coordinata della trama è pari, allora viene ignorata. Al contrario, se la parte intera della coordinata della trama è dispari, la coordinata della trama è impostata su 1 - frac (s) . il / i frattale / i è la parte frazionaria della coordinata della trama. Ciò fa sì che la trama venga specchiata ogni 2 volte.

trama a specchio

  • GL_MIRROR_CLAMP_TO_EDGE causa la ripetizione della coordinata di testo come per GL_MIRRORED_REPEAT per una rettifica della trama, a quel punto la coordinata da GL_CLAMP_TO_EDGE come in GL_CLAMP_TO_EDGE .

Notare che il valore predefinito per GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T e GL_TEXTURE_WRAP_R è GL_REPEAT .


Applicazione di trame

L'ultima cosa da fare è legare la trama prima della chiamata dell'estrazione:

glBindTexture(GL_TEXTURE_2D, texture);

Texture e Framebuffer

È possibile allegare un'immagine in una texture a un framebuffer, in modo da poter eseguire il rendering direttamente su tale texture.

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

Nota: non è possibile leggere e scrivere dalla stessa trama nello stesso task di rendering, perché chiama un comportamento non definito. Ma puoi usare: glTextureBarrier() tra le chiamate di rendering per questo.

Leggi i dati della trama

Puoi leggere i dati delle texture con la funzione 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);

Nota: il tipo e il formato della trama sono solo per esempio e possono essere diversi.

Usando PBO

Se si associa un buffer a GL_PIXEL_UNPACK_BUFFER il parametro data in glTexImage2D è un offset in quel buffer.

Ciò significa che glTexImage2D non ha bisogno di attendere che tutti i dati vengano copiati dalla memoria dell'applicazione prima che possa tornare, riducendo il sovraccarico nel thread principale.

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

Ma dove i PBO sono davvero brillanti è quando hai bisogno di leggere il risultato di un rendering nella memoria dell'applicazione. Per leggere i dati dei pixel in un buffer, collegarli a GL_PIXEL_PACK_BUFFER quindi il parametro dei dati di glGetTexImage sarà un offset in tale buffer:

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

}

Usare le trame negli shader GLSL

Il vertex shader accetta solo le coordinate della texture come un attributo vertice e inoltra le coordinate allo shader del frammento. Per impostazione predefinita, garantisce anche che il frammento riceva le coordinate correttamente interpolate in base alla sua posizione in un triangolo:

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

Il framment shader accetta quindi la variabile di output texCoord come variabile di input. È quindi possibile aggiungere una texture allo shader di frammenti dichiarando un uniform sampler2D . Per campionare un frammento della trama, utilizziamo una texture funzione incorporata che ha due parametri. La prima è la trama che vogliamo campionare e la seconda è la coordinata di questa texture:

in vec2 texCoordOut;

out vec4 color;

uniform sampler2D image;

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

Nota che l' image non è l'ID della trama diretta qui. È l'id dell'unità texture che verrà campionata. A loro volta, le trame non sono legate direttamente ai programmi; sono legati alle unità di tessitura. Ciò si ottiene rendendo l'unità texture attiva con glActiveTexture , quindi chiamando glBindTexture avrà effetto su questa particolare unità di texture. Tuttavia, poiché l'unità di trama predefinita è l'unità di trama 0 , i programmi che utilizzano una trama possono essere semplificati omettendo questa chiamata.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow