Está en la página 1de 72

tecnunLogo: un logo en tres dimensiones

TECNUNLOGO: UN LOGO EN TRES DIMENSIONES


Tutorial de OpenGL y manual de las prcticas de OpenGL
de la asignatura de Grficos por Computador y Multimedia
http://www.tecnun.es/graficos

Nicol Serrano Brcena


Fernando Alonso Blzquez
Carlos Melara Ortiz

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

Tabla de contenido
TecnunLogo: un logo en tres dimensiones
0. Introduccin
0.1
Objetivo del documento
0.2
Descripcin de logo
0.3
Entorno de visualizacin tridimensional
0.4
Contenido del documento
1. Introduccin a OpenGL: dibujando una tortuga con OpenGL
1.1
Qu es OpenGL?
1.2
Abriendo una ventana con OpenGL
1.3
Dibujando un Toroide en la ventana
1.4
Definiendo el rea de proyeccin inicial
1.5
Interactuandocon el teclado
1.6
Representando una tortuga
2. Transformaciones: dando rdenes a la tortuga (forward, right, left, up y down)
2.1
Transformaciones de modelado y de proyeccin
2.2
Interpretando los comandos
2.3
Traslacin
2.4
Rotacin
2.5
Escalado
2.6
Orden de las transformaciones
2.7
Ejemplo de bucle repeat
2.8
puntos a realizar
3. Operaciones con matrices: dibujando el camino
3.1
La pila de matrices
3.2
Dibujando un rastro
3.3
Mostrar texto
3.4
puntos a realizar
4. Viendo la escena desde otro punto de vista: cmaras
4.1
Transformaciones de vista
4.2
Transformaciones de proyeccin
4.3
Diferentes modos de mover la cmara
4.4
Trabajos propuestos
5. Iluminando la escena
5.1
Aadiendo iluminacin a la escena
5.2
Creando fuentes de luz con OpenGL
5.3
Introduciendo luces al programa TecnunLogo
5.4
Trabajos propuestos
6. Tipos de fuentes de luz
6.1
Tipos de luces
6.2
Control de los distintos tipos de luces
6.3
Trabajos propuestos
7. Leyendo objetos: otras tortugas y el escenario
7.1
Representacin de un objeto en formato Wavefront
7.2
Varias tortugas
7.3
Trabajos propuestos
8. Opciones de visualizacin: propiedades de Open GL
8.1
Trabajos propuestos
9. Creando objetos: lectura de coordenadas de vrtices
9.1
Digitalizacin de modelos
9.2
Caractersticas de la mquina de medir por coordenadas
9.3
Proceso de captura de coordenadas
9.4
Digitalizacin por fotografa
10.
El mapeado de texturas
10.1 Cargando y pegando una textura
10.2 Cargando y pegando una textura en tecnunLogo
10.3 Trabajo propuesto
Bibliografa

1
3
3
3
3
4
5
5
5
7
8
9
10
12
12
13
15
15
16
17
17
18
19
19
20
24
24
25
25
26
28
32
38
38
38
39
44
53
53
54
60
61
61
62
64
65
65
66
66
66
67
67
68
68
70
71
72

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

0. INTRODUCCIN
0.1 OBJETIVO DEL DOCUMENTO
La intencin de este guin es ensear los conceptos de la librera grfica OpenGL, es
decir la aplicacin de los conceptos de grficos por computador con una implementacin
concreta, la de OpenGL. Por ello, no se explican los fundamentos de estos conceptos, que
se pueden adquirir en la asignatura de Grficos por computador y multimedia o en la
amplia bibliografa existente.
A lo largo de los captulos de este guin se describe la realizacin de una aplicacin
con OpenGL, de modo que al final se disponga de una aplicacin til, prcticamente
distribuible a usuarios finales. Se ha preferido dar una unidad a todas las prcticas, en lugar
de estudiar los temas de forma independiente, para comprender mejor la estructura de una
aplicacin grfica, a la vez que se puede comprobar el resultado de lo realizado.
La aplicacin que se ha elegido realizar es TecnunLogo, que consiste en una
aplicacin del lenguaje de programacin Logo, desarrollado por el MIT en los aos 70 y
que ha sido el primer de contacto de innumerables personas con el mundo de la
informtica. Lo caracterstico de TecnunLogo es que se realiza en un entorno
tridimensional con lo que se gana enormemente en realismo y permite nuevas aplicaciones
del Logo para la enseanza.
0.2 DESCRIPCIN DE LOGO
Logo es un lenguaje que esta pensado para ensear conceptos matemticos y de
programacin especialmente a nios. En sus comienzos se daba rdenes (FORWARD,
RIGHT, ) desde le teclado a un pequeo robot
conectado al ordenador mediante un cable y este se mova
por el suelo respondiendo a las rdenes.
Por su aspecto, a este dispositivo se le denomin
tortuga, y al lenguage Logo se le denomina el lenguaje de
la tortuga.
Cuando los ordenadores dispusieron de capacidades
grficas, la tortuga se dibujaba en la pantalla del
ordenador. Uno de estos programas es el que se muestra
en la figura (la tortuga se representa en este caso con un
tringulo).
0.3 ENTORNO DE VISUALIZACIN TRIDIMENSIONAL
En tecnunLogo la tortuga o el objeto que se maneja se representa en un espacio
tridimensional, esto es, los objetos tienen tres dimensiones por lo que lo que se muestra en
la pantalla, es una proyeccin. En una representacin tridimensional, adems de la
proyeccin aparecen nuevos conceptos como son el del modelado de los objetos, los
parmetros de visualizacin, la iluminacin, las texturas, etc.
A lo largo de los distintos captulos se van a ir incorporando distintas caractersticas
a la aplicacin, que van a convertir a TecnunLogo, en un entorno de visualizacin

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

interactivo. Es decir, sirve para visualizar objetos tridimensionales incluyendo la


animacin de los mismos.
0.4 CONTENIDO DEL DOCUMENTO
Los distintos captulos de esta gua van a introducir las caractersticas de una
aplicacin con grficos 3D e incorporarlas a la aplicacin TecnunLogo.
En el captulo 1 se realiza una introduccin a la librera grfica OpenGL, realizando
el primer programa, que simplemente abre una ventana grfica. Se introduce la librera
GLUT que permite crear los elementos del interfaz de usuario. Se finaliza el captulo
realizando la representacin de distintos objetos en la ventana tridimensional.
En el captulo 2 se introduce el concepto de transformacin y de las matrices que las
definen, tanto de transformaciones de modelado como de proyeccin. Se utilizan estos
conceptos para implementar las primeras rdenes de Logo: FORWARD, RIGHT, LEFT,
UP y DOWN.
En el captulo 3 se manipulan las matrices de transformacin con los comandos
especficos de OpenGL para dibujar el camino que realiza la tortuga.
En el captulo 4 se describe la utilizacin de las cmaras y su control para visualizar
la escena desde distintos puntos de vistas y propiedades. Este control se realiza con
distintos modos de movimiento de la cmara y del punto de atencin.
En el captulo 5 se representan objetos slidos sombreados y se definen luces en la
escena. Se controla la posicin y estado de las luces mediante el interface de usuario.
En el captulo 6 se explican y utilizan los distintos tipos de luces: direccionales,
posicionales y focales. Se describen las propiedades de estas las luces y el modo de
controlarlas por el usuario.
En el captulo 7 se utilizan objetos modelados externamente a la aplicacin. Es un
ejemplo de utilizacin de una librera externa. En este caso la librera proporciona las
funciones para leer la estructura de un objeto desde un fichero en formato Wavefront y
representarlo. Se permite tambin el disponer de varias tortugas controladas de forma
independiente.
En el captulo 8 se utilizan otras propiedades para describir como se debe realizar la
representacin en OpenGL.
En el captulo 9 se crean objetos para utilizarse en la aplicacin a partir del
escaneado tridimensional de objetos reales.
En el captulo 10 se describe la utilizacin de las texturas en OpenGL: como leer un
archivo de imagen para utilizarlo como textura y aplicarlo a un objeto.
0.5 AGRADECIMIENTOS
Queremos agradecer la colaboracin de Tecnun (Escuela Superior de Ingenieros) y
del departamento de Organizacin Industrial del que formamos parte y en especial la de
Alex Garca Alonso (http://www.sc.ehu.es/ccwgamoa) que adems ha facilitado parte del
material del manual.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

1. INTRODUCCIN A OPENGL: DIBUJANDO UNA TORTUGA CON OPENGL


1.1 QU ES OPENGL?
OpenGL (www.opengl.org) es una librera grfica independiente de la plataforma de
hardware. Esto es, proporciona un conjunto de funciones para representar imgenes 3D en
una aplicacin y utilizar el hardware grfico disponible. Esta librera se incluye con
prcticamente todos los sistemas operativos (Windows, MacOS, Linus, Unix).
Las funciones de OpenGL estn integradas en tarjetas grficas 3D o en su defecto se
simulan por software. El origen de OpenGL est en las funciones GL (Graphics Library)
de que disponan las estaciones de trabajo de Sillicon Graphics, Inc. (SGI) a finales de los
80. Cuando estas rutinas se extendieron a otras plataformas surgi OpenGL, con el
propsito de hacer un estndar de representacin en 3D. Se ha convertido en un estndar de
hecho al ser compatible con prcticamente cualquier plataforma harware asi como con
muchos lenguajes de programacin (C, C++, Visual Basic, Visual Fortran, Java).
1.2 ABRIENDO UNA VENTANA CON OPENGL
El objetivo de este primer ejercicio es abrir una ventana con OpenGL. Se describe
como realizar el proceso en Visual C++, para otros entornos el proceso es similar. Para ello
es necesario abrir un nuevo proyecto en Visual C++ del tipo Console Application. Para
poder ejecutar las librerias GLUT de OpenGL es necesario incluir en los siguientes
lugares, si no se encuentran ya, los ficheros que se indican (se pueden obtener en el web de
la asignatura en:
http://www.tecnun.es/asignaturas/grafcomp/openGL/files/):
- glut32.dll se debe situar en windows\system(32)
- glut32.lib se debe situar en DevStudio\Vc\lib
- glut.h se debe situar en DevStudio\Vc\include\gl
Tambin es necesario incluir las libreras opengl32.lib, glu32.lib y glut32.lib en la
lista de libreras del proyecto, en el caso de Visual C++ se accede en Project > Settings >
Link > Object/Library Modules.
Se aade un fichero de tipo texto y nombre tecnunLogo.c, mediante File > New /Text
File.
En esta prctica se va a trabajar en un nico archivo con extensin llamado
tecnunlogo.c cuyo cdigo es el siguiente:
#include <GL/glut.h>
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(512, 512);
glutInitWindowPosition(20, 20);
glutCreateWindow("tecnunLogo");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

Para poder utilizar las libreras OpenGL y GL Utility Toolkit (GLUT) es necesario
incluir el archivo glut.h como se muestra en la primera lnea de cdigo.
La funcin principal main(), incluye la llamada a glutInit() que es la funcin que
inicializa la librera GLUT. Esta librera interacciona con el sistema de ventanas para la
apertura de nuevas ventanas. Sus parmetros son los mismos que los de la funcin main().
A continuacin, glutInitDisplayMode() define el modo en el que se debe dibujar la
ventana. Sus parmetros, como en muchas de las funciones OpenGL, se definen con flags
o mscaras de bits. En este caso, GLUT_RGB indica el tipo de modelo de color con el que
se dibujar (Red-Green-Blue), GLUT_DEPTH indica que se debe incluir un buffer de
profundidad y GLUT_DOUBLE que se debe utilizar un doble buffer.
Antes de crear una ventana, es necesario definir sus propiedades. Con la funcin
glutInitWindowSize() se define el tamao de la ventana en pxeles (anchura y altura) y
con la funcin glutInitWindowPosition(), la distancia horizontal y vertical con respecto
de la esquina superior izquierda del monitor donde la ventana deber aparecer. Finalmente,
con la funcin glutCreateWindow() se crea propiamente la ventana, y el string que se
pasa como argumento, es utilizado como nombre de la nueva ventana.
Ahora que la ventana ha sido creada, es necesario mostrarla. Para ello la funcin
main llama a la funcin glutDisplayFunc(). Esta funcin es la ms importante de las
funciones callback. Gracias a la definicin de las funciones callback, GLUT hace posible
una dinmica de programacin de aplicaciones OpenGL. Una funcin callback ser
llamada por GLUT para hacer alguna operacin especifica cada vez que se produzca un
evento. En este caso, glutDisplayFunc(display), define que la funcin display que es
pasada como argumento sea ejecutada cada vez que GLUT determine que la ventana debe
ser dibujada (la primera vez que se muestra la ventana) o redibujada (cuando se maximiza,
cuando se superponen varias ventanas, etc).
La ultima funcin que es llamada en el main es glutMainLoop(). Esta funcin se
encarga de pasar el control del flujo del programa a la GLUT, de manera que cada vez que
ocurra un evento sean llamadas las funciones definidas como callbacks hasta que el la
ventana se cierre.
La funcin display(), definida como funcin callback para dibujar o redubujar la
ventana cada vez que sea necesario, esta tambin contenida en el archivo tecnunlogo.c.
Como todas las funciones callback que sern utilizadas, display() es del tipo void. Como
este ejercicio es bastante simple y no se va a dibujar ninguna figura en la ventana, el
contenido de la funcin es bastante sencillo. En ella solo se van a definir las funciones que
siempre deben aparecer en cualquier funcin display callback.
void display(void) {

glClearColor(1.0, 1.0, 1.0, 0.0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSwapBuffers();
}

La funcin display() se debe incluir antes de la funcin main() para que no se


produzca un error al compilar cuando se utiliza en la funcin main().
La funcin glClearColor() establece el color de fono de la ventana, que es con el
que se borra la ventana. A continuacin se llama, antes de dibujar cualquier cosa, a la
funcin glClear(). Esta funcin se encarga de borrar el fondo de la ventana. Acepta como
argumento el buffer especfico que se desea borrar, en este caso el
GL_COLOR_BUFFER_BIT y el GL_DEPTH_BUFFER_BIT.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

La funcin glSwapBuffers() se encarga


de intercambiar el buffer posterior con el
buffer anterior y es necesaria porque se ha
definido que se trabaja con doble buffer.
Cuando se dibuja cualquier figura, esta es
dibujada en el buffer posterior (el que est
atrs) y cuando el dibujo est terminado los
dos buffers se intercambian.
El resultado de ejecutar este proyecto es
el que se muestra en la figura 1:
1.3 DIBUJANDO

UN

TOROIDE

EN

LA

Figura 1

Ventana inicial

VENTANA

El objetivo de este ejercicio es dibujar, en la ventana del ejercicio anterior, un toroide


con un cubo inscrito en su interior. Para ello ser necesario incluir algunas operaciones
ms en la funcin display():
void display(void) {

glClearColor(1.0, 1.0, 1.0, 0.0);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glutWireTorus(0.25,0.75, 28, 28);
glColor3f(0.0,0.0,1.0) ;
glutWireCube(.60) ;
glutSwapBuffers();
}

En este ejemplo sern introducidas tres nuevas funciones GL (una funcin OpenGL y
dos funciones GLUT). La funcin OpenGL glColor3f() establece el color actual con el que
se va a dibujar una figura. El color ser el mismo hasta que se cambie el estado de esta
variable con la funcin glColor3f nuevamente. Esto es lo que se quiere decir cuando se
habla de OpenGL como una maquina de estados. Todas las funciones de OpenGL
comienzan con el prefijo gl y en muchas (como es el caso de glColor3f) aparece un
sufijo compuesto por un nmero y una letra. El nmero simboliza el numero de parmetros
que se debe pasar a la funcin y la letra, el tipo de estos parmetros. En este caso, se deben
pasar 3 parmetros de tipo float. Al estar trabajando en un modelo de color de tipo RGB
(Red-Green-Blue), cada uno de estos parmetros representa el valor de cada color
respectivamente.
La funcin GLUT glutWireTorus(0.25, 0.75, 28, 28) dibuja un toroide de frame de
hilos cuyo radio interno es el double 0,25; radio externo el double 0,75; el primer entero 28
representa el numero de lados que se puede observar en cada seccin radial y el segundo
entero 28 el numero de divisiones radiales del toroide.
La funcin GLUT glutWireCube(0.60) dibuja un cubo cuyo tamao queda
determinado por su nico parmetro de valor float.
El resultado es el que se muestra en la figura:

Dibujar los ejes del sistema de coordenadas de la ventana utlilizando los


colores rojo, verde y azul (RGB) para los ejes x, y, z
correspondientemente.
Dibujar en la ventana las diferentes primitivas de GLUT (se pueden
encontrar en el tutorial de OpenGL en el web de la asignatura).

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

1.4 DEFINIENDO EL REA DE PROYECCIN INICIAL


Una vez que se ha dibujado un objeto en la ventana es necesario definir el rea de
proyeccin inicial que se desea de la figura en la ventana. Para ello se debe manipular el
rea de proyeccin por medio de la funcin callback glutReshapeFunc(). Esta funcin
callback especifica cul funcin ser llamada cada vez que la ventana sea redimensionada
o movida, pero tambin es utilizada para definir inicialmente el rea de proyeccin de la
figura en la ventana.
Muchas de las funciones que OpenGL pone a disposicin para definir la proyeccin
estn basadas en matrices de transformacin que, aplicadas sobre el sistema de
coordenadas de la ventana, definen el punto desde donde ser observada la figura. Estas
matrices y sus transformaciones se explicarn con ms detenimiento en el siguiente
capitulo.
Antes de explicar el cdigo de este ejercicio es conveniente recordar la disposicin
del sistema de coordenadas de OpenGL, en el que el eje vertical es el Y y el eje de visin
por defecto es el Z.
Y

X
Z

Observador
Figura 3

Sistema de Coordenadas de OpenGL

La funcin glutReshapeFunc(reshape) debe ser incluida en el cdigo de la funcin


main():
glutReshapeFunc(reshape);

A continuacin se define la funcion reshape():


void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)height / (GLfloat)width, 1.0, 128.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

De nuevo, como toda funcin callback, la funcin reshape() es del tipo void. Se le
pasan como argumentos el ancho y el alto de la ventana despus del reescalado. La funcin
glViewport define la porcin de ventana donde OpenGL podr dibujar. Sus parmetros
son: primero la distancia horizontal y vertical de la esquina superior izquierda del cuadro
donde OpenGL puede dibujar con respecto a la ventana; segundo, el ancho y alto de la
ventana.
A continuacin, glMatrixMode() especifica la matriz de transformacin sobre la que
se van a realizar las operaciones siguientes (de nuevo, recordar que OpenGL es una
maquina de estados). Los tres tipos de matrices que existen son: matriz de proyeccin

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

(GL_PROJECTION), matriz de modelado (GL_MODELVIEW) y matriz de textura


(GL_TEXTURE).
En este caso, glMatrixMode(GL_PROJECTION) afecta la perspectiva de la
proyeccin. La funcin glLoadIdentity() carga como matriz de proyeccin la matriz
identidad. Esto es como inicializar a uno los valores de dicha matriz. gluPerspective()
opera sobre la matriz de proyeccin y define el ngulo del campo de visin en sentido
vertical (en grados), la relacin entre la altura y la anchura de la figura (aspecto), el plano
ms cercano a la cmara y el plano ms lejano de la cmara, respectivamente. Estos dos
ltimos son los planos de corte, que son los que se encargan de acotar el volumen de
visualizacin por delante y por detrs de la figura. Todo lo que est por delante del plano
ms cercano y todo lo que est detrs del plano ms lejano no ser representado en la
ventana.
Ahora, glMatrixMode(GL_MODELVIEW) define que las operaciones que se
realicen a continuacin afectarn a la matriz de modelado. Nuevamente se carga la matriz
identidad por medio de la funcin glLoadIdentity. A continuacin, gluLookAt() define la
transformacin sobre la vista inicial. Esta funcin junto con gluPerspective() se explican
con detalle en el captulo 3, pero aqu se hacer una rpida descripcin.
La funcin gluLookAt() tiene 9 parmetros: los primeros tres representan la
distancia en x, y, z de los ojos del observador; los siguientes tres, las coordenadas x, y, z
del punto de referencia a observar y los ltimos tres, la direccin del upVector.

Modificar la funcin glView port de manera que al alargar la ventana la


figura no se deforme. Se logra haciendo que el viewport sea siempre
cuadrada, de dimensin el menor de los valores de la altura y la
anchura. El valor de la relacin entre la altura y la anchura para la
funcin gluPerspective() es ahora siempre 1.
Probar diferentes vistas iniciales con la funcin gluLookAt.
1.5 INTERACTUANDOCON EL TECLADO
El objetivo de este ejercicio es aadir la posibilidad de interactuar desde el teclado
del ordenador con la figura representada en la ventana. De nuevo utilizaremos una funcin
callback para este propsito, ya que es la GLUT, por medio de este tipo de funciones,
quien gestiona cualquier tipo de evento .
Es necesario incluir en el main del programa la funcin callback
glutKeyboardFunc(keyboard):
glutKeyboardFunc(keyboard);

La funcin keyboard() que es pasada como parmetro ser llamada cada vez que
ocurra un evento en el teclado. Se define a continuacin la funcin keyboard():
void keyboard(char key, int x, int y) {
switch (key) {
case h:
printf("help\n\n");
printf("c
- Toggle culling\n");
printf("q/escape
- Quit\n\n");
break;
case c:
if (glIsEnabled(GL_CULL_FACE))
glDisable(GL_CULL_FACE);
else
glEnable(GL_CULL_FACE);
break;
case 1:
glRotatef(1.0,1.,0.,0.);

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

10

break;
case 2:
glRotatef(1.0,0.,1.,0.);
break;
case q:
case 27:
exit(0);
break;
}
glutPostRedisplay();
}

Un bucle switch-case se encarga de identificar que tecla ha sido pulsada. Si la tecla


presionada es la h, se escribirn en la pantalla de la consola las indicaciones del
funcionamiento del programa. Con las funciones glEnable(GL_CULL_FACE) y
glDisable(GL_CULL_FACE) se muestran o se ocultan las lneas de las caras traseras de la
figura. Si la tecla es la c y las lneas traseras estn activadas, entonces se desactivan. En
caso contrario, se activan. La tecla 1 har que la figura rote por medio de la funcin
glRotatef()
cuyos
parmetros
corresponden al ngulo a rotar y a
los componentes x, y, z del eje sobre
el que va a rotar la figura. Se habla
en todo momento que es la figura
quien va a rotar porque es la matriz
de modelado la ultima que fue
cargada. La tecla 2 har que la
figura rote en el eje y. Esta funcin y
su efecto en la matriz de modelado
se trata en el siguietne captulo.
Finalmente, la tecla q produce la
finalizacin del programa.
En la figura 4 se muestra el
efecto de rotar la figura con las teclas
1 y 2.
Es importante observar que al
Figura 4
Ventana con respuesta al teclado
final de la funcin keyboard() esta
la llamada a la funcin GLUT glutPostRedisplay(). Esta funcin da la indicacin a la
GLUT que es necesario redibujar la ventana. Si no se incluyera esta rutina, OpenGL no
sabra que tiene que redibujar la ventana cuando se ha presionado una tecla.

Introducir un comando nuevo de manera que al apretar la tecla a


(axis), se muestren los ejes de la figura si estn desactivados, o se
desactiven si estn activados.
Introducir otro comando de manera que con las teclas u, d, r y l
(up, down, right, left) se tralade la cmara manipulando la funcin
gluLookAt.
1.6 REPRESENTANDO UNA TORTUGA
La funcin glBegin comienza una secuencia de vrtices con los que es posible
dibujar polgonos. De esta manera, definiendo puntos, OpenGL da la oportunidad de
construir nuevos elementos a base de lneas y polgonos. El parmetro de glBegin es el tipo
de primitiva que se va a definir (triangle, poligon, etc.) Los vrtices (puntos en un espacio
3D) se definen en OpenGL con la funcin glVertex3f() o glVertex3d().

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

11

Realizar la funcin draw Turtle() que dibujar por medio de la funcin


glBegin( ) una tortuga. Los puntos de la tortuga se almacenan en dos
vectores x[] y z[] , y despues se llama a la funcin glVertex3d() dentro
de un bucle que recorre las coordenadas de estos vectores. Al ser la
tortuga simtrica slo es necesario definir la mitad y volver a recorrer
los puntos en orden inverso. La
funcin draw Turtle() ser llamada
desde la funcin display().
Vector de coordenadas x:
double x[] = {0.0, 0.1, ...};

Bucle for:

for (i=0; i < npoints; i++){

Comparar la utilizacin de
glBegin(GL_LINE_LOOP);

glBegin(GL_POLYGON);

En la figura 5 se muestra el resultado


con GL_LINE_LOOP
Realizar
la
funcin
draw SphereTurtle() que dibuja
una tortuga mediante la primitiva de
la funcin glutWireSphere(). Esta
funcin tiene como argumentos el
radio y la precisin en latitud y
longitud.
En la figura 6 se muestra el resultado
utilizando 6 esferas. La precisin
utilizada en ambos ejes es de 10.

Figura 5

Figura 6

Tortuga con GL_LINE_LOOP

Tortuga con WireSphere s

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

12

2. TRANSFORMACIONES: DANDO RDENES A LA TORTUGA (FORWARD,


RIGHT, LEFT, UP Y DOWN)
En el presente captulo se introduce el concepto de transformacin y de las matrices
que las definen, tanto de transformaciones de modelado como de proyeccin. Se utilizarn
posteriormente estos conceptos para implementar las primeras rdenes de Logo:
FORWARD, RIGHT, LEFT, UP y DOWN.
2.1 TRANSFORMACIONES DE MODELADO Y DE PROYECCIN
La representacin de las primitivas y de los objetos se realiza transformando las
coordenadas originales. Estas transformaciones pueden originarse debido a cambios en el
modelo o a las propiedades de la cmara. Las propiedades de la cmara se vern en el
siguiente captulo. En el presente captulo veremos como afectan los cambios al modelo.
OpenGL dispone de tres matrices para realizar el proceso. Se especifican por los
nombres:
GL_MODELVIEW: la matriz que contiene las transformaciones originadas por los
cambios de modelado y posicin de la cmara.
GL_PROJECTION: la matriz con las transformaciones que realizan la proyeccin de
la escena de 3 a 2 dimensiones.
GL_TEXTURE: para transformaciones en las coordenadas de textura.
Por ello, antes de realizar una operacin de transformacin es necesario indicar sobre
que matriz se va a realizar. Se especifica con la funcin glMatrixMode(Glenum mode)
que tiene como argumento una de las tres constantes enumeradas. Se comporta como un
estado, por tanto, hasta que se especifique un nuevo estado todas las transformaciones se
realizan sobre la ltima matriz especificada.
En el cdigo de la funcin resaphe() del captulo anterior:
void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)height / (GLfloat)width, 1.0, 128.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

Se observa que se utiliza la funcin glMatrixMode() dos veces, la primera con


GL_PROJECTION y la segunda con GL_MODELVIEW .
Despues de la primera llamada a glMatrixMode(), la matriz sobre la que se
realizarn las transformaciones es GL_PROJECTION, la primera operacin es inicializar la
matriz con la funcin glLoadIdentity() que carga la matriz identidad y se define una
proyeccin perspectiva con la funcin gluPerspective(). Esta funcin se explica en el
siguiente captulo.
Despues de la segunda llamada a glMatrixMode(), la matriz sobre la que se
realizarn las transformaciones es GL_MODELVIEW, igualmente, la primera operacin es
inicializar la matriz con la funcin glLoadIdentity() y a continuacin se establece la
posicin de la cmara con gluLookAt(). Esta funcin se explicar con ms detalle en el
siguiente captulo.
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

13

Al comportarse OpenGL como una mquina de estados, las siguientes operaciones


de transformacin que se realicen en el cdigo, que estarn fuera de la funcin resaphe(),
se realizarn sobre la ltima matriz especificada, es decir sobre GL_MODELVIEW.
2.2 INTERPRETANDO LOS COMANDOS
La aplicacin TecnunLogo lee comandos introducidos por el teclado y los interpreta
para su ejecucin. Los comandos que inicialmente interpreta son los correspondientes a
avanzar, retroceder, girar a la derecha, girar a la izquierda, girar hacia arriba y girar hacia
abajo. En la siguiente tabla se muestran estos comandos, con la descripcin y la abreviatura
que se utiliza en el interprete:
Comando

Abreviatura

Descripcin

Argumento

FORWARD

fd

Avanza hacia adelante

Unidades de distancia

RIGHT

rt

Gira a la derecha

Grados (0 360)

LEFT

lt

Gira a la izquierda

Grados (0 360)

BACK

bk

Retrocede

Unidades de distancia

UPPITCH

up

Gira hacia arriba

Grados (0 360)

DOWNPITCH

down

Gira hacia abajo

Grados (0 360)

EXIT

exit

Sale del modo logo

HOME

home

Posicionarse en el inicio

La funcin parseCommand realiza la interpretacin del comando y llama a la funcin


de OpenGL correspondiente.
void parseCommand(char* strCommandParse) {
char *strToken0;
char *strToken1;
double val;
strToken0 = strtok(strCommandParse, " ");
while ((strToken1 = strtok(NULL," ")) != NULL) {
val = atof(strToken1);
if (!strcmp("fd",strToken0)) { // FORWARD
glTranslatef(0.0, 0.0, val);
} else if (!strcmp("bk",strToken0)) { // BACK
glTranslatef(0.0, 0.0, -val);
} else if (!strcmp("rt",strToken0)) { // RIGHT
glRotatef(-val,0.,1.,0.);
} else if (!strcmp("lt",strToken0)) { // LEFT
glRotatef(val,0.,1.,0.);
} else if (!strcmp("up",strToken0)) { // UP
glRotatef(val,1.,0.,0.);
} else if (!strcmp("dn",strToken0)) { // DOWN
glRotatef(-val,1.,0.,0.);
}
strToken0 = strtok(NULL, " ");
display();
}
// EXIT COMMAND MODE
if (strToken0 != NULL && strncmp(strToken0, "exit", 4) == 0) {
command = FALSE;
// HOME
} else if (strToken0 != NULL && !strcmp("home",strToken0)) {
glLoadIdentity();
}
}
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

14

Se emplea la funcin char* strtok(s, ct) de la librera <string.h> que busca elementos
en la cadena s , separados por los carcteres ct . En este caso los caracteres separadores
es el espacio en blanco.
El primer elemento strToken0 es la instruccin Logo y el segundo elemento
strToken1 es el argumento. A continuacin se compara el texto de la instruccin con las
distintas posibilidades (fd, rt, lt, ...) y se ejectua la accin correspondiente. En este caso, el
cuerpo de la accin muy reducido, se inserta a continuacin en lugar de realizar una
funcin separada.
Para introducir las instrucciones Logo, se debe pasar al modo interprete. Esto se
realiza pulsando la tecla i , con lo que los caracteres introducidos a continuacin se
almacenan en una cadena hasta que se pulsa la tecla retorno (ASCII: 13).
Se aade la librera stdio.h y las variables globales command y strCommand que
indican respectivamente si est en modo comando y la cadena de texto introducida hasta el
momento:
#include <stdio.h>
boolean command = FALSE;
char strCommand[256];

/* command mode */

La funcin keyboard() posee el siguiente cdigo:


void keyboard(char key, int x, int y) {
if (command) {
if (key == 13) {
strcat(strCommand, " ");
if (strlen(strCommand) == 1) command = FALSE;
parseCommand(strCommand);
strcpy(strCommand, "");
} else {
char strKey[2] = " ";
strKey[0] = key;
printf(strKey);
strcat(strCommand, strKey);
}
} else { // not in command mode
switch (key) {
case h:
...
case i:
command = TRUE;
break;
...
case 27:
exit(0);
break;
}
}
glutPostRedisplay();
}

Se emplea la variable booleana command para determinar si est en modo


interprete o no. Al pulsar la tecla i se activa el modo interprete.
Primeramente se comprueba si est en modo interprete:
case i:
command = TRUE;

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

15

Si se est en modo interprete, las teclas pulsadas se controlan en el bloque if


(command) , en el cual se detemina si se ha pulsado la tecla retorno, en cuyo caso se
procede a ejecutar el comando o si no, se aade el carcter a la cadena de caracteres que va
almacenando la instruccin. Si se pulsa la tecla retorno, sin haber ninguna instruccin, se
vuelve al modo interactivo, en el cual determinadas teclas tiene asociadas distintas
funciones.
Las distintas instrucciones que reconoce el interprete se corresponden con las
sentencias de OpenGL para variar la matriz GL_MODELVIEW. Las tres funciones de
OpenGL para realizar transformaciones de modelado son glTranslate(), glRotate() y
glScale(). Cada una de ellas puede tener argumentos en precisin simple (float) o doble
(double), como por ejemplo glTranslatef() y glTranslated()
2.3 TRASLACIN
Realiza una traslacin a las coordenadas x, y, z. Se realiza con la funcin glTraslate()
que tiene como argumentos estos tres valores. La funcin realiza la multiplicacin de la
matriz actual por la matriz de traslacin que se compone con estos tres valores.
En la aplicacin de TecnunLogo se utiliza en los comandos FORWARD Y BACK
if (!strcmp("fd",strToken0)) { // FORWARD
glTranslatef(0.0, 0.0, val);
} else if (!strcmp("bk",strToken0)) { // BACK
glTranslatef(0.0, 0.0, -val);

Se realiza un desplazamiento segn el eje Z, que es el eje de visualizacin en sentido


positivo para FORWARD o negativo para BACK. En la figura 1 se muestra la tortuga en
su posicin inicial y en la figura 2 una vez trasladada, en esta figura se ha conservado
tambin la posicin inicial.

Figura 1

Posicin inicial

Figura 2

Posicin inicial y trasladada

2.4 ROTACIN
La funcin de OpenGL para aplicar una rotacin es glRotate(). Tiene cuatro
argumentos: el primero es el ngulo que se desea girar en grados sexagesimales en sentido
contrario a las agujas del reloj; los siguientes tres argumentos definen las coordendas x, y,
z del eje alrededor del cual se realiza el giro. El eje pasa por el origen de coordendas, por
lo tanto, si el objeto est alejado de este eje, se producir un desplazamiento causado por la
rotacin, es decir, no solo girar. Si de desea evitar este desplazamiento ser necesario

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

16

primeramente trasladar el objeto al origen, realizar la rotacin y realizar la traslacin


inversa.
La funcin glRotate() multiplica la matriz actual por la matriz de rotacin creada con
estos cuatro argumentos.
En la aplicacin de TecnunLogo se utiliza en los comandos RIGTH, LEFT, UP Y
DOWN:
} else if (!strcmp("rt",strToken0))
glRotatef(-val,0.,1.,0.);
} else if (!strcmp("lt",strToken0))
glRotatef(val,0.,1.,0.);
} else if (!strcmp("up",strToken0))
glRotatef(val,1.,0.,0.);
} else if (!strcmp("dn",strToken0))
glRotatef(-val,1.,0.,0.);

{ // RIGTH
{ // LEFT
{ // UP
{ // DOWN

En las instrucciones RIGTH y LEFT se realiza el


giro alrededor del eje verical Y y en las instrucciones
UP Y DOWN alrededor del eje horizontal X . En la
figura 3 se muestra el efecto de un giro a la derecha 2rt
90 .

Implementar las instrucciones RIGHTROLL y


LEFTROLL con las abreviaturas rr y lr, que
realizan un giro alrededor del eje Z.
2.5 ESCALADO
Adems de poder situar el objeto en distintas
posiciones mediante traslaciones y rotaciones, OpenGL
Figura 3
Giro a la derecha
dispone de la funcin glScalef() para cambiar el tamao
de los objetos.
Posee 3 argumentos que son los factores de escala para cada uno de los tres ejes, de
manera que si estos valores no son iguales, adems de cambiar el tamao, se realiza una
deformacin del objeto. Los factores mayores de 1 aumentan las coordenadas y los
menores de 1 las disminuyen.
La funcin glScalef() multiplica la matriz actual por la matriz de escala generada.
El escalado se realiza a partir del origen, por lo que las nuevas coordenadas se
calculan a partir de este sistema de referencia. Por ejemplo si hay un cubo definido en el
eje X entre las coordendas 3 y 4, al aplicarle una escala de factor 2 segn este eje, el cubo
se encontrar ahora situado entre las coordenadas 4 y 6. Si se quiere evitar este
desplazamiento, al igual que se ha indicado en la rotacin, ser necesario primero realizar
una traslacin, aplicar el cambio de escala deseado y finalmente realizar la traslacin
inversa.

Incluir en la aplicacin las instrucciones para cambiar el tamao del


objeto: SCALEX, SCALEY y SCALEZ, con las abreviaturas sx, sy, sz. El
argumento que se proporciona es el factor de escala. Para disminuir el
tamao basta emplear un factor menor a la unidad.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

17

Los nuevos comandos introducidos son:


Comando
RIGHTROLL

AbreviaDescripcin
Argumento
tura
rr
Rota hacia la derecha segn el eje Grados (0 360)
de avance

LEFTROLL

lr

Rota hacia la izquierda segn el Grados (0 360)


eje de avance

SCALEX

sx

Multiplica las coordenadas x por Factor de escala


el factor de escala

SCALEY

sy

Multiplica las coordenadas y por Factor de escala


el factor de escala

SCALEZ

sz

Multiplica las coordenadas z por Factor de escala


el factor de escala

2.6 ORDEN DE LAS TRANSFORMACIONES


Las transformaciones de coordenadas no disponen de la propiedad conmutativa (si la
disponene si slo se realizan traslaciones o slo cambios de escala). Se puede comprobar al
ver el efecto de una traslacin seguida de una rotacin el efecto del proceso en el orden
inverso: primero la rotacin y despus la traslacin.
Si se realizan las pruebas con la aplicacin desarrollada hasta ahora, por ejemplo rt
90 fd 2 , esta se comporta como uno espera que se comporte la tortuga de Logo, es decir,
si se realizado un giro a la derecha y a continuacin se da la orden de avanzar, se realiza la
traslacin segn la direccin en la que est mirando actualmente la tortuga. Sin embargo, si
pensamos en las funciones OpenGL a las que llama el interprete, se estn dando las
rdenes:
glRotatef(-90,0.,1.,0.);
glTranslatef(0.0, 0.0, 2);

Con lo cual, si realizamos mentalemente estas transformaciones, la primera gira el


objeto en eje Y , en concordancia con lo que realiza la aplicacin, pero la segunda
transformacin est dando la orden de trasladar segn el eje Z, es decir que la tortuga se
desplazara derrapando en direccin Z. Porqu la tortuga entonces avanza segn la nueva
direccin? La respuesta es que en OpenGL las transformaciones se producen en el orden
inverso en el que se han definido. Al ver el efecto de las nuevas transformaciones, puede
parecer ms sorprendente, porque ahora lo que ocurre es que primero se produce la
traslacin y despues de la rotacin. Sin embargo, si se realizan los dos movimientos se
puede comprobar que la posicin final es la misma que se espera obtener pensando como
la tortuga: se realiza una tranlacin en sentido Z de dos unidades, se gira alrededor del eje
Y 90 grados, con lo que el objeto situado en el eje Z pasa a estar situado en el eje X. Se
puede comprobar que se produce el mismo resultado independiente del nmero y tipo de
las transformaciones.
2.7 EJEMPLO DE BUCLE REPEAT
Una instruccin que aade bastante potencia a Logo es REPEAT, que permite
realizar bucles. La sintaxis es:
REPEAT n [instrucciones]

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

18

Este comando realiza n veces las instrucciones escritas entre corchetes. Admite
anidaciones de cualquier nivel como en todos los lenguajes de programacin.
En la aplicacin tecnunLogo se implementa este comando con una inclusin en la
funcin parseCommand() y la funcin insideRepeat():
char * insideRepeat(char* strCommandInside) {
char *ini, *fin;
ini = strchr(strCommandInside,[);
if (ini == NULL) return NULL;
ini++;
fin = strrchr(strCommandInside,]);
if (fin == NULL) return NULL;
strCommandInside[fin-strCommandInside]=0;
return ini;
}

En parseCommand() se incluye antes del if de comprobacin de las instrucciones


existentes, la comprobacin de repeat .
if (!strcmp("repeat",strToken0)) {
repeatCommand = insideRepeat(strToken1 + strlen(strToken1) + 1);
if (repeatCommand == NULL) return;
nextCommand = repeatCommand + strlen(repeatCommand) + 1;
for (i = 0; i < val; i++) {
strcpy (parseCommandInit, repeatCommand);
parseCommand(parseCommandInit);
}
strToken0 = strtok(nextCommand, " ");
if (strToken0 == NULL) continue;
continue;
}

Se incluyen tambien las declaraciones correspondientes:


char *repeatCommand;
char *nextCommand;
char parseCommandInit[256];
int i;

2.8 PUNTOS A REALIZAR

Dibujar unos ejes del mundo y otros en el sistema de la tortuga como


los que se muestran en la figura 2.
Utilizando los comandos de logo dar las instrucciones para que la
tortuga se desplaze en una circunferencia.
Leer comandos desde un fichero, la instruccin se define LOAD
nombreFichero, el fichero contiene 1 o varias lneas de sentencias de
logo.
Definir el sistema de medida de ngulos, de forma que en vez de utilizar
el sistema sexagesimal de 0 a 360, se pueda utilizar cualquier otro;
como radianes de 0 a 2p; grados centesimales, de 0 a 400 o cualquier
otro como de 0 a 12 o 0 a 60 como las horas o minutos de un reloj.
Utilizar para ello el comando SETCIRCLE nn, siendo nn el nmero
correspondiente a la medida de un giro completo. Por defecto el valor
es 360. La abreviatura del comando es sc.
Implementar los comandos HIDETURTLE y SHOWTURTLE, con las
abreviaturas ht y st que muestran u ocultan la torguga.
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

19

3. OPERACIONES CON MATRICES: DIBUJANDO EL CAMINO


La transformacin de las coordenadas se realiza internamente en OpenGL a partir de
las matrices de transformacin y de las coordenadas de modelado del objeto. Sin embargo,
para representar el rastro que dibuja la tortuga al desplazarse, se realizar explcitamente la
transformacin de la coordenada en la que se encuentra la tortuga. De esta forma se acta
directamente en la matriz de transformacin.
3.1 LA PILA DE MATRICES
En la funcin display() se encuentran las llamadas a dos funciones de matrices que
todava no han sido comentadas. Se trata de glPushMatrix() y glPopMatrix(). Para
comprender su funcionamiento, primero se va a experimentar que es lo que ocurre cuando
no estn dichas llamadas. Para ello se comentan en la funcin display() ambas llamadas:
void display(void) {
...
// glPushMatrix();
...
glTranslatef(0.0, 0.0, .5);
...
// glPopMatrix();
glutSwapBuffers();
}

Al ejecutar de nuevo la aplicacin, primeramente tiene el mismo aspecto que sin


comentar las llamadas, pero si obligamos a que se llame varias veces a la funcin
display(), por ejemplo pulsando la tecla c (que activa y desactiva los polgonos
posteriores del objeto), vemos que adems de producirse el efecto de cambiar el modo
GL_CULL_FACE, el objeto se va moviendo progresivamente a lo largo de eje Z .
La razn de este movimiento es que en la funcin display est incluida una llamada a
glTranslatef() que se utiliza para posicionar uno de los objetos. Como se ha explicado
anteriormente, las funciones de traslacin multiplican la matriz actual por una matriz de
traslacin creada con los argumentos que se le pasan, por tanto, sucesivas llamadas a la
funcin display() provocan sucesivas multiplicaciones de la matriz actual con el efecto que
se observa de incrementar la traslacin.
Para solucionar este problema OpenGL dispone de unos stacks o pilas de matrices,
que permiten almacenar y recuperar una matriz anterior. Aunque OpenGL dispone de pilas
para las matrices GL_MODELVIEW y GL_PROJECTION, slo se suele utilizar la pila de
GL_MODELVIEW.
Una pila es un almacn con funcionamiento LIFO, el ltimo en entrar es el primero
en salir, por lo que suele comparar a una pila de platos en la que slo se puede dejar uno
encima de la pila o coger el superior que es el ltimo depositado. La pila de matrices tiene
el mismo funcionamiento sustituyendo los platos por matrices. La matriz superior de la pila
es sobre la que se aplican las distintas transformaciones, multiplicndola por la matriz que
generan las disntintas funciones.
Para poder guardar una determinada matriz y posteriormente recuperarla OpenGL
dispone de las dos funciones comentadas: glPushMatrix() y glPopMatrix().
La funcin glPushMatrix() realiza una copia de la matriz superior y la pone encima
de la pila, de tal forma que las dos matrices superiores son iguales. En la figura 1 se
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

20

observa la pila en la situacin inicial con una sola matriz, al llamar a la funcin
glPushMatrix() se duplica la matriz superior. Las siguientes transformaciones que se
realizan se aplican slo a la matriz superior de la pila, quedando la anterior con los valores
que tena en el momento de llamar a la funcin glPushMatrix().
La funcin glPopMatrix() elimina la matriz superior, quedando en la parte superior
de la pila la matriz que estaba en el momento de llamar a la funcin glPushMatrix().

Push
Figura 1

Translate

Pop

PushMatrix y PopMatrix

En la funcin display() al llamar a la funcin glPushMatrix() se realiza una copia de


la matriz actual. La traslacin en el eje Z se realiza en la matriz superior de la pila, es decir,
en la copia de la matriz, de tal forma que al llamar a la funcin glPopMatrix(), como se
muestra en la figura 1, se elimina la matriz superior, que es la que tena el efecto de esta
transformacin, quedando la matriz que estaba en el momento de llamar a glPushMatrix().
Al descomentar las llamadas a las funciones glPushMatrix() y glPopMatrix() las
transformaciones realizadas entre ambas no afectan al resto de la aplicacin.
3.2 DIBUJANDO UN RASTRO
Una caracterstica de Logo es que la tortuga al avanzar va dibujando el camino por el
que ha pasado. Hasta ahora la aplicacin va transformando las coordenadas del objeto para
situarlo en la nueva posicin segn las instrucciones introducidas pero no muestra la ruta
seguida.
Para mostrar la ruta es necesario almacenar los puntos por los que pasa la tortuga. El
rastro consistir en una lnea que una estos puntos.
Necesitaremos realizar tres operaciones: calcular la coordendas donde se encuentra la
tortuga, almacenar dicha coordenada y dibujar el rastro.
Para almacenar los puntos se utiliza una variable para indicar el nmero de puntos y
tres vectores para las coordenadas x, y, z.
int np =
float px
float py
float pz

0;
[10000];
[10000];
[10000];

Para calcular las coordenadas de la tortuga es necesario conocer la matriz de


transformacin de modelado. Debido a que en OpenGL, la matriz de modelado se
almacena junto con la de visualizacin en la matriz GL_MODELVIEW, es necesario
guardar de modo independiente esta matriz de modelado. Para ello definimos la variable
mModel, como una variable global, ya que va a ser accedida en distinos puntos de la
aplicacin:
GLdouble mModel[16];

Para obtener la matriz actual de una de las pilas se dispone de la funcin de OpenGL
glGetDoublev() a la que se indica que matriz se quiere obtener, GL_MODELVIEW en
nuestro caso, y un puntero a un vector de 16 posiciones donde se rellenarn los valores de
la matriz.
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

21

Hay que tener en cuenta que OpenGL almacena esta matriz por columnas de modo
que los elementos son:

m1
m
M = 2
m3

m4

m5
m6
m7
m8

m9
m10
m11
m12

m13
m14
m15

m16

Para operar con la matriz mModel, se cargar en la pila de matrices de


GL_MODELVIEW despues de realizar un PushMatrix(), de modo que no altere la matriz
actual. En la funcin main() se inicializa esta matriz con el cdigo:
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glGetDoublev (GL_MODELVIEW_MATRIX, mModel);
glPopMatrix();

En este cdigo se realizan las siguientes operaciones:

se indica primeramente sobre que matriz se van a realizar las opereraciones


con glMatrixMode();
se crea una nueva matriz con glPushMatrix();
se carga la matriz identidad con glLoadIdentity();
se almacena la matriz superior de la pila en el vector mModel con la fucnin
glGetDoublev();
y finalmente se elimina la matriz superior de la pila con glPopMatrix() para
dejar la que estaba antes de este proceso.

En realidad todo este proceso lo que ha hecho ha sido inicializar la matriz que
represena mModel con la matriz identidad.
Para guardar las distintas transformaciones que se realizan con las instrucciones de
logo (FORWARD, RIGHT, ...), se carga la matriz mModel en la pila, antes del bloque de
if que determinan que instruccin se va a realizar:
glPushMatrix();
glLoadIdentity();
glMultMatrixd(mModel);

La funcin glMultMatrixd() multiplica la matriz superior de la pila por la matriz


que tiene como argumento. Al multiplicar en este caso por la matriz identidad, la matriz
que queda en la posicin superior de la pila es mModel.
A continuacin se realiza la operaci correspondiente a la instruccin dada
(glTranslate(), glRotate(), ...) que actuar sobre esta matriz.
Al finalizar el bloque if se recupera la matriz mModel y se restaura la que estaba
previamente en la pila con el cdigo:
glGetDoublev (GL_MODELVIEW_MATRIX, mModel);
glPopMatrix();

Para conocer las coordenadas de la tortuga en la situacin actual, el proceso que se


realiza es obtener la matriz de modelado despues de la transformacin y aplicar dicha
matriz de transformacin sobre la coordenada original de la tortuga. Esto se realiza en la
funcin addPointToTrace(), que aade un nuevo punto a la lista de coordenadas.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

22

void addPointToTrace() {
int i;
GLdouble m[16];
glGetDoublev (GL_MODELVIEW_MATRIX, m);
// print the matrix
printf ("\nMatrix:\n");
for (i = 0; i < 4; i++) {
printf ("Row %i: %f \t%f \t%f \t%f \n",
i+1, m[i+0],m[i+4],m[i+8],m[i+12]);
}
// if is the first point
if (np == 0) { // add the first point
px [0] = 0;
py [0] = 0;
pz [0] = 0;
np++;
}
px [np] = m[0] * px [0] + m[4] * py [0] + m[8] * pz [0] + m[12];
py [np] = m[1] * px [0] + m[5] * py [0] + m[9] * pz [0] + m[13];
pz [np] = m[2] * px [0] + m[6] * py [0] + m[10] * pz [0] + m[14];
printf ("Point %i: %f \t%f \t%f \n",
np, px[np],py[np],pz[np]);
np++;
}

La matriz se obtiene de la pila en lugar de ser mModel, porque esta ltima todava no
tiene incorporada la ultima transformacin realizada.
El proceso de la funcin addPointToTrace() consiste en:

obtener la matriz,
la imprime a efectos informativos, la matriz se imprime de la forma habitual que
es con la traslaccin como ltima columna de la matriz, por ello en la primera fila
se imprimen los elementos 0, 4 ,8 y 12.
si es el primer punto de la lista lo introduce directamente, en este caso es el
origen,
calcula las coordenadas del nuevo punto como producto de la matriz por el vector
de coordenadas del primer punto

y finalmente imprime estas coordendas.


En este caso al ser las coordenadas del punto inicial igual al origen, bastara con
sumar los trminos de traslacin. Se ha dejado como un procedimiento general porque as
se pueden cambiar las coordenadas del punto inicial.
Para dibujar la ruta se implementa la funcin displayTrace(), que consiste en dibujar
una polilnea (GL_LINE_STRIP) con todos los puntos almacenados. A continuacin se
muestra la funcin displayTrace():
void displayTrace() {
int i;
glColor3f(1.0,1.0,1.0) ;
glBegin(GL_LINE_STRIP);
for (i = 0; i < np; i++) {
glVertex3f (px[i],py[i],pz[i]);
}
glEnd();
}

Para que se realice la representacin de la ruta es necesio invocar estas dos funciones
en el cdigo.
La llamada a addPointToTrace() se introduce despues de las llamadas a
glTranslatef() en las instrucciones correspondientes al FORWARD y BACK.
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

23

addPointToTrace();

La llamada a displayTrace() se realiza en la funcin display().


El dibujo del objeto que representa la tortuga se debe realizar despues de multiplicar
la matriz actual (la matriz de visualizacin) por la matriz de modelado que se almacena en
mModel. Sin embargo, el rastro solo debe multiplicarse por la matriz de visualizacin.
A continuacin se muestra la funcin display():
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glMultMatrixd(mModel);
glColor3f(1.0,1.0,0.0) ;
drawTurtle();
glPopMatrix();
displayTrace();
glutSwapBuffers();
}

La llamada a PushMatrix() realiza una


copia de la matriz actual, a continuacin se
multiplica por la matriz de modelado y se
realiza el dibujado del objeto.
Se restaura la matriz de visualizacin y
se dibuja el rastro. La ltima llamada realiza el
intercambio de buffers.
En la figura 2 se muestra el rastro tras
realizar fd 5 rt 90 fd 2 .

Figura 2

Dibujo del rastro

Dibujar un rastro que consista en unas superficie en lugar de una lnea.


Para ello se puede utilizar glBegin(GL_QUAD_STRIP) que dibuja una
sucesin de rectngulos para cada pareja de
6
7
puntos que recibe, como se muestra en la figura 3.
4

5
3

Figura 3 GL_QUAD_STRIP

Ya no bastar con tener un solo


punto inicial, el origen, sino que ser
necesario disponer adems de otro
perpendicular a l, por ejemplo el
(0.1, 0.0, 0.0). En cada nuevo
movimiento ser necesario aadir
estos dos puntos transformados. El
Figura 4
Dibujo del rastro
resultado es el que se muestra en la
figura 4, en la que se dibuja el rastro
despus de haber realizado 5 fd .2, 10 rt 9 fd .2 y 5 fd .2.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

24

3.3 MOSTRAR TEXTO


Las instrucciones introducidas se muestran en la ventana MSDOS. Se pueden
mostrar en la ventana grfica. Para ello es necesario cambiar las matrices de
transformacin. La siguiente funcin realiza la representacin del texto:
void text(GLuint x, GLuint y, GLfloat scale, char* format, ...) {
va_list args;
char buffer[255], *p;
GLfloat font_scale = 119.05f + 33.33f;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT));
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glTranslatef(x, y, 0.0);
glScalef(scale/font_scale, scale/font_scale, scale/font_scale);
for(p = buffer; *p; p++)
glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
glPopAttrib();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}

Para mostrar el texto se llama desde la funcin display() con la sentencia:


if (command) {
glColor3f(1.0,1.,0.0) ;
text(5, 5, 20, "->%s", strCommand);
}

3.4 PUNTOS A REALIZAR

Utilizando los comandos de logo


representar una esfera compuesta
por un conjunto de circunferencias en
el espacio.
Utilizando los comandos de logo
realizar la representacin de una
helicoidal. En la figura 5 se muestra
el resultado de dicho comando.

Figura 5

Helicoidal

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

25

4. VIENDO LA ESCENA DESDE OTRO PUNTO DE VISTA: CMARAS


En este captulo se profundiza en los conceptos de transformaciones de vista y de
proyeccin y se explica con ms detalle las funciones de que dispone OpenGL para
manejar dichas transformaciones.
Para poder ver la escena desde otros puntos de vista es necesario mover la cmara,
esto es, su punto de vista y/o su punto de atencin. Esto puede hacerse de forma directa
dndole las coordenadas del nuevo punto, sin embargo es ms til dotar a la cmara de
diferentes tipos de movimientos controlados mediante el ratn o el teclado, de forma que
se pueda mover por la escena en la forma deseada. Se implementan en este captulo, los
dos tipos de movimiento de cmara ms clsicos: el modo Examinar y el modo Caminar.
4.1 TRANSFORMACIONES DE VISTA
Las transformaciones de vista operan sobre la posicin y orientacin del punto de
vista. Cuando se desea establecer una cierta composicin de una escena, esta se puede
realizar bien moviendo la cmara o bien moviendo los objetos en direccin contraria.
Debido al orden de aplicacin de las distintas transformaciones, las transformaciones de
vista deben ser ejecutados antes de las transformaciones de modelado, para que las
transformaciones de modelado tengan efecto sobre los objetos.
Una transformacin de vista se puede realizar de cualquiera de las siguientes formas:

Con una o ms funciones de transformaciones de modelado (glTranslate*() y


glRotate*() ).
Con la funcin gluLookAt() de la Librera de Utilidades (GLU) que define la
posicin y direccin de visualizacin.
Crear una funcin propia que encapsule rotaciones y translaciones.

La persona que est desarrollando un programa para visualizar una escena, suele
tener en mente un sistema de coordenadas en el que situa los distintos objetos y luces. La
cmara la sita de forma similar, es decir colocndoloa en una posicin determinada y
apuntando a un lugar concreto. La funcin gluLookAt() est disponible para este
propsito. La declaracin de la funcin es de la siguiente:
void gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble centerx, GLdouble centery, GLdouble centerz,
GLdouble upx, GLdouble upy, GLdouble upz );

El punto en el que se sita la cmara se especifica por los argumentos eyex, eyey, y
punto al que mira la cmara se especifica por los argumentos centerx, centery, y
Estos dos puntos definenen la lnea de visin. Los argumentos upx, upy, y upz
determinan la direccin que se considera hacia arriba (equivale al vector que va de los pies
a la cabeza del observador). Estos argumentos se muestran en la figura 3.1.
eyez. El
centerz.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

26

up X
up Y
up Z

eye X
eye Y
eye Z

center X
center Y
center Z

Figura 3.1. Parmetros de la funcin gluLookAt().


La funcin gluLookAt() no es parte de la librera bsica OpenGL, sino de la
OpenGL Utility (GLU). Esto se debe a que lo que hace esta fucin es encapsular otras
funciones bsicas de OpenGL (glTranslate*() y glRotate*() ).
4.2 TRANSFORMACIONES DE PROYECCIN
La transformacin de proyeccin define como se ve la escena y que parte se ve, es
decir, define un volumen de visin. Como se ve la escena, lo define la transformacin de
proyeccin por el modo en que se proyecta el objeto en el plano de visualizacin
(proyeccin ortogonal o perspectiva). Qu parte se ve se determina por los parmetros que
delimitan el volumen de visin.
Dependiendo del modo de proyeccin se utilizar una funcin u otra, como se ver
en los dos subapartados siguientes. Estas funciones determina la matriz de proyeccin. La
matriz de proyeccin transforma las coordenadas de los vrtices de la escena. Para la
correcta definicin de esta matriz, antes de ejecutar las funciones de transformacin de
proyeccin, se llama a las funciones glMatrixMode() y glLoadIdentity():
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

La funcin glMatrixMode(), con el argumento GL_PROJECTION, determina que las


funciones de transformacin siguientes afecten a la matriz de transformacin en lugar de a
la de modelado. La funcin glLoadIdentity() inicializa en este caso la matriz de
proyeccin, puesto que las funciones de proyeccin definen de forma completa dicha
matriz de proyeccin.
4.2.1

Proyeccin en perspectiva
El efecto principal que se observe en la proyeccin en perspectiva es la disminucin
del tamao de un objeto en la proyeccin cuanto ms alejado est de la cmara. La causa
de este efecto es que el volmen de visin en este caso es un tronco de pirmide; en
realidad el volmen de visin sera una pirmide de altura infinita, pero se corta por dos
planos para definir un espacio finito de visin. La proyeccin de los objetos se realiza en
direccin al punto de vista, que corresponde al vrtice comn de los lados de la pirmide.
Los objetos ms cercanos al punto de vista ocupan un rea relativa ms grande del
volmen de visin que los objetos ms cercanos.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

27

El volumen de visin de la proyeccin en perspectiva se define con la funcin


gluPerspective() de la Utility Library (GLU):
);

void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar

La figura 3.2. muestra las caractersticas del volumen de visin especificado por la
rutina gluPerspective() as como el significado de los argumentos de la funcin.

w
h

fovy

aspect = w/h

near
far

Figura 3.2. Volumen de visin en perspectiva especificado por gluPerspective().


4.2.2

Proyeccin Ortogonal
En la proyeccin ortogonal, la direccin de proyeccin es perpendicular al plano de
proyeccin, con lo que el volumen de visin es en este caso un paraleleppedo. En la
proyeccin ortogonal el tamao de los objetos proyectados es independiente de la distancia
a la cmara.
El volumen de visin en la proyeccin ortogonal se define con la funcin glOrtho(),
perteneciente a la librera bsica de OpenGL:
void glOrtho( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,
GLdouble near, GLdouble far );

top
left

far
right
bottom

near
Figura 3.3. Volumen de visin Ortogonal especificado por glOrtho().
La figura 3.3. muestra las caractersticas del volumen de visin especificado por la
rutina glOrtho() as como el significado de los argumentos de la funcin.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

28

4.3 DIFERENTES MODOS DE MOVER LA CMARA


Se va a dotar a la aplicacin la posiblidad de realizar movimientos de cmara que
permiten observar la escena desde diferentes puntos de vista. Se implementan los
siguientes modos de movimiento de cmara:
1. MODO EXAMINAR: Consiste en mover la cmara por una esfera con centro
en el Punto de Atencin. Los movimientos de la cmara se realizarn mediante
movimientos del ratn de la siguiente forma:

Movimiento adelante-atrs: El Punto de Vista de la cmara se mueve


sobre un meridiano manteniendo el Punto de Atencin fijo.
Movimiento izquierda-derecha: El Punto de Vista de la cmara se
mueve sobre un paralelo manteniendo el Punto de Atencin fijo.
Movimiento de zoom pulsando el botn izquierdo del ratn: Zoom Alejar - Acercar o ms exactamente de apertura o cierre del ngulo de la
cmara.

2. MODO CAMINAR: Consiste en colocar la cmara a altura cero y avanzar en la


direccin formada por el Punto de Vista y el Punto de Atencin. Los
movimientos de la cmara se realizarn mediante movimientos del ratn de la
siguiente forma:

Movimiento adelante-atrs pulsando el botn izquierdo del ratn: El


Punto de Vista y el de Atencin de la cmara se mueven hacia delante o
hacia atrs siguiendo el vector formado por ambos.
Movimiento izquierda-derecha pulsando el botn izquierdo del ratn:
El Punto de Atencin de la cmara gira hacia la izquierda o derecha.

Para ello se necesita definir un interface de cmara que guarde los datos de la cmara
y una serie de funciones auxiliares para cada movimiento de la cmara. En el proyecto se
incluyen los siguientes archivos:
contiene las declaraciones de las variables y de las funciones de manejo
de cmara.
camera.c
contiene las definiciones de las funciones para el manejo de la cmara.
A su vez, se necesitan ciertas funciones para el manejo de vectores, las cuales estan
definidas en los siguientes ficheros, que tambin se incluyen en el proyecto:
camera.h

vector_tools.h
vector_tools.c

contiene las declaraciones de las funciones de manejo de vectores.


contiene las definiciones de las funciones de manejo de vectores.

En la cabecera del fichero tecnunLogo.c se incluyen las sentencias:


#include "camera.h"
#include "vector_tools.h"

Se debes declarar una variable global que contendr el interface de cmara, es decir,
los datos de la cmara con los cuales se alimenta a las funciones que realizan las
transformaciones de vista y de proyeccin. Puesto que los movimientos de la cmara se
realizan con el ratn, se necesita conocer las coordenadas en las que estaba el puntero justo
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

29

antes de un movimiento para poder evaluar cunto se ha movido. Se Incluyen las


siguientes lneas en el fichero tecnunLogo.c inmediatamente despus de los ficheros de
cabecera:
static camera *LOCAL_MyCamera;
static int old_x, old_y;

Inicialmente se debe crear el interface para la cmara y asignrselo a la variable


global que se acaba de declarar. Esto se realiza incluyendo la siguiente sentencia en la
funcin main del programa:
LOCAL_MyCamera = CreatePositionCamera(0.0f, 1.0f, -3.0f);

Mediante esta sentencia se coloca la cmara en (0,1,-3) mirando hacia (0,0,0). Para
poder manejar la cmara, bien en un modo o en otro, se utilizan las siguientes teclas:
F1

Desactivar cualquier modo de movimiento de cmara

F2

Modo Examinar

F3

Modo Caminar

HOME La cmara vuelve a la situacin inicial


Puesto que se trata de teclas especiales, se debe incluir en el main del programa la
funcin callback glutSpecialFunc(SpecialKey):
glutSpecialFunc(SpecialKey);

La funcin SpecialKey() que es pasada como parmetro ser llamada cada vez que
ocurra un evento de pulsado de una tecla especial entre las que se incluyen las teclas de
funciones, las flechas de desplazamiento y las de Inicio, Fin, Avance pgina y Retroceso
pgina. Se define a continuacin la funcin SpecialKey():
static void SpecialKey ( int key, int x, int y ){
switch(key) {
case GLUT_KEY_F1:
glutPassiveMotionFunc(MouseMotion);
LOCAL_MyCamera->camMovimiento = CAM_STOP;
break;
case GLUT_KEY_F2:
glutPassiveMotionFunc(Examinar);
LOCAL_MyCamera->camMovimiento = CAM_EXAMINAR;
break;
case GLUT_KEY_F3:
glutPassiveMotionFunc(MouseMotion);
LOCAL_MyCamera->camMovimiento = CAM_PASEAR;
LOCAL_MyCamera->camAtY = 0;
LOCAL_MyCamera->camViewY = 0;
SetDependentParametersCamera( LOCAL_MyCamera );
break;
case GLUT_KEY_HOME: //Reset Camera
LOCAL_MyCamera->camAtX =0;
LOCAL_MyCamera->camAtY =0;
LOCAL_MyCamera->camAtZ =0;
LOCAL_MyCamera->camViewX = 0;
LOCAL_MyCamera->camViewY = 1;
LOCAL_MyCamera->camViewZ = -3;
SetDependentParametersCamera( LOCAL_MyCamera );
break;

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

30

default:
printf("key %d %c X %d Y %d\n", key, key, x, y );
}
glutPostRedisplay();
}

La funcin callback glutPassiveMotionFunc() recibe por ventana la funcin que se


llamar cada vez que se produzca un evento de movimiento de ratn sin tener ningn botn
de este pulsado. La funcin MouseMotion(int x, int y), lo nico que hace es guardar la
posicin a la que se mueve el ratn como la ltima posicin de este:
void MouseMotion(int x, int y){
old_y = y;
old_x = x;
}

En la funcin main tambin hay que llamar a la funcin glutPassiveMotionFunc()


para que cuando se mueva el ratn se guarde la posicin a la que se traslade:
glutPassiveMotionFunc(MouseMotion);

La funcin Examinar(int x, int y) mover la cmara en el modo Examinar segn los


movimientos del ratn:
void Examinar(int x, int y){
float rot_x, rot_y;
rot_y = (float)(old_y - y);
rot_x = (float)(x - old_x);
Rotar_Latitud( LOCAL_MyCamera, rot_y * DEGREE_TO_RAD );
Rotar_Longitud( LOCAL_MyCamera, rot_x * DEGREE_TO_RAD );
old_y = y;
old_x = x;
glutPostRedisplay();
}

Por otro lado, se debe indicar al programa qu funcin controlar los movimientos
del ratn cuando se pulsa algn botn de este. Para ello se dispone de la funcin callback
glutMouseFunc(), que se incluye en la funcin main del programa y que responde a los
eventos de pulsado de botones del ratn:
glutMouseFunc(mouse);

La funcin mouse() que es pasada como parmetro ser llamada cada vez que ocurra
un evento de pulsado de un botn del ratn. En ella se define qu operaciones se realizan
cuando se pulse un botn y se encuentra en un modo de movimiento de cmara o en otro:
void mouse(int button, int state, int x, int y){
old_x = x;
old_y = y;
switch(button){
case GLUT_LEFT_BUTTON:
switch(LOCAL_MyCamera->camMovimiento){
case CAM_EXAMINAR:
if (state == GLUT_DOWN) glutMotionFunc(Zoom);
if (state == GLUT_UP){
glutPassiveMotionFunc(Examinar);
glutMotionFunc(NULL);
}
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

31

break;
case CAM_PASEAR:
if (state == GLUT_DOWN) glutMotionFunc(Andar);
if (state == GLUT_UP) glutMotionFunc(NULL);
break;
}
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) ;
break;
default:
break;
}
glutPostRedisplay();
}

Se observa que se realizan llamadas a la funcin callback glutMotionFunc() que


responde a los movimientos del ratn cuando se tiene pulsado algn botn de este.
Dependiendo del tipo de movimiento de cmara que se est llevando a cabo, se le pasa por
ventana una funcin que realice la operacin definida:
void Zoom(int x, int y){
float zoom;
zoom = (float) ((y - old_y) * DEGREE_TO_RAD);
old_y = y;
switch(LOCAL_MyCamera->camMovimiento){
case CAM_EXAMINAR:
if (LOCAL_MyCamera->camAperture + zoom > (5 * DEGREE_TO_RAD) &&
LOCAL_MyCamera->camAperture + zoom < 175 * DEGREE_TO_RAD)
LOCAL_MyCamera->camAperture=LOCAL_MyCamera->camAperture + zoom;
break;
}
glutPostRedisplay();
}
void Andar(int x, int y){
float rotacion_x, avance_y;
avance_y = (float)(y - old_y) / 10;
rotacion_x = (float)(old_x - x) * DEGREE_TO_RAD / 5;
YawCamera( LOCAL_MyCamera, rotacion_x );
AvanceFreeCamera( LOCAL_MyCamera, avance_y);
old_y = y;
old_x = x;
glutPostRedisplay();
}

Para que todos los movimientos de cmara que se realizan se vean reflejados se debe
incluir en la funcin display() una llamada a la funcin que se encarga de actualizar los
valores de la cmara a aquellos que tiene guardados el interface de cmara y que son los
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

32

que se han modificado al realizar movimientos de cmara. Para ello se debe incluir en la
funcin display() la siguiente sentencia:
SetGLCamera( LOCAL_MyCamera );

Por ltimo, la funcin reshape() necesita un cambio para que al cambiar el aspecto
de la ventana se mantengan las proporciones de la escena y esta no se deforme. Quedar de
la siguiente forma:
void reshape(int width, int height) {
glViewport(0, 0, width, height);
SetGLAspectRatioCamera( LOCAL_MyCamera );
}

4.4 TRABAJOS PROPUESTOS

Dotar al programa de una tecla que permita cambiar el modo de


proyeccin entre ORTOGONAL y PERSPECTIVA.
Programar otros modos de movimiento de cmara como son el MODO
PAN o el MODO TRPODE.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

33

#ifndef CAMERA_H
#define CAMERA_H
#define CAM_PARALLEL 1
#define CAM_CONIC 2
#define CAM_STOP 0
#define CAM_EXAMINAR 1
#define CAM_PASEAR 2
typedef struct _Camera
{
// we consider a rigth handed reference system for the camera
// V point where the camera is placed (world coordinates)
// A point the camera is looking at
(world coordinates)
// up vector : unit vector, perpendicular to AV (world componnents)
// origin camera reference system : at V
// Z camera : defined by vector from A to V (penetrates the viewers eye)
// Y camera : defined by up vector
// X camera : looking from V towards A goes rigthwards
float
camViewX; // View point
float
camViewY;
float
camViewZ;
float
camAtX;
// look At point
float
camAtY;
float
camAtZ;
float
camUpX;
// Up vector
float
camUpY;
float
camUpZ;
float
camAperture; // field of view radians
// NOTE : OpenGL uses degrees
// defined as they are used by OpenGL
// always => positive ; Far > Near (distance from plane to camera origin)
float
camNear;
float
camFar;
int
camProjection; // PARALLEL or CONIC
int
camMovimiento; // EXAMINAR, ANDAR, TRIPODE or PAN
// ****** dependent values ******
// window system dependent
float
aspectRatio;
// for ortho projection
float
x1, x2, y1, y2, z1, z2;
// camera i j k vectors in world coordinates
float
camIX, camIY, camIZ;
float
camJX, camJY, camJZ;
float
camKX, camKY, camKZ;
} camera;
void DestroyCamera ( camera **theCamera );
camera *CreatePositionCamera( float positionX, float positionY, float positionZ );
void SetCamera( camera *thisCamera, float viewX, float viewY, float viewZ,
float atX,
float atY,
float atZ,
float upX,
float upY,
float upZ );
void
void
void

SetDependentParametersCamera( camera *thisCamera );


SetGLCamera( camera *thisCamera );
SetGLAspectRatioCamera( camera *thisCamera );

// Free camera advances "step" following vector VA, step admits negative values
void AvanceFreeCamera( camera *thisCamera, float step );
// ROTATION
void YawCamera( camera *thisCamera, float angle );

// local axis Y camera

void Rotar_Latitud( camera *thisCamera, float inc );


void Rotar_Longitud( camera *thisCamera, float inc );
#endif /* CAMERA_H */

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

34

#include <GL/glut.h>
#include "camera.h"
#include "vector_tools.h"
void DestroyCamera ( camera **theCamera ){
camera *thisCamera = *theCamera;
if( ! thisCamera ) return;
free( thisCamera );
*theCamera = NULL;
}
camera *CreatePositionCamera( float positionX, float positionY, float positionZ ){
camera *newCamera;
int
ierr = 0;
newCamera = (camera *) malloc( sizeof(camera) * 1 );
newCamera->camViewX
newCamera->camViewY
newCamera->camViewZ

= positionX;
= positionY;
= positionZ;

// looks towards
newCamera->camAtX
newCamera->camAtY
newCamera->camAtZ

= 0.0f;
= 0.0f;
= 0.0f;

newCamera->camUpX
newCamera->camUpY
newCamera->camUpZ

= 0.0f;
= 1.0f;
= 0.0f;

newCamera->camAperture = 60.0f * DEGREE_TO_RAD;


newCamera->camNear
= 0.5f;
newCamera->camFar
= 200.0f;
newCamera->camProjection = CAM_CONIC;
newCamera->aspectRatio
= 1.0f;
SetDependentParametersCamera( newCamera );
return newCamera;
}
void
//
//
//
//

SetDependentParametersCamera (camera *thisCamera){


camera i j k vectors in world coordinates
camIX, camIY, camIZ;
camJX, camJY, camJZ;
camKX, camKY, camKZ;

float
float
float
float
float
float
int
viewX
viewY
viewZ
atX
atY
atZ
upX
upY
upZ

ix,
jx,
kx,
atX,
upX,
viewX,
ierr =
=
=
=
=
=
=
=
=
=

iy,
jy,
ky,
atY,
upY,
viewY,
0;

iz;
jz;
kz;
atZ;
upZ;
viewZ;

thisCamera->camViewX;
thisCamera->camViewY;
thisCamera->camViewZ;
thisCamera->camAtX;
thisCamera->camAtY;
thisCamera->camAtZ;
0.0f;
1.0f;
0.0f;

// i, j, k, up must be unit vectors


// k = normalizar( AV )
// i = normalizar( up ^ k )
// j = k ^ i
UnitVectorPP( &ierr, &kx, &ky, &kz, atX, atY, atZ, viewX, viewY, viewZ );
UnitVectorVV( &ierr, &ix, &iy, &iz, upX, upY, upZ, kx, ky, kz );
UnitVectorVV( &ierr, &jx, &jy, &jz, kx, ky, kz, ix, iy, iz );
thisCamera->camKX = kx;

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

35

thisCamera->camKY = ky;
thisCamera->camKZ = kz;
thisCamera->camIX = ix;
thisCamera->camIY = iy;
thisCamera->camIZ = iz;
thisCamera->camJX = jx;
thisCamera->camJY = jy;
thisCamera->camJZ = jz;
thisCamera->camUpX = jx;
thisCamera->camUpY = jy;
thisCamera->camUpZ = jz;
}
void SetGLCamera( camera *thisCamera ){
float
fovy;
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );
if( thisCamera->camProjection == CAM_CONIC ){
fovy = thisCamera->camAperture*RAD_TO_DEGREE;
gluPerspective(fovy, thisCamera->aspectRatio, thisCamera->camNear, thisCamera->camFar
);
}
else { // CAM_PARALLEL
glOrtho(thisCamera->x1, thisCamera->x2, thisCamera->y1, thisCamera->y2,
thisCamera->z1,thisCamera->z2);
}
gluLookAt(thisCamera->camViewX, thisCamera->camViewY, thisCamera->camViewZ,
thisCamera->camAtX, thisCamera->camAtY, thisCamera->camAtZ,
thisCamera->camUpX, thisCamera->camUpY, thisCamera->camUpZ );
glMatrixMode( GL_MODELVIEW ); //* GL_MODELVIEW *
}
void SetGLAspectRatioCamera( camera *thisCamera ){
GLint
viewport[4];
glGetIntegerv( GL_VIEWPORT, viewport );
if( viewport[3] > 0 )
thisCamera->aspectRatio = (float) viewport[2] / (float) viewport[3];
else
thisCamera->aspectRatio = 1.0f;

// width/height

SetDependentParametersCamera( thisCamera );
}
void

SetCamera( camera *thisCamera, float viewX, float viewY, float viewZ,


float atX,
float atY,
float atZ,
float upX,
float upY,
float upZ ){

thisCamera->camViewX
thisCamera->camViewY
thisCamera->camViewZ
thisCamera->camAtX =
thisCamera->camAtY =
thisCamera->camAtZ =
thisCamera->camUpX =
thisCamera->camUpY =
thisCamera->camUpZ =

= viewX;
= viewY;
= viewZ;
atX;
atY;
atZ;
upX;
upY;
upZ;

SetDependentParametersCamera( thisCamera );
}
void AvanceFreeCamera(camera *thisCamera, float step) {
float
vaX, vaY, vaZ;
vaX= step * thisCamera->camKX;
vaY= step * thisCamera->camKY;
vaZ= step * thisCamera->camKZ;
// Set V & A
thisCamera->camViewX=thisCamera->camViewX+vaX;

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

36

thisCamera->camViewY=thisCamera->camViewY+vaY;
thisCamera->camViewZ=thisCamera->camViewZ+vaZ;
thisCamera->camAtX = thisCamera->camAtX + vaX;
thisCamera->camAtY = thisCamera->camAtY + vaY;
thisCamera->camAtZ = thisCamera->camAtZ + vaZ;
SetDependentParametersCamera( thisCamera );
}
void YawCamera(camera *thisCamera, float angle){
float vIn[3];
vIn[0]=thisCamera->camAtX-thisCamera->camViewX;
vIn[1]=thisCamera->camAtY-thisCamera->camViewY;
vIn[2]=thisCamera->camAtZ-thisCamera->camViewZ;
VectorRotY( vIn, angle );
thisCamera->camAtX=thisCamera->camViewX+vIn[0];
thisCamera->camAtY=thisCamera->camViewY+vIn[1];
thisCamera->camAtZ=thisCamera->camViewZ+vIn[2];
SetDependentParametersCamera( thisCamera );
}
void Rotar_Longitud(camera *thisCamera,float inc){
float vIn[3];
vIn[0]=thisCamera->camViewX-thisCamera->camAtX;
vIn[1]=thisCamera->camViewY-thisCamera->camAtY;
vIn[2]=thisCamera->camViewZ-thisCamera->camAtZ;
VectorRotY( vIn, inc );
thisCamera->camViewX=thisCamera->camAtX+vIn[0];
thisCamera->camViewZ=thisCamera->camAtZ+vIn[2];
SetDependentParametersCamera( thisCamera );
}
void Rotar_Latitud(camera *thisCamera,float inc){
float vIn[3];
vIn[0]=thisCamera->camViewX-thisCamera->camAtX;
vIn[1]=thisCamera->camViewY-thisCamera->camAtY;
vIn[2]=thisCamera->camViewZ-thisCamera->camAtZ;
VectorRotXZ( vIn, inc, TRUE );
thisCamera->camViewX=thisCamera->camAtX+vIn[0];
thisCamera->camViewY=thisCamera->camAtY+vIn[1];
thisCamera->camViewZ=thisCamera->camAtZ+vIn[2];
SetDependentParametersCamera( thisCamera );
}

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

37

#ifndef TOOLS_H
#define TOOLS_H
#include <math.h>
#ifndef TRUE
#define TRUE
#define FALSE
#endif

1
0

// *** Mathematics
#define VECTOR_EPSILON
#define DISTANCE_EPSILON
#define ANGLE_EPSILON

0.00001f
1e-08f
0.00872665f

// 0.5 degrees

#define MOD(A,B,C) (float) sqrt( A*A + B*B + C*C )


#define PI_VALUE
#define DEGREE_TO_RAD
#define RAD_TO_DEGREE

3.14159265359f
0.0174533f /* 2.0 * 3.1415927 / 360.0 */
57.2958f
/* 360 / ( 2.0 * 3.1415927 ) */

void VectorNormalize( int *ierr, float *vX, float *vY, float *vz );
void UnitVectorPP( int *ierr, float *wX, float *wY, float *wZ,
float aX, float aY, float aZ,
float bX, float bY, float bz );
void UnitVectorVV( int *ierr, float *wX, float *wY, float *wZ,
float uX, float uY, float uZ,
float vX, float vY, float vz );
void VectorRotY( float *v, float inc );
// rotates vector : around Y axis like moving its end on its
parallel
void VectorRotXZ( float *vIn, float inc, int flagStop );
// rotates vector : like moving its end on its meridiam
#endif /* TOOLS_H */

X
Z

VectorRotXZ()

VectorRotY()

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

38

5. ILUMINANDO LA ESCENA
En este captulo se explican las funciones que OpenGL pone a disposicin para
manejar la iluminacin de la escena y a crear, posicionar y dar propiedades a diferentes
tipos de luces. La posicin de las luces se realiza mediante el ratn con funciones similares
a las utilizadas para posicionar la cmara en el modo examinar.
5.1 AADIENDO ILUMINACIN A LA ESCENA
Para que OpenGL pueda realizar los clculos correspondientes a la iluminacin es
necesaria la siguiente informacin de la escena:
1. Los vectores normales de cada vrtice de los objeto que definen la orientacin de
cada punto respecto a las lueces.
2. La posicin y caractersticas de cada una de las luces.
3. Las propiedades de los materiales de los objetos.
La presente prctica se va a centrar exclusivamente en el segundo punto. Se utilizar
como objeto una tortuga en 3D realizada con esferas, de forma que las normales para
dichas esferas viene definidas como parte de la rutina glutSolidSphere(). Las propiedades
del material de los objetos se realizar asignando directamente un color en lugar de definir
materiales y posteriormente asignarlos a los objetos.
5.2 CREANDO FUENTES DE LUZ CON OPENGL
5.2.1

Comando glLight*( )
El comando usado para especificar todas las propiedades luces es glLight*(); esta
funcin toma tres argumentos: el primero de ellos identifica la luz para la cual se est
especificando una propiedad, la propiedad que se desea especificar y el valor para dicha
propiedad. La forma de la funcin es la siguiente:
void glLight{if}(GLenum light, GLenum pname, TYPE param);
void glLight{if}v(GLenum light, GLenum pname, TYPE *param);
Parameter Name

GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR
GL_POSITION
GL_SPOT_DIRECTION
GL_SPOT_EXPONENT
GL_SPOT_CUTOFF
GL_CONSTANT_ATTENUATION
GL_LINEAR_ATTENUATION
GL_QUADRATIC_ATTENUATION

Default Value

(0.0, 0.0, 0.0, 1.0)


(1.0, 1.0, 1.0, 1.0)
(1.0, 1.0, 1.0, 1.0)
(0.0, 0.0, 1.0, 0.0)
(0.0, 0.0, -1.0)
0.0
180.0
1.0
0.0
0.0

Meaning

Intensidad RGBA de la luz ambiente


Intensidad RGBA de la luz difusa
Intensidad RGBA de la luz especular
Posicin (x, y, z, w) de la luz
Direccin (x, y, z) del spotlight
Spotlight exponent
Spotlight cutoff angle
Constant attenuation factor
Linear attenuation factor
Quadratic attenuation factor

Tabla 5.1. Valores por defecto del Parmetro pname de glLight*().

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

39

El parmetro light que identifica la luz puede tomar los valores GL_LIGHT0,
GL_LIGHT1,..., GL_LIGHT7, de forma que se pueden tener hasta 8 luces diferentes
simultneamente en la escena.
El parmetro pname controla la propiedad de la luz que se desea especificar. Las
diferentes propiedades de la luz que se pueden modificar, su significado, as como los
valores por defecto de cada propiedad se muestran en la tabla 5.1.
5.3 INTRODUCIENDO LUCES AL PROGRAMA TECNUNLOGO
5.3.1

Tipos de luces

Figura 1. Forma de representar la luz

Se van a introducir tres luces al


programa TecnunLogo, todas del mismo
tipo. Esto permitir estudiar cmo vara
la iluminacin de la escena al cambiar las
componentes propias de la luz. Adems,
permitiendo que puedan ser encendidas o
apagadas de forma independiente se
pueden estudiar los efectos de
combinaciones entre ellas.
En la figura 1 se muestra cmo
aparecern representadas en el programa
TecnunLogo las luces. Un paralelo y un
meridiano localizan la posicin de la luz.
En el caso de luz direccional, que es el
tipo de luz que se va a introducir, esta
viene representada con un vector dirigido
siempre hacia el centro de la escena que
indica su direccin. En el siguiente
captulo se vern otros tipos de fuentes de
luz y sus representaciones.

5.3.2

Interface de usuario
Para que el usuario de la aplicacin pueda interactuar con las luces que se van a
poner a su disposicin, se debe definir un inteface de usuario. Este interface constar de
una serie de teclas que permitan pasar al Modo Luces y pasar el control de una luz a otra,
as como encender y apagar cada una de las luces (Tabla 5.2).
Puesto que a estas alturas el programa ya dispondr de al menos dos modos de
interaccin, a saber, modo cmara y modo luces, se va a hacer que para pasar de un modo a
otro no se pueda hacer directamente sino que haya que desactivar previamente el modo en
curso. Mediante el ratn ser posible cambiar la posicin de las luces (Tabla 5.3).
Tecla

Accin

F1

Desactivar luces (en general, desactivar cualquier modo)

F8

Modo luces. Cada vez que se pulsa se pasa de una luz a otra.

F9

ON/OFF la luz con la cual se est interactuando.


Tabla 5.2. Teclas del Modo Luces

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

40

Movimiento del Ratn

Accin

Adelante/Atrs

Movimiento de la luz con la cual se est interactuando a lo


largo de un meridiano con centro en el origen de
coordenadas de la escena.

Izquierda/Derecha

Movimiento de la luz con la cual se est interactuando a lo


largo de un paralelo con centro en el eje Y.

Adelante/Atrs con
botn izquierdo pulsado

Movimiento de la luz a lo largo del vector que une la


posicin de la luz con el centro de coordenadas de la escena.

Tabla 5.3. Movimiento de la posicin de las luces


5.3.3

Modificaciones en el cdigo
Se va a dotar al programa de tres luces que permitirn en el siguiente captulo
observar las diferencias entre los distintos tipos de luces y su efecto en la escena. Para ello
se permitir interactuar con la posicin y direccin de cada una de ellas y mantenerlas
encendidas o apagadas independientemente una de otra.
Se necesita definir un interface de luz que guarde los datos de la luz y una serie de
funciones auxiliares para el movimiento de las luces. En el proyecto incluiremos los
siguientes archivos:
light.h
light.c

contiene las declaraciones del interface de luces y de las funciones de


manejo de luces.
contiene las definiciones de las funciones para el manejo de las luces.

Adems se necesitan una serie de funciones que dibujan primitivas. Entre estas
primitivas estn una tortuga modelada con esferas, el trazado de meridianos y paralelos en
un punto y otras. Se incluyen en el proyecto los siguientes ficheros:
primitivas.h
primitivas.c

contiene las declaraciones de las funciones de dibujo de primitivas.


contiene las definiciones de las funciones de dibujo de primitivas.

En la cabecera del fichero tecnunLogo.c incluiremos las sentencias:


#include "light.h"
#include "primitivas.h"

Se debe declarar una variable global que contendr el interface de cada una de las
tres luces, es decir, los datos de cada luz con los cuales alimentaremos a la funcin que
efectivamente realiza los cambios en la luz, glLight*(). A su vez se necesita una variable
global que indique la luz con la cual se est interactuando en cada momento. Adems se
definir una variable global que indique el modo en el que se est trabajando (modo
examinar, modo andar, modo luces). Se incluyen las siguientes lneas en el fichero
tecnunLogo.c inmediatamente despus de los ficheros de cabecera:
static light
**LOCAL_MyLights;
static int current_mode = 0;
static int current_light = -1;

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

41

Inicialmente se debe crear el interface para las luces y asignrselo a la variable global
que se acaba de declarar. Adems se deben dar las caractersticas a cada una de las luces.
De esta forma quedan definidos los interfaces para las tres luces en un array. Esto lo
realizamos incluyendo las siguientes sentencias en la funcin main() del programa:
int i;
...
//Reservamos memoria para tres interfaces de luces
LOCAL_MyLights = (light **) malloc( 3 * sizeof(light *));
//Creamos las luces y damos a cada una sus caractersticas
for(i=0;i<3;i++){
LOCAL_MyLights[i] = CreateDefaultLight();
LOCAL_MyLights[i]->type = AGA_DIRECTIONAL;
LOCAL_MyLights[i]->id = GL_LIGHT0 + i;
LOCAL_MyLights[i]->position[0] = 1.0f;
LOCAL_MyLights[i]->position[1] = 1.0f;
LOCAL_MyLights[i]->position[2] = 1.0f;
LOCAL_MyLights[i]->position[3] = 0.0f;
LOCAL_MyLights[i]->pointAtInfinity[0] = LOCAL_MyLights[0]->position[0];
LOCAL_MyLights[i]->pointAtInfinity[1] = LOCAL_MyLights[0]->position[1];
LOCAL_MyLights[i]->pointAtInfinity[2] = LOCAL_MyLights[0]->position[2];
}

OpenGL pone a disposicin del programador la posibilidad de asignar colores en


lugar de materiales a los objetos que van a ser utilizados en programas que usan
iluminacin. Esta caracterstica se conoce como Colour Tracking y es muy til pues evita
el tener que asignar manualmente las propiedades del material a los objetos cuando la
aplicacin no requiere tal cosa pues no importan las propiedades del material. Para
activarla introducir la siguiente sentencia en la funcin main( ):
glEnable(GL_COLOR_MATERIAL);

La funcin SpecialKey() quedar de la siguiente manera una vez que se incluyen las
sentencias necesarias para definir las teclas que permiten pasar al Modo Luces:
static void SpecialKey ( int key, int x, int y ){
switch(key) {
case GLUT_KEY_F1:
current_mode = 0;
glutPassiveMotionFunc(MouseMotion);
LOCAL_MyCamera->camMovimiento = CAM_STOP;
current_light = -1;
break;
case GLUT_KEY_F2:
if (current_mode != 0) break;
current_mode = 1;
glutPassiveMotionFunc(Examinar);
LOCAL_MyCamera->camMovimiento = CAM_EXAMINAR;
break;
case GLUT_KEY_F3:
if (current_mode != 0) break;
current_mode = 2;
glutPassiveMotionFunc(MouseMotion);
LOCAL_MyCamera->camMovimiento = CAM_PASEAR;
LOCAL_MyCamera->camAtY = 0;
LOCAL_MyCamera->camViewY = 0;
SetDependentParametersCamera( LOCAL_MyCamera );
break;
case GLUT_KEY_F8:
if (current_mode != 0 && current_mode != 7) break;
current_mode = 7;
if (current_light == -1) glutPassiveMotionFunc(Mouse_Luces);
if (current_light != 2) current_light++;
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

42

else current_light = 0;
printf("Luz actual = %d\n",current_light);
break;
case GLUT_KEY_F9:
if (current_light != -1)
if ( LOCAL_MyLights[current_light]->switched )
SwitchLight( LOCAL_MyLights[current_light], FALSE);
else SwitchLight( LOCAL_MyLights[current_light], TRUE);
break;
case GLUT_KEY_HOME: //Reset Camera
LOCAL_MyCamera->camAtX =0;
LOCAL_MyCamera->camAtY =0;
LOCAL_MyCamera->camAtZ =0;
LOCAL_MyCamera->camViewX = 0;
LOCAL_MyCamera->camViewY = 1;
LOCAL_MyCamera->camViewZ = -3;
SetDependentParametersCamera( LOCAL_MyCamera );
break;
default:
printf("key %d %c X %d Y %d\n", key, key, x, y );
}
glutPostRedisplay();
}

La funcin Mouse_Luces(int x, int y) mover la luz con la cual se est


interactuando en ese momento a lo largo de un paralelo o un meridiano segn los
movimientos del ratn definidos con anterioridad:
void Mouse_Luces(int x, int y){
float rot_x, rot_y;
rot_y = (float)(old_y - y);
rot_x = (float)(x - old_x);
Rotar_Luces_Latitud( LOCAL_MyLights[current_light],rot_y*DEGREE_TO_RAD );
Rotar_Luces_Longitud( LOCAL_MyLights[current_light], rot_x*DEGREE_TO_RAD);
LOCAL_MyLights[current_light]->pointAtInfinity[0] =
LOCAL_MyLights[current_light]->position[0];
LOCAL_MyLights[current_light]->pointAtInfinity[1] =
LOCAL_MyLights[current_light]->position[1];
LOCAL_MyLights[current_light]->pointAtInfinity[2] =
LOCAL_MyLights[current_light]->position[2];
old_y = y;
old_x = x;
glutPostRedisplay();
}

La funcin mouse() quedar de la siguiente forma despus de incluir las sentencias


necesarias para interactuar con las luces:
void mouse(int button, int state, int x, int y){
old_x = x;
old_y = y;
switch(button){
case GLUT_LEFT_BUTTON:
if(current_light > 0){
if (state == GLUT_DOWN)
glutMotionFunc(Mouse_Luces_Acercar_Alejar);
if (state == GLUT_UP){
glutPassiveMotionFunc(Mouse_Luces);
glutMotionFunc(NULL);
}

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

43

}else{
switch(LOCAL_MyCamera->camMovimiento){
case CAM_EXAMINAR:
if (state == GLUT_DOWN) glutMotionFunc(Zoom);
if (state == GLUT_UP){
glutPassiveMotionFunc(Examinar);
glutMotionFunc(NULL);
}
break;
case CAM_PASEAR:
if (state == GLUT_DOWN) glutMotionFunc(Andar);
if (state == GLUT_UP) glutMotionFunc(NULL);
break;
}
}
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) ;
break;
default:
break;
}
glutPostRedisplay();
}

Se ve que se realizan llamadas a la funcin callback glutMotionFunc() que responde


a los movimientos del ratn cuando se tiene pulsado algn botn de este. Cuando se est
interactuando con la posicin de una luz, se le pasa por ventana una funcin que realice la
operacin de acercar o alejar la luz:
void Mouse_Luces_Acercar_Alejar(int x, int y){
float step;
step = (float) (y - old_y) / 20.0f;
old_y = y;
Acercar_Alejar_Luces( LOCAL_MyLights[current_light], step );
glutPostRedisplay();
}

La funcin display() quedar de la siguiente forma:


void display(void) {
float At[3];
float Direction[3];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
SetGLCamera( LOCAL_MyCamera );
SetLight( LOCAL_MyLights[0] );
SetLight( LOCAL_MyLights[1] );
SetLight( LOCAL_MyLights[2] );
glPushMatrix();
glColor3f(1.0,1.0,0.0);
drawSphereTurtle();
switch( current_light ){
case 0:
case 1:
case 2:
At[0] = LOCAL_MyLights[current_light]->position[0];
At[1] = LOCAL_MyLights[current_light]->position[1];
At[2] = LOCAL_MyLights[current_light]->position[2];

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

44

Direction[0] = - LOCAL_MyLights[current_light]->position[0];
Direction[1] = - LOCAL_MyLights[current_light]->position[1];
Direction[2] = - LOCAL_MyLights[current_light]->position[2];
Draw_Parallel(At);
Draw_Meridian(At);
Draw_Vector(At, Direction);
break;
default:
break;
}
glPopMatrix();
glutSwapBuffers();
}

Por ltimo, en la funcin keyboard() hay que aadir el siguiente cdigo para que
cuando se pulse escape para abandonar el programa, se libere la memoria que se a
reservado dinmicamente:
case 27:
DestroyCamera(&LOCAL_MyCamera);
DestroyLight( LOCAL_MyLights[0] );
DestroyLight( LOCAL_MyLights[1] );
DestroyLight( LOCAL_MyLights[2] );
free (LOCAL_MyLights);
exit(0);
break;

5.4 TRABAJOS PROPUESTOS

Hacer que al acercar o alejar las luces GL_LIGHT1 o GL_LIGHT2, el


avance o retroceso de esta mediante el movimiento del ratn sea
proporcional a la distancia de dicha luz al centro de la escena.
Proporcionar alguna forma amigable de modificar el color de la luz. Por
ejemplo mediante el teclado con las letras (r,g,b para disminuir y R,G,B
para aumentar)

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

45

#ifndef LIGHT_H
#define LIGHT_H
#define AGA_DIRECTIONAL
#define AGA_POSITIONAL
#define AGA_SPOT

1
2
3

typedef struct _Light


{
// The default values that are listed here
// are those defined by OpenGL
// Our Default Light has different values
// (see SetDefaultLight() )
int
type;
int
id;
// GL_LIGHTx ; -1 not binded
int
switched;
// TRUE => ON
int
needsUpdate;
// TRUE / FALSE
int
white;
// TRUE / FALSE
int
attenuation;
// TRUE / FALSE
float ambient[4];
// GL_AMBIENT : default (0.0, 0.0, 0.0, 1.0)
float diffuse[4];
// GL_DIFFUSE : default (0.0, 0.0, 0.0, 1.0)
// except for light zero (1.0, 1.0, 1.0, 1.0)
float specular[4];
// GL_SPECULAR : default (0.0, 0.0, 0.0, 1.0)
// except for light zero (1.0, 1.0, 1.0, 1.0)
float position[4];
// GL_POSITION : default (0,0,1,0);
// directional, in the direction of the -z
float pointAtInfinity[4]; // these values do not refer to the components of
// one vector they refer to :
// the coordinates of one point placed in the
infinite
// ( as the point is in the infinite,
// its 4th homogeneous coordinate must be 0.0 )
float spotDirection[4]; // GL_SPOT_DIRECTION : default direction is (0,0,-1)
// significant only when GL_SPOT_CUTOFF is not 180
float spotExponent;
// GL_SPOT_EXPONENT [0,128], default 0
// 0 => uniform light distribution
// higher spot => more focused light source,
float spotCutOff;
// GL_SPOT_CUTOFF [0,90] & 180, default 180
// 180 => uniform light distribution
float a;
// GL_QUADRATIC_ATTENUATION
float b;
// GL_LINEAR_ATTENUATION
float c;
// GL_CONSTANT_ATTENUATION
// I = I / ( a*delta*delta + b*delta + c )
// delta : distance from light position to point
// default a=0 b=0 c=1, no atenuation
} light;
light *CreateDefaultLight();
void
DestroyLight( light *thisLight );
void
void
void

SetLight( light *thisLight );


SetDefaultLight( light *thisLight );
SwitchLight( light *thisLight, int status );

void Rotar_Luces_Longitud( light *thisLight, float inc );


void Rotar_Luces_Latitud( light *thisLight, float inc );
void Acercar_Alejar_Luces( light *thisLight, float step );
void Rotar_Spot_Latitud( light *thisLight, float inc );
void Rotar_Spot_Longitud( light *thisLight, float inc );
#endif /* LIGHT_H */

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

46

#include <GL/glut.h>
#include "light.h"
#include "vector_tools.h"
light *CreateDefaultLight() {
light
*newLight;
newLight = (light *) malloc( sizeof(light) * 1 );
SetDefaultLight( newLight );
return newLight;
}
void SetDefaultLight( light *thisLight ) {
int
ierr = 0;
float intensity;
float vx, vy, vz;
// directional light
thisLight->type
=
thisLight->id
=
thisLight->switched
thisLight->white
thisLight->attenuation
thisLight->needsUpdate

AGA_DIRECTIONAL;
-1;
= FALSE;
= TRUE;
= FALSE;
= TRUE;

intensity = 0.0f;
thisLight->ambient[0]
thisLight->ambient[1]
thisLight->ambient[2]
thisLight->ambient[3]

=
=
=
=

intensity;
intensity;
intensity;
1.0f;

intensity = 0.8f;
thisLight->diffuse[0]
thisLight->diffuse[1]
thisLight->diffuse[2]
thisLight->diffuse[3]

=
=
=
=

intensity;
intensity;
intensity;
1.0f;

intensity = 0.0f;
thisLight->specular[0]
thisLight->specular[1]
thisLight->specular[2]
thisLight->specular[3]

=
=
=
=

intensity;
intensity;
intensity;
1.0f;

thisLight->position[0]
thisLight->position[1]
thisLight->position[2]
thisLight->position[3]

=
=
=
=

1.0f;
1.0f;
1.0f;
1.0f;

vx = 1.0f; vy = 1.0f; vz = 1.0f;


VectorNormalize( &ierr, &vx, &vy,
thisLight->pointAtInfinity[0]
=
thisLight->pointAtInfinity[1]
=
thisLight->pointAtInfinity[2]
=
"V" in the infinite
thisLight->pointAtInfinity[3]
=
direction of vector "-v"
vx = -1.0f; vy = -1.0f; vz =
VectorNormalize( &ierr, &vx,
thisLight->spotDirection[0]
thisLight->spotDirection[1]
thisLight->spotDirection[2]
thisLight->spotDirection[3]

&vz );
vx;
vy;
vz;

// The light is "placed" at point

0.0f;

//

So

light

rays

flow

in

the

-1.0f;
&vy, &vz );
= vx;
= vy;
= vz;
= 0.0f;

thisLight->spotExponent
thisLight->spotCutOff

= 10.0f;
= 30.0f;

thisLight->a = 0.1f;
thisLight->b = 0.0f;

// GL_QUADRATIC_ATTENUATION
// GL_LINEAR_ATTENUATION

// must be degrees

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones


thisLight->c = 1.0f;

47

// GL_CONSTANT_ATTENUATION

}
void DestroyLight( light *thisLight ) {
if( ! thisLight ) return;
free( thisLight );
thisLight = NULL;
}
void SwitchLight( light *thisLight, int status ) {
if( ! thisLight ) return;
if(
thisLight->id < GL_LIGHT0 ) return;
thisLight->switched = status;
if( status ) {
glEnable( thisLight->id );
thisLight->needsUpdate = TRUE;
}
else {
glDisable( thisLight->id );
}
}
void SetLight( light *thisLight ) {
int
lightId;
if( ! thisLight ) return;
if( ! thisLight->switched ) return;
if(
thisLight->id < GL_LIGHT0 ) return;
lightId = thisLight->id;
// Geometric parameters will be always set when the scene is redrawn
if( thisLight->type == AGA_DIRECTIONAL ) {
glLightfv( lightId, GL_POSITION,
thisLight->pointAtInfinity );
}
else if( thisLight->type == AGA_POSITIONAL ) {
glLightfv( lightId, GL_POSITION,
thisLight->position );
}
else {
glLightfv( lightId, GL_POSITION,
thisLight->position );
glLightfv( lightId, GL_SPOT_DIRECTION,
thisLight->spotDirection );
}
// These other parameters are seldom changed
// So, they will be set only when any one of them is changed. The user
interface
// must set "needsUpdate" to TRUE, whenever any of these parameters changes
if( thisLight->needsUpdate ) {
thisLight->needsUpdate = FALSE;
glLightfv( lightId, GL_AMBIENT,
thisLight->ambient );
glLightfv( lightId, GL_DIFFUSE,
thisLight->diffuse );
glLightfv( lightId, GL_SPECULAR,
thisLight->specular );
if( thisLight->type == AGA_SPOT ) {
glLightf( lightId, GL_SPOT_EXPONENT,
thisLight->spotExponent );
glLightf( lightId, GL_SPOT_CUTOFF,
thisLight->spotCutOff );
}
else {
glLighti( lightId, GL_SPOT_EXPONENT,
0 );
glLighti( lightId, GL_SPOT_CUTOFF,
180 );
}
if( ! thisLight->attenuation || thisLight->type == AGA_DIRECTIONAL ) {
glLighti( lightId, GL_CONSTANT_ATTENUATION,
1 );
glLighti( lightId, GL_LINEAR_ATTENUATION,
0 );
glLighti( lightId, GL_QUADRATIC_ATTENUATION, 0 );
}
else {
glLightf( lightId, GL_CONSTANT_ATTENUATION,
thisLight->c );
glLightf( lightId, GL_LINEAR_ATTENUATION,
thisLight->b );
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

48

glLightf( lightId, GL_QUADRATIC_ATTENUATION, thisLight->a );


}
}
}
void Rotar_Luces_Longitud( light *thisLight, float inc ) {
float vIn[3];
vIn[0]= thisLight->position[0] ;
vIn[1]= thisLight->position[1] ;
vIn[2]= thisLight->position[2] ;
VectorRotY( vIn, inc );
thisLight->position[0] = vIn[0];
thisLight->position[2] = vIn[2];
}
void Rotar_Luces_Latitud( light *thisLight, float inc ) {
float vIn[3];
vIn[0]= thisLight->position[0] ;
vIn[1]= thisLight->position[1] ;
vIn[2]= thisLight->position[2] ;
VectorRotXZ( vIn, inc, TRUE );
thisLight->position[0] = vIn[0];
thisLight->position[1] = vIn[1];
thisLight->position[2] = vIn[2];
}
void Acercar_Alejar_Luces( light *thisLight, float step ) {
int ierr;
float vaX, vaY, vaZ;
float modulo;
vaX= thisLight->position[0];
vaY= thisLight->position[1];
vaZ= thisLight->position[2];
VectorNormalize( &ierr, &vaX, &vaY, &vaZ );
vaX= step * vaX;
vaY= step * vaY;
vaZ= step * vaZ;
// Set new position
modulo = sqrt(pow(thisLight->position[0] + vaX,2) + pow(thisLight->position[1] +
vaY,2) + pow(thisLight->position[2] + vaZ,2));
if(modulo < 0.8f) return;
thisLight->position[0] += vaX;
thisLight->position[1] += vaY;
thisLight->position[2] += vaZ;
}
void Rotar_Spot_Latitud( light *thisLight, float inc ) {
float vIn[3];
vIn[0]= thisLight->spotDirection[0] ;
vIn[1]= thisLight->spotDirection[1] ;
vIn[2]= thisLight->spotDirection[2] ;
VectorRotXZ( vIn, inc, TRUE );
thisLight->spotDirection[0] = vIn[0];
thisLight->spotDirection[1] = vIn[1];
thisLight->spotDirection[2] = vIn[2];
}
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

49

void Rotar_Spot_Longitud( light *thisLight, float inc ) {


float vIn[3];
vIn[0]= thisLight->spotDirection[0] ;
vIn[1]= thisLight->spotDirection[1] ;
vIn[2]= thisLight->spotDirection[2] ;
VectorRotY( vIn, inc );
thisLight->spotDirection[0] = vIn[0];
thisLight->spotDirection[2] = vIn[2];
}

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

50

#include <GL/glut.h>
#include "vector_tools.h"
void Draw_Parallel (float *At) {
double radius, angle;
float vectorX,vectorZ, vectorX1, vectorZ1;
int lightingFlag;
lightingFlag = glIsEnabled( GL_LIGHTING );
if( lightingFlag ) glDisable( GL_LIGHTING );
radius = sqrt(At[0]*At[0]+At[2]*At[2]);
vectorZ1=radius;
vectorX1=0.0;
glBegin(GL_LINE_STRIP);
for(angle=0.0f;angle<=(2.0f*3.14159);angle+=0.01f){
vectorX=radius*(float)sin((double)angle);
vectorZ=radius*(float)cos((double)angle);
glVertex3d(vectorX1,At[1],vectorZ1);
vectorZ1=vectorZ;
vectorX1=vectorX;
}
glEnd();
}
void Draw_Meridian (float *At) {
double radius, alfa, beta;
float vectorX, vectorY, vectorZ, vectorX1, vectorY1, vectorZ1;
int lightingFlag;
lightingFlag = glIsEnabled( GL_LIGHTING );
if( lightingFlag ) glDisable( GL_LIGHTING );
radius = sqrt(pow(At[0],2)+pow(At[1],2)+pow(At[2],2));
alfa = atan2(At[2],At[0]);
vectorX1=radius*(float)cos((double)alfa);
vectorY1=0;
vectorZ1=radius*(float)sin((double)alfa);
glBegin(GL_LINE_STRIP);
for(beta=0.0f;beta<=(2.0f*3.14159);beta+=0.01f){
vectorX=radius*(float)cos((double)beta)*(float)cos((double)alfa);
vectorY=radius*(float)sin((double)beta);
vectorZ=radius*(float)cos((double)beta)*(float)sin((double)alfa);
glVertex3d(vectorX1,vectorY1,vectorZ1);
vectorX1=vectorX;
vectorY1=vectorY;
vectorZ1=vectorZ;
}
glEnd();
}
void Draw_Vector(float *At, float *Direction) {
int ierr, lightingFlag;
float mod;
float alpha,beta;
float length = .2f;
float vectorX, vectorY, vectorZ;
lightingFlag = glIsEnabled( GL_LIGHTING );
if( lightingFlag ) glDisable( GL_LIGHTING );
mod = sqrt(pow(Direction[0],2)+pow(Direction[1],2)+pow(Direction[2],2));
alpha = atan2(Direction[0],Direction[2]);
beta = asin(Direction[1]/mod);
glBegin(GL_LINES);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f(At[0], At[1], At[2] );
glVertex3f(At[0]+Direction[0]*length,At[1]+Direction[1]*length,At[2]+Direction
[2]*length);
glEnd();
VectorNormalize( &ierr, &Direction[0], &Direction[1], &Direction[2]);
vectorX = At[0] + Direction[0]*(length-0.05);
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

51

vectorY = At[1] + Direction[1]*(length-0.05);


vectorZ = At[2] + Direction[2]*(length-0.05);
glTranslatef(vectorX, vectorY, vectorZ);
glRotatef(beta *RAD_TO_DEGREE, sin( alpha-PI_VALUE/2.0 ), 0.0f, cos( alphaPI_VALUE/2.0 ));
glRotatef( alpha*RAD_TO_DEGREE, 0.0f, 1.0f, 0.0f );
glutSolidCone(0.02,0.1,28,28);
}
void Draw_Sphere_Spot(float *At, float *Direction) {
int lightingFlag;
float mod;
float alpha,beta, alfa;
float length = .2f;
double radius, angle;
float vectorX, vectorY, vectorZ, vectorX1, vectorY1, vectorZ1;
lightingFlag = glIsEnabled( GL_LIGHTING );
if( lightingFlag ) glDisable( GL_LIGHTING );
mod = sqrt(pow(Direction[0],2)+pow(Direction[1],2)+pow(Direction[2],2));
alpha = atan2(Direction[0],Direction[2]);
beta = asin(Direction[1]/mod);
glLoadIdentity();
radius = sqrt(pow(Direction[0]*length,2)+pow(Direction[2]*length,2));
vectorX1=At[0];
vectorZ1=At[2]+radius;
glBegin(GL_LINE_STRIP);
for(angle=0.0f;angle<=(2.0f*3.14159);angle+=0.01f){
vectorX=At[0]+radius*(float)sin((double)angle);
vectorZ=At[2]+radius*(float)cos((double)angle);
glVertex3d(vectorX1,At[1]+Direction[1]*length,vectorZ1);
vectorZ1=vectorZ;
vectorX1=vectorX;
}
glEnd();
radius = sqrt( pow(Direction[0]*length,2) + pow(Direction[1]*length,2)
pow(Direction[2]*length,2) );
alfa = atan(Direction[2]/Direction[0]);
vectorX1=At[0]+radius*(float)cos((double)alfa);
vectorY1=At[1];
vectorZ1=At[2]+radius*(float)sin((double)alfa);
glBegin(GL_LINE_STRIP);
for(beta=0.0f;beta<=(2.0f*3.14159);beta+=0.01f){
vectorX=At[0]+radius*(float)cos((double)beta)*(float)cos((double)alfa);
vectorY=At[1]+radius*(float)sin((double)beta);
vectorZ=At[2]+radius*(float)cos((double)beta)*(float)sin((double)alfa);
glVertex3d(vectorX1,vectorY1,vectorZ1);
vectorX1=vectorX;
vectorY1=vectorY;
vectorZ1=vectorZ;
}
glEnd();

}
void drawSphereTurtle() {
int slices = 40;
int stacks = 40;
glPushMatrix();
glScalef(1.0f,.3f,1.0f);
glutSolidSphere(1.0,slices,stacks);
glPopMatrix();
glPushMatrix();
glTranslatef(.7f,0.0f,.7f);
glutSolidSphere(.3,slices,stacks);
glPopMatrix();
glPushMatrix();
glTranslatef(-.7f,0.0f,.7f);
glutSolidSphere(.3,slices,stacks);
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

52

glPopMatrix();
glPushMatrix();
glTranslatef(.7f,0.0f,-.7f);
glutSolidSphere(.3,slices,stacks);
glPopMatrix();
glPushMatrix();
glTranslatef(-.7f,0.0f,-.7f);
glutSolidSphere(.3,slices,stacks);
glPopMatrix();
glPushMatrix();
glScalef(1.0f,.6f,1.0f);
glTranslatef(0.0f,0.0f,-1.2f);
glutSolidSphere(.4,slices,stacks);
glPopMatrix();
}

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

53

6. TIPOS DE FUENTES DE LUZ


Una vez que han establecido distintas luces en la escena, se va a explicar que tipos de
luces existen y como se introducen en la aplicacin tecnunLogo.
6.1 TIPOS DE LUCES
Se puede decidir tener una fuente de luz que sea tratada como si estuviera localizada
en infinitamente lejos de la escena o una que sea cercana a la escena.
6.1.1

Direccional
El primer tipo referido, se conoce como fuente de luz direccional. En este caso se
define la direccin de la que proviene la luz, como si la fuente de luz estuviera situada en
el infinito, por lo que todos los rayos son paralelos.
Los argumentos de la funcin glLight*() es un vector de cuatro valores (x,y,z,w) para
el parmetro GL_POSITION. En las luces direccionales, el valor de w, es cero y los
valores (x,y,z) describen la direccin.
6.1.2

Posicional
El segundo tipo referido se conoce como fuente de luz posicional, ya que su posicin
exacta dentro de la escena determina el efecto que tiene sobre esta, especficamente, la
direccin desde la cual vienen los rayos de luz.
Los argumentos de la funcin glLight*() es un vector de cuatro valores (x,y,z,w) para
el parmetro GL_POSITION. En las luces direccionales el valor, w, es distinto de cero y
los valores (x,y,z) definen la localizacin de la fuente de luz.
Otro efecto que se produce en la realidad es que la intensidad de la luz decrece al
aumentar la distancia de la luz. Esto es aplicable nicamente a las luces posicionales, ya
que las direccionales estn situadas en el infinito. La forma de definir la atenuacin en
OpenGL es mediante un factor de atenuacin:
factor de atenuacin =

donde
d

1
kc + kl d + k q d 2

: distancia entre la luz y el vrtice

kc

: GL_CONSTANT_ATTENUATION

kl

: GL_LINEAR_ATTENUATION

kq

: GL_QUADRATIC_ATTENUATION

6.1.3

Focal
Una luz posicional irradia en todas las direcciones, pero se puede restringir la
direccin en que acta de forma que se produzca un cono de luz definiendo lo que se

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

54

conoce como una luz de tipo foco (spotlight) (un ejemplo puede ser un foco o una lmpara
tipo flexo).
En las luces focales hay que definir, adems de la posicin por ser posicional:
1. La direccin del foco
2. El ngulo del cono de luz.
3. La intensidad de la distribucin de la luz en el cono.
La direccin del eje del cono de luz se define con el parmetro
GL_SPOT_DIRECTION que es un vector de 3 posicones (x, y, z).
El ngulo del cono de luz se define con el parmetro GL_SPOT_CUTOFF que
define el ngulo entre el eje del cono y una arista de dicho cono. En la figura 2 se muestra
este ngulo. El valor por defecto anula el efecto de la luz focal al ser de 180 grados e
irradiar todo el espacio. Los valores posibles de este parmetro es de 0 a 90 grados.

GL_SPOT_CUTOFF

Figura 2.

Parmetro GL_SPOT_CUTOFF

La intensidad de la distribucin de la luz dentro del cono se fija, adems de con el


factor de atenuacin de cualquier luz posicional, mediante el parmetro
GL_SPOT_EXPONENT que determina cmo disminuye la intensidad de la luz al alejarse
del eje del cono. La luz se atena hacia los bordes del cono de luz mediante un exponente,
cuanto mayor es este exponente, la luz esta ms focalizada.
6.2 CONTROL DE LOS DISTINTOS TIPOS DE LUCES
6.2.1

Tipos de luces
Las tres luces de que dispone el programa tecnunLogo, actualmente las tres del
mismo tipo, se van a cambiar para que cada una sea de un tipo: una de tipo direccional, una
de tipo posicional y una de tipo spotlight. Esto permitir estudiar las diferentes
caractersticas de los tipos de luces y cuales son sus efectos sobre la escena tanto al
cambiar su posicin o direccin como al cambiar las componentes propias de la luz.
Adems, permitiendo que puedan ser encendidas o apagadas de forma independiente se
pueden estudiar los efectos de combinaciones entre ellas.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

55

6.2.2

Interface de usuario
El interface de usuario actual permite pasar al Modo Luces y pasar el control de una
luz a otra, encender y apagar cada una de las luces e indicar la direccin de las luces
direccionales. Se va a aadir la posibilidad de controlar la direccin y ngulo de la luz de
tipo spotlight (Tabla 6.1).

Figura 3. Luz Direccional

Figura 4. Luz Posicional

En las figuras 2, 3 y 4 se muestra


cmo aparecern representados en el
programa tecnunLogo cada uno de los
tipos de luz.
La luz direccional se indica su
direccin mediante un paralelo y un
meridiano y viene representada con un
vector dirigido siempre hacia el centro de
la escena que indica su direccin. En el
caso de luz posicional aparecer una esfera
y en el caso de luz tipo spotlight su
representacin es a travs de una esfera
que indica la posicin y un vector con otro
paralelo y meridiano que indica la
direccin del cono de luz que emite.
Figura 5. Luz Spotlight

Mediante el ratn ser posible cambiar la posicin de las luces (Tabla 6.2) y para el
caso de la luz tipo spotlight cambiar tambin la direccin de la luz y el ngulo de apertura
del cono de luz (Tabla 6.3).

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

56

6.2.3

Modificaciones en el cdigo
Se va a dotar al programa de los tres tipos de luces expuestas en el apartado anterior
que permitirn observar las diferencias entre ellas y su efecto en la escena. Para ello se
permitir interactuar con la posicin y direccin de cada una de ellas y mantenerlas
encendidas o apagadas independientemente una de otra. Para ello se utilizar el interface
de luz definido en la prctica 5 y se realizarn modificaciones al cdigo.
Tecla
F1

Accin
Desactivar luces (en general, desactivar cualquier modo)
Modo luces. Cada vez que se pulsa se pasa de una luz a otra:

F8
F9

Direccional

Posicional

Spotlight

ON/OFF la luz con la cual se est interactuando.


Cuando se est interactuando con la luz tipo spotlight, pulsando F10 se pasa de
controlar la posicin de la luz a controlar la direccin de esta y viceversa:

F10

Posicin

Direccin

Tabla 6.1. Teclas del Modo Luces


Movimiento del Ratn

Accin

Adelante/Atrs

Movimiento de la luz con la cual se est


interactuando a lo largo de un meridiano
con centro en el origen de coordenadas de la
escena.

Izquierda/Derecha

Movimiento de la luz con la cual se est


interactuando a lo largo de un paralelo con
centro en el eje Y.

Adelante/Atrs con botn izquierdo pulsado

Movimiento de la luz a lo largo del vector


que une la posicin de la luz con el centro de
coordenadas de la escena.

Tabla 6.2. Movimiento de la posicin de las luces

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

57

Movimiento del Ratn

Accin

Adelante/Atrs

Movimiento del extremo del vector de


direccin del spotlight a lo largo de un
meridiano con centro en la posicin de la
luz.

Izquierda/Derecha

Movimiento del extremo del vector de


direccin del spotlight a lo largo de un
paralelo con centro en la vertical que pasa
por la posicin de la luz.

Adelante/Atrs con botn izquierdo pulsado

Incremento/Decremento
apertura del spotlight..

del

ngulo

de

Tabla 6.3. Control de la direccin y apertura del cono de luz del spotlight
Para la luz del tipo spotlight har falta una variable ms que indique si se est
interactuando con la posicin de la luz o con el vector de direccin.. Se incluyen las
siguientes lneas en el fichero tecnunLogo.c inmediatamente despus de los ficheros de
cabecera:
static int spot_move = 0;

Se deben dar las caractersticas a cada una de las luces. Esto lo realizamos
modificando las siguientes sentencias en la funcin main() del programa:
//Creamos las luces y damos a cada una sus caractersticas
//DIRECCIONAL
LOCAL_MyLights[0] = CreateDefaultLight();
LOCAL_MyLights[0]->type = AGA_DIRECTIONAL;
LOCAL_MyLights[0]->id = GL_LIGHT0 + i;
LOCAL_MyLights[0]->position[0] = 1.0f;
LOCAL_MyLights[0]->position[1] = 1.0f;
LOCAL_MyLights[0]->position[2] = 1.0f;
LOCAL_MyLights[0]->position[3] = 0.0f;
LOCAL_MyLights[0]->pointAtInfinity[0] = LOCAL_MyLights[0]->position[0];
LOCAL_MyLights[0]->pointAtInfinity[1] = LOCAL_MyLights[0]->position[1];
LOCAL_MyLights[0]->pointAtInfinity[2] = LOCAL_MyLights[0]->position[2];
//POSICIONAL
LOCAL_MyLights[1] = CreateDefaultLight();
LOCAL_MyLights[1]->type = AGA_POSITIONAL;
LOCAL_MyLights[1]->id = GL_LIGHT1;
LOCAL_MyLights[1]->position[0] = 1.0f;
LOCAL_MyLights[1]->position[1] = 1.0f;
LOCAL_MyLights[1]->position[2] = -1.0f;
LOCAL_MyLights[1]->position[3] = 1.0f;
//SPOT
LOCAL_MyLights[2] = CreateDefaultLight();
LOCAL_MyLights[2]->type = AGA_SPOT;
LOCAL_MyLights[2]->id = GL_LIGHT2;
LOCAL_MyLights[2]->position[0] = -1.0f;
LOCAL_MyLights[2]->position[1] = 1.0f;
LOCAL_MyLights[2]->position[2] = 1.0f;
LOCAL_MyLights[2]->spotDirection[0] = 1.0f;
LOCAL_MyLights[2]->spotDirection[1] = -1.0f;
LOCAL_MyLights[2]->spotDirection[2] = -1.0f;

De esta forma quedan definidos los interfaces para las tres luces en un array. Con el
ndice 0 se tiene una luz direccional, con el ndice 1 se tiene una luz posicional y con el
ndice 2 se tiene una luz tipo spotlight.
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

58

En la funcin SpecialKey() se debern incluir las sentencias necesarias para definir


las teclas que permiten pasar al modo de movimiento de la direccin del spotlight:
case GLUT_KEY_F10:
if (current_light == 2){
if ( spot_move == 0 ){
glutPassiveMotionFunc(Mouse_Spot);
spot_move = 1;
}else{
glutPassiveMotionFunc(Mouse_Luces);
spot_move = 0;
}
}
break;

La funcin Mouse_Spot(int x, int y) mover el vector de direccin de la luz tipo


spotlight, cuando se est interactuando con l, a lo largo de un paralelo o un meridiano
segn los movimientos del ratn definidos con anterioridad:
void Mouse_Spot(int x, int y){
float rot_x, rot_y;
rot_y = (float)(old_y - y);
rot_x = (float)(x - old_x);
Rotar_Spot_Latitud(LOCAL_MyLights[current_light],rot_y*DEGREE_TO_RAD);
Rotar_Spot_Longitud(LOCAL_MyLights[current_light],rot_x*DEGREE_TO_RAD);
old_y = y;
old_x = x;
glutPostRedisplay();
}

La funcin mouse() quedar de la siguiente forma despus de incluir las sentencias


necesarias para interactuar con las luces:
void mouse(int button, int state, int x, int y){
old_x = x;
old_y = y;
switch(button){
case GLUT_LEFT_BUTTON:
if(current_light > 0){
if(current_light == 2 && spot_move == 1){
if (state == GLUT_DOWN)
glutMotionFunc(Mouse_Spot_Abrir_Cerrar);
if (state == GLUT_UP){
glutPassiveMotionFunc(Mouse_Spot);
glutMotionFunc(NULL);
}
}else{
if (state == GLUT_DOWN)
glutMotionFunc(Mouse_Luces_Acercar_Alejar);
if (state == GLUT_UP){
glutPassiveMotionFunc(Mouse_Luces);
glutMotionFunc(NULL);
}
}
}else{
switch(LOCAL_MyCamera->camMovimiento){
case CAM_EXAMINAR:
if (state == GLUT_DOWN) glutMotionFunc(Zoom);
if (state == GLUT_UP){
glutPassiveMotionFunc(Examinar);
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

59

glutMotionFunc(NULL);
}
break;
case CAM_PASEAR:
if (state == GLUT_DOWN) glutMotionFunc(Andar);
if (state == GLUT_UP) glutMotionFunc(NULL);
break;
}
}
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) ;
break;
default:
break;
}
glutPostRedisplay();
}

Se ve que se realizan llamadas a la funcin callback glutMotionFunc() que responde


a los movimientos del ratn cuando se tiene pulsado algn botn de este. Si se est
interactuando con la direccin de la luz tipo spotlight, se le pasar por ventana la funcin
que se encarga de abrir o cerrar el ngulo del cono de luz, ngulo que variar entre 0 y 90
grados:
void Mouse_Spot_Abrir_Cerrar(int x, int y){
float step;
step = (float) (y - old_y) ;
old_y = y;
if(LOCAL_MyLights[current_light]->spotCutOff + step < 90 &&
LOCAL_MyLights[current_light]->spotCutOff + step > 0)
LOCAL_MyLights[current_light]->spotCutOff += step ;
LOCAL_MyLights[current_light]->needsUpdate = TRUE;
glutPostRedisplay();
}

La funcin display() quedar de la siguiente forma:


void display(void) {
float At[3];
float Direction[3];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
SetGLCamera( LOCAL_MyCamera );
SetLight( LOCAL_MyLights[0] );
SetLight( LOCAL_MyLights[1] );
SetLight( LOCAL_MyLights[2] );
glPushMatrix();
glColor3f(1.0,1.0,0.0);
drawSphereTurtle();
switch( current_light ){
case 0:
At[0] = LOCAL_MyLights[current_light]->position[0];
At[1] = LOCAL_MyLights[current_light]->position[1];
At[2] = LOCAL_MyLights[current_light]->position[2];
Direction[0] = - LOCAL_MyLights[current_light]->position[0];
Direction[1] = - LOCAL_MyLights[current_light]->position[1];
Direction[2] = - LOCAL_MyLights[current_light]->position[2];
Draw_Parallel(At);
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

60

Draw_Meridian(At);
Draw_Vector(At, Direction);
break;
case 1:
At[0] = LOCAL_MyLights[current_light]->position[0];
At[1] = LOCAL_MyLights[current_light]->position[1];
At[2] = LOCAL_MyLights[current_light]->position[2];
Draw_Parallel(At);
Draw_Meridian(At);
glTranslatef(At[0],At[1],At[2]);
glColor3f(1.0,0.0,0.0);
glutSolidSphere(0.05,28,28);
break;
case 2:
At[0] = LOCAL_MyLights[current_light]->position[0];
At[1] = LOCAL_MyLights[current_light]->position[1];
At[2] = LOCAL_MyLights[current_light]->position[2];
Direction[0] = LOCAL_MyLights[current_light]->spotDirection[0];
Direction[1] = LOCAL_MyLights[current_light]->spotDirection[1];
Direction[2] = LOCAL_MyLights[current_light]->spotDirection[2];
Draw_Parallel(At);
Draw_Meridian(At);
glColor3f(1.0,0.0,0.0);
Draw_Vector(At, Direction);
Draw_Sphere_Spot(At, Direction);
glTranslatef(At[0],At[1],At[2]);
glutSolidSphere(0.05,28,28);
break;
default:
break;
}
glPopMatrix();
glutSwapBuffers();
}

6.3 TRABAJOS PROPUESTOS

En la luz tipo spotlight, que se muestre el cono de luz.


Definir las propiedades del material de la tortuga.
Proporcionar al programa alguna forma amigable de interactuar con las
propiedades del material (interface de usuario).

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

61

7. LEYENDO OBJETOS: OTRAS TORTUGAS Y EL ESCENARIO


Hasta ahora, en la aplicacin tecnunLogo se han utilizado para representar a la
tortuga primitivas de OpenGL u objetos generados en el propio cdigo del programa. Si se
desea representar objetos con ms detalles de modelado lo ms lgico es generarlos con
aplicaciones de modelado y leerlos en la aplicacin. En este captulo se explica el modo de
leer y representar objetos en formato Wavefront. Posteriormente se generaliza el control y
representacin de una tortuga a un nmero variable de las mismas.
7.1 REPRESENTACIN DE UN OBJETO EN FORMATO WAVEFRONT
Existen multitud de formatos para representar un objeto en tres dimensiones. Uno de
ellos es el formato Wavefront.
http://www.tnt.uni-hannover.de/js/soft/compgraph/fileformats/docs/OBJ.format.txt
Para leer dichos formatos se va a utilizar la librera glm.
http://www.opengl.org/developers/code/examples/more_samples/smooth.zip
Se deben aadir los ficheros glm.c y glm.h al directorio del proyecto y aadirlos al
proyecto (Project / Add to Project / Files ...).
Adems de la librera se han creado unas funciones para facilitar el uso de dicha
librera, estas funciones se encuentran en los ficheros glmObject.c y glmObject.h que
tambin se deben copiar al directorio del proyecto y aadirlos al proyecto.
Incluir en tecnunLogo el include de glmObject.h, no es necesario el de glm.h puesto
que lo incluye glmObject.h:
#include "glmObject.h"

Incluir el puntero al objeto que se va a leer:


static glmObject

*object;

Incluir en la funcin main la comprobacin de que existe el argumento nmero 1 que


es el que va a proporcionar el nombre del fichero en el que se encuentra el objeto a
representar:
if (!argv[1]) {
fprintf(stderr, "usage: tecnunLogo model_file.obj\n");
exit(1);
}

Incluir en la funcin main la llamada a la funcin createGlmObject() que realiza la


lectura del fichero, esta funcin se puede leer en glmObject.c:
object = createGlmObject(argv[1]);

Substituir el dibujo actual de la tortuga:


drawSphereTurtle();

por la representacin del objeto que se ha ledo:


glCallList(object->model_list);

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

62

En modo de debugger, para indicar el


nombre del primer argumento, se debe
incluir en la configuracin del proyecto
(Project /Settings / Debug/ Program
arguments: ). Proporcionar por ejemplo el
valor:
../data/porsche.obj

En la figura 1se puede apreciar el


aspecto el de la aplicacin con el objeto
representado e iluminado:

7.2 VARIAS TORTUGAS


Se va a implementar a continuacin el comando SETTURTLE i, que activa un
nmero de objeto i, pudiendo ir i de 0 a n. Si la tortuga i no est creada se crea en ese
momento. Para asociar un objeto a la tortuga se va implementar el comando
OBJECTLOAD fileName.
Para manejar varias tortugas se crea la estructura turtle, que contiene la informacin
de cada una de las posibles tortugas en el escenario. La declaracin se introduce con el
resto de declaraciones en el fichero tecnunLogo.c
typedef struct _turtle
{
int np;
float px [10000];
float py [10000];
float pz [10000];
glmObject
*object;
GLdouble mModel[16];
} turtle;

Se crean variables para almacenar el nmero de tortugas existentes, un vector para


contener todas las tortugas posibles (256 en este caso) y un puntero a la tortuga actual, la
designada por SETTURTLE i.
int nturtles;
turtle *turtleVector[256];
turtle *actualTurtle;

En la funcin main se inicializa el vector de tortugas y la primera tortuga (posicin 0)


con el valor del primer argumento, como se ha hecho en el primer apartado. En este caso se
inicializa tambin la matriz mModel de la primera tortuga:
turtleVector[0] = (turtle*) malloc(sizeof(turtle));
turtleVector[0]->np = 0;
actualTurtle = turtleVector[0];
nturtles = 1;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glGetDoublev (GL_MODELVIEW_MATRIX, actualTurtle->mModel);
glPopMatrix();
actualTurtle->object = createGlmObject(argv[1]);
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

63

En display se debe realizar un bucle para todas las tortugas existentes:


Ejes_World(); // ejes globales
for (i=0; i < nturtles; i++){
if (turtleVector[i] != NULL) {
glColor3f(1.0,1.0,0.0) ;
displayTrace(turtleVector[i]);
glPushMatrix();
glMultMatrixd(turtleVector[i]->mModel);
Ejes_World(); // ejes locales
glColor3f(1.0,1.0,0.0) ;
if (turtleVector[i]->object != NULL)
glCallList(turtleVector[i]->object->model_list);
else
drawTurtle();
glPopMatrix();
}
}

En la interpretacin de los comandos se deben aador los comandos SETTURTLE y


OBJECTLOAD, abreviados por st y ol:
} else if (!strcmp("st",strToken0)) {
printf("SETTURTLE");
ival = val;
actualTurtle = turtleVector[ival];
if (actualTurtle == NULL) {
turtleVector[ival] = (turtle*) malloc(sizeof(turtle));
turtleVector[ival]->np = 0;
turtleVector[ival]->object = NULL;
actualTurtle = turtleVector[ival];
if ((ival + 1) > nturtles) nturtles = ival + 1;
glLoadIdentity();
glGetDoublev (GL_MODELVIEW_MATRIX, actualTurtle->mModel);
}
glLoadIdentity();
glMultMatrixd(actualTurtle->mModel);
} else if (!strcmp("ol",strToken0)) {
printf("OBJECTLOAD");
actualTurtle->object = createGlmObject(strToken1);

Se deben modificar adems las funciones addPointToTrace(), displayTrace() y


parseCommand().
En addPointToTrace() los puntos se aaden a la tortuga actual, ya que la variable np
y los vectores px, py y pz pertenecen ahora a la estructura turtle.
La funcin displayTrace(turtle* turtlei) dibuja el rastro de la tortuga que se le pasa
como parmetro, que es la que contiene la informacin de los puntos (np, px, py y pz).
En parseCommand(char* command), se manipula la matriz de la tortuga actual
(actualTurtle->mModel).

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

64

El resultado se muestra en
la figura 2, en la que se han
introducido 4 tortugas, 3 de
ellas con el objeto de un
vehculo.

7.3 TRABAJOS PROPUESTOS

Definir un modo (MOVEBOX ON / MOVEBOX OFF), en el que al mover


la escena, los objetos se representen por cajas.
Actualmente los objetos se escalan para que tengan una dimensin de
uno. Realizar esta operacin si el modo autoescala est en ON y no
realizarlo cuando est en OFF. El comando es AUTOSCALE ON /
AUTOSCALE OFF.
Permitir tener n luces, (estar limitado a las 8 que permite OpenGL)
cada una de las cuales puede ser de uno de los tres tipos posibles
(direccional, posicional o spotlight). Para ello se debe utilizar una
estructura similar al vector de tortugas utilizado en este captulo.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

65

8. OPCIONES DE VISUALIZACIN: PROPIEDADES DE OPEN GL


En OpenGL, como en todas las libreras grficas, se pueden especificar propiedades
que determinan como se realiza la representacin de las imgenes. Entre estas propiedades
se encuentran el modo de sombreado, el modo de representar los polgonos, utilizar el
doble buffer, utilizar el Z-buffer, el borrado y color de fondo, etc.
En este captulo se va a proporcionar a la
aplicacin tecnunLogo del interfaz necesario para
controlar estas propiedades durante la ejecucin de
la aplicacin. En concreto, las propiedades que se
controlan son:
Representacin de lneas (figura 1).

Polgonos sin sombreado (figura 2).


Representacin sin iluminacin
(figura 3).

Activar / desactivar el doble buffer.


Activar / desactivar el Z buffer.
Establecer el color de fondo.

Activar / desactivar el borrado de la imgen


en cada escena.

Modo de representar los materiales,


utilizado en la funcin list() de
glmObject.c
Eliminacin de caras traseras (cull face).

8.1 TRABAJOS PROPUESTOS

Controlar las caractersticas descritas


para el objeto activo o para todos, con
los comando Apply All / Apply active.
Crear un menu con el que se controlan
estan mismas propiedades. Un ejemplo
de construccin de este men se
encuentra en la aplicacin smooth,
indicada en el captulo anterior.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

66

9. CREANDO OBJETOS: LECTURA DE COORDENADAS DE VRTICES


Los objetos utilizados en las prcticas anteriores se encontraban ya creados y lo que
se hace el programa es leerlos para representarlos. Si lo que se desea es generar nuevos
objetos la forma ms habitual es mediante un modelizador de slidos, ya sea de propsito
general (Studio 3D, Strata, trueSpace, ...) o uno orientado a la ingeniera (ProEngineer,
Microstation, ...).
9.1 DIGITALIZACIN DE MODELOS
Otra posibilidad es la de crear
objetos a partir de modelos reales de los
mismos, que es lo que se realiza en este
captulo. Para ello se parte del diseo
de un vehculo Volkswagen Beetle.
Este diseo ha sido construido en el
curso de diseo organizado en Tecnun
en Julio de 2002. En las imgenes se
muestran dos etapas del proceso.
En esta prctica se parte del
prototipo construido para digitalizarlo e
introducir sus coordenadas en un objeto
Wavefront.
Para digitalizar los vrtices se
utiliza una mquina de medir por
coordenadas. La utilizacin habitual de
esta mquina es la obtencin de las
dimensiones de una pieza a partir de
diferentes coordenadas para comprobar
la adecuacin de la pieza a las
especificaciones. En la prctica se
utilizar la mquina para obtener las
coordenadas, ya que no se desea
contrastarlas con otros datos.
La precisin que proporciona la mquina de medir por coordenadas es bastante ms
alta de la necesaria para definir un objeto, por lo que no sern ncesarios todos los
decimales que proporciona.
En la prctica, para digitalizar modelos se utilizan escneres lasers o robots
artculados que agilizan la captura, pero el proceso es el mismo que el descrito en este
captulo.
9.2 CARACTERSTICAS DE LA MQUINA DE MEDIR POR COORDENADAS
Las partes principales de la mquina de medir por coordenadas son:
Mesa: de granito, para evitar deformaciones trmicas.
Carros: permiten la traslacin en los tres ejes. Cada carro dispone de cojinetes
neumticos para suavizar el movimiento.
Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

67

Palpador: elemento en el que se montan las agujas que realizan el contacto con la
pieza. El palpador empleado habitualmente, PH), dispone de dos grados de libertad que le
permite orientarse en cualquier direccin del espacio.
Agujas: son unas esferas de rub unidas a un cilindro que se montan en el palpador.
Mando de control: permite mover los tres carros para efectuar el contacto de la aguja
con la pieza, dispone tambin de controles para cambiar la velocidad (posicionamiento y
medicin), registrar puntos de posicionamiento, potencimetro para graduar la velocidad
en modo de medicin y los de seguridad (hombre muerto y emergencia).
Ordenador: una aplicacin de software para controlar la mquina.
9.3 PROCESO DE CAPTURA DE COORDENADAS
El primer paso es determinar los puntos del vehculo que se van a digitalizar. Para
ello se traza una malla sobre el modelo. Los puntos de interseccin de las lneas
horizontales y verticales determinan los puntos a digitalizar. La separacin de las lneas se
establece en funcin de la curvatura de las superficies, de modo que en aquellos puntos que
la curvatura es mayor, las lneas se encuentran ms prximas.
A continuacin se capturarn las coordenadas. En este caso de todas las formas de
medicin de que dispone la mquina, se elige la ms simple, que es la de medicin de un
punto, ya que interesan las coordenadas x, y, z de cada vrtice.
Con las coordenadas capturadas se pasan a un fichero de datos que es necesario
convertir en un objeto Wavefront. Para ello, a la geometra capturada se aade la topologa
que define los vrtices que forman cada cara.
La digitalizacin se realiza para uno de los lados del vehculo, ya que la otra mitad se
obtiene por simetra.
9.4 DIGITALIZACIN POR FOTOGRAFA
Si no se dispone de una mquina de medir por coordinadas, se puede realizar una
aproximacin de este mtodo mediante varias fotografas de un objeto desde los distintos
ejes. Al menos son necesarias dos fotografas. Podran obtenerse desde dos direcciones
arbitrarias, pero el proceso se simplifica si se realiza desde dos direcciones ortogonales.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

68

10. EL MAPEADO DE TEXTURAS


En los captlos previos, las primitivas se han dibujado definiendo un color para la
primitiva o para cada uno de los vrtices, con lo que OpenGL interpola entre dichos
vrtices. Otra forma de representar las superficies es mediante las funciones de mapeado de
texturas que dispone OpenGL. El mapeado de una textura consiste bsicamente en pegar
imgenes, mediante una determinada transformacin, en la superficie de las primitivas
dibujadas. Este efecto permite aadir mayor realismo a la escena. En este capitulo se
explica el proceso de mapeado de texturas a travs de un sencillo ejemplo, para
posteriormente emplear las texturas en la aplicacin tecnunLogo.
10.1

CARGANDO Y PEGANDO UNA TEXTURA

En este capitulo se va a utilizar la funcin LoadDIBitmap (de Michael Sweet,


OpenGL SuperBible) para cargar archivos grficos de tipo bmp. Para esto se deben incluir
al directorio del proyecto los archivos bitmap.c y bitmap.h y aadirlos al proyecto (Project
/ Add to Project / Files...). Tambin es necesario incluir el archivo escudo.bmp . Los
archivos se encuentran en la direccin:
http://www.tecnun.es/asignaturas/grafcomp/practicas/textures/escudo.bmp
http://www.tecnun.es/asignaturas/grafcomp/practicas/textures/bitmap.c
http://www.tecnun.es/asignaturas/grafcomp/practicas/textures/bitmap.h
El cdigo del ejemplo es el siguiente:
#include <GL/glut.h>
#include "bitmap.h"
BITMAPINFO *TexInfo; /* Texture bitmap information */
GLubyte
*TexBits; /* Texture bitmap pixel bits */
void display(void) {
glClearColor (1.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
TexBits = LoadDIBitmap("escudo.bmp", &TexInfo);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TexInfo->bmiHeader.biWidth,
TexInfo->bmiHeader.biHeight, 0, GL_BGR_EXT,
GL_UNSIGNED_BYTE, TexBits);
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(GL_TEXTURE_2D,

GL_TEXTURE_WRAP_S, GL_REPEAT);
GL_TEXTURE_WRAP_T, GL_REPEAT);
GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glColor3f(1.0, 1.0, 1.0);


//se activa el mapeado de texturas
glEnable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 0.0);
glVertex2f(-1.0, -1.0);
glTexCoord2f(1.0, 0.0);
glVertex2f(1.0, -1.0);
glTexCoord2f(1.0, 1.0);
glVertex2f(1.0, 1.0);
glTexCoord2f(0.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

69

glDisable(GL_TEXTURE_2D);
glutSwapBuffers() ;
}
void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)height / (GLfloat)width, 1.0, 128.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(400, 400);
glutInitWindowPosition(100, 100);
glutCreateWindow("tecnunLogo");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

Como puede observarse, la funcin main() y reshape() son muy similares a las ya
vistas en prcticas anteriores. Para entender el proceso de mapeado de texturas se va a
explicar nicamente la funcin display().
Las texturas en OpenGL pueden ser 1D, 2D o 3D. Las 1D tienen anchura pero no
altura; las 2D son imgenes que tienen una anchura y una altura de ms de 1 pxel, y son
generalmente cargadas a partir de un archivo .bmp (aunque puede ser en principio
cualquier formato). En este capitulo no se hablar de las texturas 3D (volumen). Un
aspecto muy importante a tener en cuenta es que en OpenGL las dimensiones de las
imgenes deben ser potencia de 2 (2, 4, 8, 16, 32...)
Antes de definir la textura, se carga una imagen a partir de un archivo (.bmp en este
caso). Para esto es necesario incluir dos punteros, TexInfo y TexBits, para almacenar la
informacin de la imagen (header) y los bits que componen la imagen respectivamente. Se
carga la imagen con la funcin LoadDIBitmap() y se le pasa como argumentos el nombre
de la imagen ( escudo.bmp en este caso) y el puntero que guardar la informacin de
dicha imagen (header).
Para definir las texturas, OpenGL pone a disposicin las funciones glTexImage1D y
glTexImage2D (la nica diferencia entre ambas es que en la segunda se define, adems, la
altura de la imagen). La funcin glTexImage2D tiene 9 argumentos:
void glTexImage2D(GLenum target, GLint level, GLint components, GLsezei width, GLsizei height, GLint
border, GLenum format, GLenum type, const GLvoid *pixels)

El target indica el tipo de textura que va a definirse, en este caso


GL_TEXTURE_2D. Level el nivel de detalle de la imagen, generalmente se utiliza el valor
0. Components el nmero de colores que han sido utilizados en la definicin de cada pxel
de la imagen, en este caso 3. Width y height son las dimensiones de la imagen, siempre
potencia de 2, y se accede a esta informacin por medio de la variable TexInfo. Border
indica el nmero de pxeles que debe tener el borde de la textura, y toma valores de 0, 1 o
2. Format el tipo de colores que se espera tenga la textura. Type el tipo de datos en que va
a ser pasada la informacin de la imagen cargada, y pixels es la informacin en bits de esa
imagen, que en este caso est almacenada en la variable TexBits.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

70

Una vez cargada la imagen y definida la textura, se define la manera de cmo ser
aplicada la textura a cada pxel de la superficie que queremos texturizar por medio de la
funcin glTexParameteri().
t
La textura tiene 2 coordenadas, la s para el
(0.0, 1.0)
(1.0, 1.0)
eje horizontal y la t para el eje vertical, y toma
valores de 0.0 a 1.0. Para la coordenada s 0.0
representa el extremo izquierdo de la textura y
1.0 el extremo derecho. Para la t el 0.0
representa el extremo inferior y el 1.0 el
s
superior.
(0.0, 0.0)

(1.0, 0.0)

Texture Wrap. Cuando se pega la textura a


una superficie debe indicarse la correspondencia entre las coordenadas de la textura los
vrtices de dicha superficie. Si las coordenadas que hacen referencia a la textura se salen
del rango 0-1, la textura se repite (GL_REPEAT) o se estira (GL_CLAMP) sobre la
superficie segn se defina en el TEXTURE_WRAP. En este ejemplo se define que, en
ambas direcciones s y t, la textura se repita:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

Texture Filters. Cuando la imagen de la textura no se adecua con el tamao de la


superficie que se quiere cubrir, OpenGL utiliza unos filtros de textura para interpolar entre
los pxeles de la imagen y adecuarla a la superficie. Cuando la superficie sea menor que la
imagen OpenGL utilizar un minification filter (GL_TEXTURE_MIN_FILTER) y cuando
la superficie sea mayor que la imagen, utilizar un magnification filter
(GL_TEXTURE_MAG_FILTER). OpenGL pone a disposicin 6 tipos de filtros (ver
tutorials). En este caso se ha optado por una interpolacin lineal:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

Una vez se tiene definida completamente la


textura, se activa el mapeado de texturas por medio
de la funcin glEnable(GL_TEXTURE_2D) y se
dibuja la escena, indicando la correspondencia entre
las coordenadas de la textura y las coordenadas de
los vrtices de la superficie. Para hacer referencia a
las coordenadas de la textura se utiliza la funcin
glTexCoord2f() (o glTexCoord3f(), segn sea el
caso).
10.2

CARGANDO
TECNUNLOGO

Y PEGANDO UNA TEXTURA EN

Para cargar una imagen y pegar una textura en tecnunLogo se siguen los mismos
pasos que en la aplicacin previa. Estos pasos son:

Cargar una imagen (LoadDIBitmap) y definirla como textura (glTexImage2D).


Indicar cmo se aplicar la textura (glTexParameteri).
Activar el mapeado de texturas (glEnable(GL_TEXTURE_2D)).
Dibujar la escena aadiendo las coordenadas de la textura (glTexCoord2f).

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

71

Aplicando estos pasos a la aplicacin tecnunLogo se van a modificar las funciones


main() y drawTurtle() para no alterar el funcionamiento de la funcin display() de la
aplicacin.
Se deben aadir los ficheros bitmap.c y bitmap.h al directorio del proyecto y
aadirlos al proyecto (Project/ Add to Project/ Files...).
Incluir en tecnunLogo el include de bitmap.h:
#include "bitmap.h"

Incluir en las declaraciones, los punteros para almacenar la informacin (header) de


la imagen y los bits que componen la imagen:
BITMAPINFO *TexInfo;
GLubyte
*TexBits;

Dentro de la funcin main(), se carga la imagen que se utilizar posteriormente y se


indica cmo deber aplicarse a la superficie:
TexBits = LoadDIBitmap("escudo.bmp", &TexInfo);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TexInfo->bmiHeader.biWidth,
TexInfo->bmiHeader.biHeight, 0, GL_BGR_EXT,
GL_UNSIGNED_BYTE, TexBits);
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(GL_TEXTURE_2D,
glTexParameteri(GL_TEXTURE_2D,

GL_TEXTURE_WRAP_S, GL_REPEAT);
GL_TEXTURE_WRAP_T, GL_REPEAT);
GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GL_TEXTURE_MIN_FILTER, GL_LINEAR);

En la funcin drawTurtle() comentar el bucle que genera el dibujo de la tortuga


(desde glBegin() hasta glEnd()) y sustituir por el cdigo que activa el mapeado de texturas
y dibuja un rectngulo, indicando la correspondencia entre las coordenadas de la textura y
los vrtices de dicho rectngulo:
glEnable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 0.0);
glVertex2f(-1.0, -1.0);
glTexCoord2f(1.0, 0.0);
glVertex2f(1.0, -1.0);
glTexCoord2f(1.0, 1.0);
glVertex2f(1.0, 1.0);
glTexCoord2f(0.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
glDisable(GL_TEXTURE_2D);

Para que se dibuje la tortuga ser necesario


activar una tortuga distinta de la 0, por ejemplo con el
comando st 1 . En la figura se aprecia el resultado.
10.3

Figura 1.
tecnunLogo con
Imagen

TRABAJO PROPUESTO

Aadir una textura al rastro que deja la tortuga al hacer un recorrido. El


rastro deber ser un polgono o una serie de polgonos para facilitar la
definicin de las coordenadas de textura.

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

tecnunLogo: un logo en tres dimensiones

72

BIBLIOGRAFA
OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 1.4, 4/E
Dave Shreiner, Mason Woo, Jackie Neide, Tom Davis
ISBN: 0-321-17348-1, Addison Wesley Professional, 2004, 816 pp
Computer Graphics with OpenGL, Third Edition
Donald Hearn, M. Pauline Baker
ISBN: 0-13-120238-3, Prentice Hall, 2004, 857 pp
OpenGL : SuperBible
Richard S. Wright, Jr. , Michael Sweet
ISBN: 1-57169-164-2, Waite Group Press, 1999, 696 pp
A 3D Case Study Using OpenGL
Fotis Chatzinikos
The Developers Gallery, 1999, 93 pp
The OpenGL Utiliy Toolkit (GLUT) Programming Interface
Mark J. Kilgard
Silicon Graphics, Inc, 1996, 62 pp

Copyright 2003 Nicols Serrano Brcena, Fernando Alonso Blzquez, Carlos Melara Ortiz. Todos los derechos reservados. Est prohibida
la reproduccin total o parcial con fines comerciales y por cualquier medio del contenido de estas pginas. Slo esta permitida su impresin y
utilizacin con fines personales.

También podría gustarte