Introducción.

Una textura, desde el punto de vista de su almacenamiento en memoria es un array de datos. Cada uno de los valores de este array lo llamamos 'texel'. Este array de datos representa una imagen, que utilizaremos para mapearla sobre un polígono.

Dicho array lo podemos rellenar bien cargando una imagen desde un fichero, en este caso debemos ser nosotros quienes carguemos la imagen usando alguna librería o el API correspondiente del SO, posteriormente la pasamos a un formato aceptado por OpenGL y finalmente se la entregamos a OpenGL como un puntero. O también podemos crear una textura dándole nosotros los valores de color a cada textel, lo cual puede resultar muy complicado salvo que sepamos perfectamente lo que queremos, en general es mucho más fácil crear la imagen con un edito y luego usarla en nuestro programa.

La información de cada uno de los componente puede ser:

Gracias a la texturización el número de polígonos para representar un objeto se ve reducido enormemente. La texturización consiste en "pegar" un poster a una primitiva (un polígono) que sustituye (o complementa) el color especificado. Por ejemplo, si deseamos renderizar una pared de ladrillos, necesitamos un polígono para cada ladrillo, además de otros tantos para renderizar el espacio que hay entre estos, en cambio con texturas podemos renderizar una pared entera con solo un polígono y una textura que se repite a lo largo del polígono.

Podemos tener texturas de varios tipos, dependiendo de las dimensiones que cubra la imagen, así pueden ser:unidimensionales (un solo pixel de alto o de ancho) bidemensionales (imagen de tamaño mxn) o tridimensionales (con volumen), aunque lo habitual será utilizar las bidimensionales.

En OpenGl las dimensiones de una textura deben ser siempre potencia de 2= 64,128,256...

Los pasos necesarios para mapear texturas sobre polígonos son los siguientes

A continuación veremos como realizar cada uno de los pasos mencionados.

Crear objeto textura.

Los objetos textura pueden ser  creados y destruidos, pero no se comparten entre los distintos contextos de OpenGL. Las funciones relacionadas con los objetos texturas son las siguientes:

Una vez creado, debemos especificar la textura para este objeto como ya comentamos antes.

Especificar textura.

Para este paso disponemos de tres funciones, una diferente para cada numero de dimensiones (1 dimensión, 2 dimensiones o 3 dimensiones). En general funcionan todas de la misma manera, por lo que centraremos el tutorial en el caso más habitual, siendo extensible para 1D y 3D.

glTextImage2D(GLenum objetivo, Glint nivel, GLint componentes, GLsizei ancho, GLsizei alto, GLint borde, GLenum formato, GLenum tipo, const GLvoid *texels);

Ahora veremos que representa cada uno de los parámetros que se le pasan a la función:

objetivo GL_TEXTURE_2D (para texturas bidimensionales, que es el caso que veremos)
nivel 0,1,2.. es el nivel de detalle de la textura. Si sólo hay una textura nivel=0, otros valores se emplean para técnicas de mipmapping
componentes Número de componentes de color. Color indexado=1, RGB=3 (GL_RGB), RGBA=4
ancho Ancho de la textura: potencia de 2
alto Alto de la textura: potencia de 2
borde Anchura del borde= 0,1, ó 2. El tamaño total será (2n+b)*(2m+b)
formato formato de la información de píxel. Pueden ser: GL_COLOR_INDEX, GL_RGB, GL_RGBA, etc.
tipo Tipo de datos de cada píxel: GL_UNSIGNED_BYTE, GL_INT, GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, GL_BITMAP.
texels Puntero al array donde se almacenan los valores de la textura, de izquierda a derecha y de abajo a arriba.

Esta función deberemos llamarla antes de dibujar los polígonos sobre los que queremos aplicar la textura.

Especificamos cual es la textura para el objeto textura activo. Es conveniente por cuestiones de rendimiento que por cada textura que utilicemos tengamos un objeto textura y mantener los objetos textura durante toda la aplicación, en lugar de crearlo y destruirlo cada vez que se usa la textura.

Definición de los parámetros de la aplicación de la textura.

Ahora debemos definir una serie de parámetros que servirán para definir cómo se aplica la textura sobre el polígono. Esto ser hará con la función glTexParameter, cuyo prototipo es:

        glTexParameter{if}{v}(GLenum objetivo, GLenum pnombre, GLfloat param);

En nuestro caso particular objetivo será igual a GL_TEXTURE_2D, pudiendo adaptarlo al caso 1D con GL_TEXTURE_1D o a 3D con GL_TEXTURE_3D, mientras que los otros dos parámetros indican un parámetro de la textura y su valor. Hay cuatro variables que deberemos definir, por lo que se deberá llamar a esta función 4 veces. Los valores que pueden tomar son los siguientes:

pnombre

param

GL_TEXTURE_WRAP_S

GL_CLAMP, GL_REPEAT

GL_TEXTURE_WRAP_T

GL_CLAMP, GL_REPEAT

GL_TEXTURE_MAG_FILTER

GL_NEAREST,GL_LINEAR

GL_TEXTURE_MIN_FILTER

GL_NEAREST,GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR

 

Con GL_TEXTURE_WRAP especificamos el tratamiento de las coordenadas S y T de la textura, fuera del rango [0.0,1.0]. Y Con GL_MAG_FILTER y GL_MIN_FILTER especificamos los filtros de ampliación o reducción de la textura.

Otra de las posibilidades que debemos contemplar es la combinación del color del polígono con el color de la textura. La asignación del método para combinar el color y la textura se realiza con la función glTexEnv* :

glTexEnv{if}{v}(GLenum objetivo, GLenum pnombre, GLfloat param);

Objetivo debe valer GL_TEXTURE_2D en nuestro caso particular, pero como ya hemos comentado antes este parámetro varia segun el tipo de textura sobre la que estemos trabajando.

Si pnombre vale GL_TEXTURE_ENV_MODE param puede valer GL_DECAL, GL_REPLACE, GL_MODULATE o GL_BLEND, para especificar como se mezcla el color del polígono con la textura.
Si pnombre vale GL_TEXTURE_ENV_COLOR param es un array de cuatro puntos flotantes representando las componentes R, G, B, A. Estos valores solo se usan si se ha especificado el modo GL_BLEND.

Veremos ahora por encima que es cada modo cuando la textura es RGB:

Dibujar la escena y asignar coordenadas de textura.

El último paso para emplear nuestras texturas será dibujar los objetos. Para ello debemos asignarle a cada uno de los vértices del objeto las coordenadas de la textura que le correspondan. Estas coordenadas determinan el texel que es aplicado desde el mapa de texturas a cada vértice, interpolando las coordenadas textura de los vértices de la misma forma que se hacia para el color. Para hacer ésto, debemos llamar antes de cada glVertex, a la función:

glTexCoord2{if}(coord_s, coord_t);

Veamos un ejemplo:

    glBegin(GL_QUADS);

    glColor3f(1.0, 1.0, 1.0);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0, -2.0, 0.0);

    glTexCoord2f(0.0, 3.0);
    glVertex3f(-1.0, 2.0, 0.0);

    glTexCoord2f(2.0, 3.0);
    glVertex3f(1.0, 2.0, 0.0);

    glTexCoord2f(2.0, 0.0);
    glVertex3f(1.0, -2.0, 0.0);

    glEnd();

Las coordenadas de la textura varían de 0 a 1, números mayores a 1 representan que la textura se repite.

Veamos finalmente un ejemplo de la utilización de todas estas funciones:

//Pegado sobre el polígono
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

//Filtros
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);

//Cargamos un fichero bmp en el array
imagen[0]=LoadBMP("file.bmp");  //Esta función suponemos que ya está definida.

//Activamos las texturas
glEnable(GL_TEXTURE_2D);

Por último, en la función de dibujado, cargamos la textura antes de dibujar el polígono:

glTexImage2D(GL_TEXTURE_2D,0,3,imagen[0]->sizeX, imagen[0]->sizeY,
0,GL_RGB,GL_UNSIGNED_BYTE,imagen[0]->data);

glBegin(GL_POLYGON);
glNormal3f(0,0,1);
glTexCoord2i(0,0); //Asignamos las coordenadas de textura del siguiente vértice.
glVertex3f(-ancho/2,-alto/2,0);
glTexCoord2i(0,1);
glVertex3f(-ancho/2,alto/2,0);
glTexCoord2i(1,1);
glVertex3f(ancho/2,alto/2,0);
glTexCoord2i(1,0);
glVertex3f(ancho/2,-alto/2,0);
glEnd();