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.
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:
Para crear objetos textura:
void
glGenTextures(GLsizei n, GLuint *textureNames)
: Solicitamos
n
objetos textura, el nombre o identificador de estos objetos son
devueltos en
textureNames
que previamente le habremos reservado espacio.
Para eliminar objetos textura:
void glDeleteTextures(GLsizei
n, GLuint *textureNames) : Solicitamos que los n objetos textura
especificados en
textureNames
sean
borrados.
Para usar un objeto textura:
void
glBindTexture(GLenum target, GLuint textureName)
: Selecciona la textura
textureName
como textura activa para el target especificado (GL_TEXTURE_1D,
GL_TEXTURE_2D,
GL_TEXTURE_3D).
Con esta función marcamos el objeto textura como el objeto activo, tener un
objeto textura como objeto activo tiene dos funcionalidades, indincar que
textura se utiliza y sobre que textura modificamos los parámetros de
texturización.
Una vez creado, debemos especificar la textura para este objeto como ya comentamos antes.
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.
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:
GL_DECAL, GL_REPLACE : Usa el color de la textura, ignora el color del polígono.
GL_MODULATE : Usa el color de la textura multiplicado por el color del polígono, es útil para renderizar iluminación con texturas. Se renderiza con el polígono en color blanco que multiplicado por la textura nos da para cada vértice la iluminación que recibe.
GL_BLEND : Mezcla el color del polígono y el color especificado en GL_TEXTURE_ENV_COLOR, en las proporciones definidas por la 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();