Buscar..


Fundamentos de la texturización.

Una textura es una forma de almacenamiento de datos que permite un acceso conveniente no solo a entradas de datos particulares, sino también a puntos de muestra que mezclan (interpolan) varias entradas juntas.

En OpenGL, las texturas se pueden usar para muchas cosas, pero lo más común es mapear una imagen a un polígono (por ejemplo, un triángulo). Para mapear la textura a un triángulo (u otro polígono) tenemos que decirle a cada vértice a qué parte de la textura corresponde. Asignamos una coordenada de textura a cada vértice de un polígono y luego se interpolará entre todos los fragmentos de ese polígono. Las coordenadas de la textura suelen oscilar entre 0 y 1 en los ejes x e y como se muestra en la siguiente imagen:

coordenadas de textura

Las coordenadas de textura de este triángulo se verían así:

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

Coloque esas coordenadas en VBO (objeto de búfer de vértice) y cree un nuevo atributo para el sombreador. Ya debería tener al menos un atributo para las posiciones de vértice, así que cree otro para las coordenadas de textura.


Generando textura

Lo primero que se debe hacer es generar un objeto de textura al que se hará referencia mediante una ID que se almacenará en una textura int sin signo:

GLuint texture;
glGenTextures(1, &texture); 

Después de eso, debe estar vinculado para que todos los comandos de textura subsiguientes configuren esta textura:

glBindTexture(GL_TEXTURE_2D, texture); 

Cargando imagen

Para cargar una imagen, puede crear su propio cargador de imágenes o puede usar una biblioteca de carga de imágenes como SOIL (Simple OpenGL Image Library) en c ++ o PNGDecoder de TWL en java.

Un ejemplo de carga de imagen con SOIL sería:

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

Ahora puedes asignar esta imagen al objeto de textura:

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

Después de eso debes desenlazar el objeto de textura:

glBindTexture(GL_TEXTURE_2D, 0); 

Wrap parámetro para coordenadas de textura

Como se ve arriba, la esquina inferior izquierda de la textura tiene las coordenadas UV (st) (0, 0) y la esquina superior derecha de la textura tiene las coordenadas (1, 1), pero las coordenadas de textura de una malla pueden estar en cualquier rango. Para manejar esto, se debe definir cómo se ajustan las coordenadas de la textura a la textura.

El parámetro de ajuste para la coordenada de textura se puede configurar con glTextureParameter usando GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T y 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);

Los parámetros posibles son:

  • GL_CLAMP_TO_EDGE hace que las coordenadas de la textura se GL_CLAMP_TO_EDGE al rango [1 / 2N, 1 - 1 / 2N] , donde N es el tamaño de la textura en la dirección.

  • GL_CLAMP_TO_BORDER hace lo mismo que GL_CLAMP_TO_EDGE , pero en los casos en que la sujeción, los datos de texel obtenidos se sustituyen con el color especificado por GL_TEXTURE_BORDER_COLOR .

  • GL_REPEAT hace que se GL_REPEAT la parte entera de la coordenada de textura. La textura es de baldosas .

repetir textura

  • GL_MIRRORED_REPEAT : Si la parte entera de la coordenada de textura es par, entonces se ignora. A diferencia de, si la parte entera de la coordenada de la textura es impar, entonces la coordenada de la textura se establece en 1 - frac (s) . fract (s) es la parte fraccionaria de la coordenada de textura. Eso hace que la textura se refleje cada 2 veces.

textura de espejo

  • GL_MIRROR_CLAMP_TO_EDGE hace que la coordenada textue se repita como para GL_MIRRORED_REPEAT para una repetición de la textura, en cuyo punto la coordenada se fija como en GL_CLAMP_TO_EDGE .

Tenga en cuenta que el valor predeterminado para GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T y GL_TEXTURE_WRAP_R es GL_REPEAT .


Aplicando texturas

Lo último que hay que hacer es enlazar la textura antes del dibujo:

glBindTexture(GL_TEXTURE_2D, texture);

Textura y Framebuffer

Puede adjuntar una imagen en una textura a un framebuffer, para que pueda renderizar directamente a esa textura.

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

Nota: no puede leer y escribir desde la misma textura en la misma tarea de renderizado, ya que se trata de un comportamiento indefinido. Pero puede usar: glTextureBarrier() entre las llamadas de render para esto.

Leer datos de textura

Puede leer datos de textura con la función 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: el tipo y el formato de la textura son solo por ejemplo y pueden ser diferentes.

Usando PBOs

Si vincula un búfer a GL_PIXEL_UNPACK_BUFFER entonces el parámetro de data en glTexImage2D es un desplazamiento en ese búfer.

Esto significa que glTexImage2D no necesita esperar a que todos los datos se copien de la memoria de la aplicación antes de que pueda regresar, lo que reduce la sobrecarga en el subproceso principal.

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

Pero donde realmente brillan las PBO es cuando necesita leer el resultado de un render en la memoria de la aplicación. Para leer los datos de píxeles en un búfer, GL_PIXEL_PACK_BUFFER a GL_PIXEL_PACK_BUFFER entonces el parámetro de datos de glGetTexImage será un desplazamiento en ese búfer:

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

}

Usando texturas en sombreadores GLSL

El sombreador de vértices solo acepta las coordenadas de textura como un atributo de vértice y envía las coordenadas al sombreador de fragmentos. De forma predeterminada, también garantizará que el fragmento reciba la coordenada interpolada correctamente en función de su posición en un triángulo:

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

El sombreador de fragmentos acepta la variable de salida texCoord como una variable de entrada. Luego puede agregar una textura al fragmento sombreado declarando un uniform sampler2D . Para muestrear un fragmento de la textura usamos una texture función incorporada que tiene dos parámetros. Primero está la textura de la que queremos muestrear y la segunda es la coordenada de esta textura:

in vec2 texCoordOut;

out vec4 color;

uniform sampler2D image;

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

Tenga en cuenta que la image no es la identificación directa de la textura aquí. Es la identificación de la unidad de textura que se muestreará. A su vez, las texturas no están limitadas a los programas directamente; Ellos están obligados a unidades de textura. Esto se logra primero glActiveTexture unidad de textura con glActiveTexture , y luego llamando a glBindTexture afectará a esta unidad de textura en particular. Sin embargo, como la unidad de textura predeterminada es la unidad de textura 0 , los programas que usan una textura pueden simplificarse omitiendo esta llamada.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow