Explicamos a continuación la manera de programar lo anteriormente explicado de forma teórica en OpenGL paso a paso:
Esto se hace ejecutando la siguiente instrucción:
glEnable(GL_TEXTURE_2D);Si queremos usar texturas en una dimensión (líneas), cambiaremos el parámetro por GL_TEXTURE_1D. Si las dos están habilitadas, por defecto se usara en 2D.
Para ello se utiliza la siguiente función:
void glTexImage2D( GLenum target, GLint level, GLint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );Se explica a continuación el significado de cada parámetro:
Ejemplo:
glTexImage2D(GL_TEXTURE_2D,0,3,TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0] ->data);
Cuando se está dibujando el objeto, hay que indicar, para cada vértice de este, qué posición de la textura le corresponde. Esto se hace mediante la siguiente función, donde (s,t) indica una posición sobre el mapa de la imagen.
void glTexCoord2f( GLfloat s, GLfloat t);
Lo que se hace es indicar la coordenada de la textura antes de indicar el vértice del polígono.
A continuación vamos a ver dos funciones, donde se dibujan un cuadrado y un triángulo, indicando las posiciones de la textura:
void Cuadrado(void)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0);glVertex3f(-1.0,1.0,0.0);
glTexCoord2f(1.0,1.0);glVertex3f(1.0,1.0,0.0);
glTexCoord2f(1.0,0.0);glVertex3f(1.0, -1.0,0.0);
glTexCoord2f(0.0,0.0);glVertex3f(-1.0,-1.0,0.0);
glEnd();
}
void Triangulo(void)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0);glVertex3f(-1.0,1.0,0.0);
glTexCoord2f(1.0,0.0);glVertex3f(1.0, -1.0,0.0);
glTexCoord2f(0.0,0.0);glVertex3f(-1.0,-1.0,0.0);
glEnd();
}
En este paso es donde se indican diferentes parámetros que van a tener variopintos efectos sobre el resultado final. Entre los más destacables está la repetición de la textura o no, el filtrado y las funciones de texturización que ya se vieron en el apartado tres, pero además hay otros más que son también interesantes como los mipmap, y que se utiliza para evitar problemas visuales sobre la textura cuando el observador se aleja o acerca a la misma.
Básicamente el manejo de estos parámetros se va a realizar con la función que se indica a continuación en la cual se indicarán los valores correspondientes para dar el efecto deseado:
void glTexParameterf( GLenum target, GLenum pname, GLfloat param );A continuación vamos a ver un ejemplo que dibuja un cubo que va rotando por la pantalla y al cual se le ha aplicado una textura. La salida será como se muestra debajo:

#include <GL/glut.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
#include <stdio.h>
//angulos de rotacion
GLfloat xrot=0.0;
GLfloat yrot=0.0;
GLfloat zrot=0.0;
GLint texture[1];
//parametros de la fuente de luz
GLfloat LightAmbient[]={ 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]={ 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]={ 1.0f, 1.0f, 1.0f, 0.0f };
AUX_RGBImageRec *LoadBMP(char *Filename) //carga un bitmap
{
FILE *File=NULL;
if (!Filename) return NULL;
File=fopen(Filename,"r");
if (File)
{
fclose(File);
return auxDIBImageLoad(Filename);
}
return NULL;
}
int LoadGLTextures() // Convierte el bitmap a textura
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[1];
memset(TextureImage,0,sizeof(void *)*1);
if (TextureImage[0]=LoadBMP("imagen.bmp"))
{
Status=TRUE;
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3,TextureImage[0]->
sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0] ->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
if (TextureImage[0])
{
if (TextureImage[0]->data)
{
free(TextureImage[0]->data);
}
free(TextureImage[0]);
}
return Status;
}
void init(void)
{
//Carga la textura
LoadGLTextures();
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
//posicion de la fuente de luz
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
//activa la luz
glEnable(GL_LIGHT1);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-4.5f);
//Rota el cubo
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_QUADS);
// Frente
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// parte de Atras
glNormal3f( 0.0f, 0.0f,-1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// Arriba
glNormal3f( 0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// Abajo
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// lado Derecho
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// Lado Izquierdo
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glFlush();
glutSwapBuffers();
}
void reshape (int width, int height)
{
if (height==0) height=1;
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit(0);
break;
}
}
//Incremento los angulos de rotacion
void Idle(void)
{
xrot+=5.0f;
yrot+=6.0f;
zrot+=7.0f;
display();
}
int main(int argc, char** argv)
{
//Inicializar el estado de GLUT
glutInit(&argc, argv);
//Seleccionar el tipo de modo de display Buffer doble y color RGBA
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
//Poner el tamaño y posición de la ventana
glutInitWindowSize (300, 300);
glutInitWindowPosition (0, 0);
glutCreateWindow ("Textura 3D");
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(Idle);
glutMainLoop();
return 0;
}
En el ejercicio anterior se mostró el resultado de aplicar una textura con un determinado número de pixels de alto y ancho. En este ejemplo se va a mostrar como el uso de texturas 1D también proporciona imágenes de calidad.
Se muestra la salida que produce el siguiente código de ejemplo. Se pueden cambiar parámetros de aplicación de la textura con las teclas "e", "o", "s", "x" y "t".

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#ifdef _WIN32
#define floorf(x) ((float)floor((x)))
#endif
static float transx = 1.0, transy, rotx, roty;
static int ox = -1, oy = -1;
static int mot = 0;
#define PAN 1
#define ROT 2
void pan(const int x, const int y) {
transx += (x -ox)/5.;
transy -= (y-oy)/5.;
ox = x; oy = y;
glutPostRedisplay();
}
void rotate(const int x, const int y) {
rotx += x-ox;
if (rotx > 360.) rotx -= 360.;
else if (rotx < -360.) rotx += 360.;
roty += y-oy;
if (roty > 360.) roty -= 360.;
else if (roty < -360.) roty += 360.;
ox = x; oy = y;
glutPostRedisplay();
}
void motion(int x, int y) {
if (mot == PAN) pan(x, y);
else if (mot == ROT) rotate(x,y);
}
void mouse(int button, int state, int x, int y) {
if(state == GLUT_DOWN) {
switch(button) {
case GLUT_LEFT_BUTTON:
mot = PAN;
motion(ox = x, oy = y);
break;
case GLUT_MIDDLE_BUTTON:
mot = ROT;
motion(ox = x, oy = y);
break;
case GLUT_RIGHT_BUTTON:
break;
}
} else if (state == GLUT_UP) mot = 0;
}
#define stripeImageWidth 32
GLubyte stripeImage[4*stripeImageWidth];
void makeStripeImage(void) {
int j;
for (j = 0; j < stripeImageWidth; j++) {
stripeImage[4*j] = (GLubyte) ((j<=4) ? 255 : 0);
stripeImage[4*j+1] = (GLubyte) ((j>4) ? 255 : 0);
stripeImage[4*j+2] = (GLubyte) 0;
stripeImage[4*j+3] = (GLubyte) 255;
}
}
void hsv_to_rgb(float h,float s,float v,float *r,float *g,float *b)
{
int i;
float f, p, q, t;
h *= 360.0;
if (s==0) {
*r = v;
*g = v;
*b = v;
} else {
if (h==360)
h = 0;
h /= 60;
i = floorf(h);
f = h - i;
p = v*(1.0-s);
q = v*(1.0-(s*f));
t = v*(1.0-(s*(1.0-f)));
switch (i) {
case 0 :
*r = v;
*g = t;
*b = p;
break;
case 1 :
*r = q;
*g = v;
*b = p;
break;
case 2 :
*r = p;
*g = v;
*b = t;
break;
case 3 :
*r = p;
*g = q;
*b = v;
break;
case 4 :
*r = t;
*g = p;
*b = v;
break;
case 5 :
*r = v;
*g = p;
*b = q;
break;
}
}
}
GLubyte rainbow[4*stripeImageWidth];
void makeRainbow(void) {
int j;
for (j = 0; j < stripeImageWidth; j++) {
float r, g, b;
hsv_to_rgb((float)j/(stripeImageWidth-1.f), 1.0, 1.0, &r, &g, &b);
rainbow[4*j] = r*255;
rainbow[4*j+1] = g*255;
rainbow[4*j+2] = b*255;
rainbow[4*j+3] = (GLubyte) 255;
}
}
/* planes for texture coordinate generation */
static GLfloat xequalzero[] = {1.0, 0.0, 0.0, 0.0};
static GLfloat slanted[] = {1.0, 1.0, 1.0, 0.0};
static GLfloat *currentCoeff;
static GLenum currentPlane;
static GLint currentGenMode;
void init(void) {
glClearColor (0.0, 0.0, 0. 0, 0.0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
makeStripeImage();
makeRainbow();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D
(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
currentCoeff = xequalzero;
currentGenMode = GL_OBJECT_LINEAR;
currentPlane = GL_OBJECT_PLANE;
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode);
glTexGenfv(GL_S, currentPlane, currentCoeff);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_1D);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glMaterialf (GL_FRONT, GL_SHININESS, 64.0);
}
void tfunc(void) {
static state;
if (state ^= 1) {
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D
(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rainbow);
} else {
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D
(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage);
}
glutPostRedisplay();
}
void display(void) {
static GLUquadric *q;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0., 0., transx);
glRotatef(rotx, 1.0, 0.0, 0.0);
glRotatef(45.0, 0.0, 0.0, 1.0);
glutSolidTeapot(2.0);
#if 0
if (!q) q = gluNewQuadric();
gluQuadricTexture(q, GL_TRUE);
gluCylinder(q, 1.0, 2.0, 3.0, 10, 10);
#endif
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho
(-3.5, 3.5, -3.5*(GLfloat)h/(GLfloat)w, 3.5*(GLfloat)h/(GLfloat)w, -3.5, 3.5);
else
glOrtho
(-3.5*(GLfloat)w/(GLfloat)h,3.5*(GLfloat)w/(GLfloat)h, -3.5, 3.5, -3.5, 3.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
/*ARGSUSED1*/
void keyboard (unsigned char key, int x, int y) {
switch (key) {
case 'e':
case 'E':
currentGenMode = GL_EYE_LINEAR;
currentPlane = GL_EYE_PLANE;
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode);
glTexGenfv(GL_S, currentPlane, currentCoeff);
glutPostRedisplay();
break;
case 'o':
case 'O':
currentGenMode = GL_OBJECT_LINEAR;
currentPlane = GL_OBJECT_PLANE;
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode);
glTexGenfv(GL_S, currentPlane, currentCoeff);
glutPostRedisplay();
break;
case 's':
case 'S':
currentCoeff = slanted;
glTexGenfv(GL_S, currentPlane, currentCoeff);
glutPostRedisplay();
break;
case 'x':
case 'X':
currentCoeff = xequalzero;
glTexGenfv(GL_S, currentPlane, currentCoeff);
glutPostRedisplay();
break;
case 't':
tfunc();
break;
case 27:
exit(0);
break;
default:
break;
}
}
int main(int argc, char*argv[]) {
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(512, 512);
glutInitWindowPosition(100, 100);
glutInit(&argc, argv);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutMainLoop();
return 0;
}
Trabajo realizado para la asignatura de Gráficos de Computación de la UDC, del curso 2008/2009, por los alumnos
Jorge Abad Casares, Rafael Bermudez Míguez, Yerai Doval Mosquera y Jorge Pérez Rodríguez