Uso de Texturas con OpenGl

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 'textel'. Este array de datos representa una imagen, que utilizaremos para mapearla sobre un polígono.

Podemos rellenar dicho array bien cargando una imagen desde un fichero, o bien dándole nosotros los valores de color a cada texel.

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

Además, podemos tener texturas 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

Veamos cómo hacer cada uno de estos pasos.

Definición de los parámetros de texturado.

Una vez cargada la imagen en memoria 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;

Donde: objetivo= GL_TEXTURE_2D ,y pnombre y param pueden tomar los siguientes valores:

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

 

Habrá que llamar a la función glTexParameter cuatro veces, para dar los valores que deseemos a cada uno de los parámetros.

Con GL_TEXTURE_WRAP especificamos el tratamiento de las coordenadas S y T de la textura, fuega 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.

También podemos especificar cómo aplicar la textura sobre los píxels. Esto lo haremos con la función:

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

donde objetivo=GL_TEXTURE_2D y

pnombre

param

GL_TEXTURE_ENV_MODE

(especifica el tipo de textura)

GL_DECAL(la textura reemplaza los colores previos)

GL_BLEND ó GL_MODULATE

GL_TEXTURE_ENV_COLOR

(especificar qué color usar en las mezclas)

puntero a un valor de color RGBA

 

Para poder ver las texturas deberemos activarlas con la función:

glEnable(GL_TEXTURE_2D);

Especificar la textura.

Normalmente partiremos de una imagen almacenada en algún formato standard (bmp, jpg, gif, rgb, etc). Para poder cargar esta imagen necesitaremos algún programa o biblioteca que lea este tipo de ficheros. Por la red se pueden encontrar todo de tipo de cargadores de imagen. Debemos asegurarnos, utilizando algún editor de imágenes, que el ancho y el alto de la imagen es potencia de dos.

Si la imagen la tenemos en formato bmp podemos utilizar también una función de la biblioteca glaux para cargarla:

AUX_RGBImageRec *auxDIBImageLoad(Filename);

Esta función nos devolverá una estructura de la cual podremos leer la información de tamaño y datos:

typedef struct _AUX_RGBImageRec {
GLint sizeX, sizeY;
unsigned char *data;
} AUX_RGBImageRec;

Una vez hemos cargada de fichero la textura deseada, debemos definir la textura en OpenGl. Para ello utilizamos la función glTextImage2D:

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

Donde:

parámetro
valores
objetivo GL_TEXTURE_2D (para texturas bidimensionales)
nivel 0,1,2.. es el nivel de detalle de la textura. Si sólo hay una textura nivel=0
componentes Número de componentes de color. Color indexado=1, RGB=3, 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.
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, etc.
pixels Puntero al array donde se almacenan los valores de la textura.

 

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

Dibujar la escena y asignar coordenadas de textura.

El último paso del proceso será dibujar los objetos. Para que la textura se visualice correctamente sobre ellos deberemos asignarle a cada uno de los vértices las coordenadas de textura. Estas coordenadas determinan qué texsel en el mapa de texturas es asignado a cada vértice. Para ello, llamaremos, antes de cada glVertex, a la función:

glTexCoord2{if}(coord_s, coord_t);

Otras funciones.

Otras funciones útiles para el tratamiento de texturas son glBindTexture y glGenTexture . Estas funciones son útiles para gestionar las texturas cuando vamos a utilizar un gran número de ellas. Nos permiten asignarle un 'nombre' a la textura cuando se carga, y en el momento del redibujado no necesitamos llamar a glTexImage2D, sino que bastará con llamar a glBindTexture y pasarle el nombre de la textura a activar.

Ejemplo.

Un ejemplo del código necesario para dibujar un objeto con texturas.

Necesitaremos una variable globarl, que será un array de texturas donde almacenarlas:

AUX_RGBImageRec *imagen[1]; //En este caso solo cargamos una textura

La función para leer las texturas de fichero será como sigue:

AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; if (!Filename)
{ return NULL; }

File=fopen(Filename,"r");

if (File)
{
fclose(File);
return auxDIBImageLoad(Filename); //Carga el bitmap y devuelve un puntero

}
return NULL;
}

En la función de inicialización de valores definiremos los parámetros de pegado de la textura, y leeremos las imágenes de fichero

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

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