Sunteți pe pagina 1din 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
VENTANA UN

TOROIDE

EN

LA

Figura 1

Ventana inicial

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 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


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

10

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, ...}; for (i=0; i < npoints; i++){ glBegin(GL_LINE_LOOP);

Bucle for:

Comparar la utilizacin de y
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

Tortuga con GL_LINE_LOOP

Figura 6

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 FORWARD RIGHT LEFT BACK UPPITCH DOWNPITCH EXIT HOME Abreviatura fd rt lt bk up down exit home Descripcin Avanza hacia adelante Gira a la derecha Gira a la izquierda Retrocede Gira hacia arriba Gira hacia abajo Sale del modo logo Posicionarse en el inicio Argumento Unidades de distancia Grados (0 360) Grados (0 360) Unidades de distancia Grados (0 360) Grados (0 360) -

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 LEFTROLL SCALEX SCALEY SCALEZ AbreviaDescripcin Argumento tura rr Rota hacia la derecha segn el eje Grados (0 360) de avance lr sx sy sz Rota hacia la izquierda segn el Grados (0 360) eje de avance Multiplica las coordenadas x por Factor de escala el factor de escala Multiplica las coordenadas y por Factor de escala el factor de escala 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 PushMatrix y PopMatrix

Pop

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


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++; }

22

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


addPointToTrace();

23

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.
2 4 3 0 1 5

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 up X up Y up Z

26

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. 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. 4.2.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

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 aspect = w/h

fovy near far

Figura 3.2. Volumen de visin en perspectiva especificado por gluPerspective(). 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 );

4.2.2

top left 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. far

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 F2 F3 Desactivar cualquier modo de movimiento de cmara Modo Examinar 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


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

30

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


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

31

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


#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 );

33

// 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


#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 // looks towards newCamera->camAtX newCamera->camAtY newCamera->camAtZ newCamera->camUpX newCamera->camUpY newCamera->camUpZ = positionX; = positionY; = positionZ; = 0.0f; = 0.0f; = 0.0f; = 0.0f; = 1.0f; = 0.0f;

34

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; ix, jx, kx, atX, upX, viewX, ierr = = = = = = = = = = iy, jy, ky, atY, upY, viewY, 0; iz; jz; kz; atZ; upZ; viewZ;

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

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


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

35

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; SetDependentParametersCamera( thisCamera ); } void SetCamera( camera *thisCamera, float viewX, float viewY, float viewZ, float atX, float atY, float atZ, float upX, float upY, float upZ ){ = viewX; = viewY; = viewZ; atX; atY; atZ; upX; upY; upZ;

// width/height

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

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


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 ); }

36

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


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

37

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

5.2.1

Parameter Name

(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

Default Value

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

Meaning

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 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.

Figura 1. Forma de representar la luz

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 F1 F8 F9 Accin Desactivar luces (en general, desactivar cualquier modo) Modo luces. Cada vez que se pulsa se pasa de una luz a otra. 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.

5.3.2

tecnunLogo: un logo en tres dimensiones

40

Movimiento del Ratn Adelante/Atrs Izquierda/Derecha Adelante/Atrs con botn izquierdo pulsado

Accin 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. Movimiento de la luz con la cual se est interactuando a lo largo de un paralelo con centro en el eje Y. 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 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

5.3.3

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


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

42

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


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

43

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


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

44

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


#ifndef LIGHT_H #define LIGHT_H #define AGA_DIRECTIONAL #define AGA_POSITIONAL #define AGA_SPOT 1 2 3

45

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


#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 intensity = 0.0f; thisLight->ambient[0] thisLight->ambient[1] thisLight->ambient[2] thisLight->ambient[3] intensity = 0.8f; thisLight->diffuse[0] thisLight->diffuse[1] thisLight->diffuse[2] thisLight->diffuse[3] intensity = 0.0f; thisLight->specular[0] thisLight->specular[1] thisLight->specular[2] thisLight->specular[3] thisLight->position[0] thisLight->position[1] thisLight->position[2] thisLight->position[3] AGA_DIRECTIONAL; -1; = FALSE; = TRUE; = FALSE; = TRUE; = = = = = = = = = = = = = = = = intensity; intensity; intensity; 1.0f; intensity; intensity; intensity; 1.0f; intensity; intensity; intensity; 1.0f; 1.0f; 1.0f; 1.0f; 1.0f; &vz ); vx; vy; vz; 0.0f;

46

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] thisLight->spotExponent thisLight->spotCutOff thisLight->a = 0.1f; thisLight->b = 0.0f;

// The light is "placed" at point // So light rays flow in the

-1.0f; &vy, &vz ); = vx; = vy; = vz; = 0.0f; // must be degrees

= 10.0f; = 30.0f;

// GL_QUADRATIC_ATTENUATION // GL_LINEAR_ATTENUATION

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; } 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 ); } // GL_CONSTANT_ATTENUATION

47

// 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


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;

48

// 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


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]; }

49

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


#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;

50

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


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

52

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. 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. 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 = 1 kc + kl d + k q d 2 6.1.2 6.1.1

donde d kc kl
kq

: distancia entre la luz y el vrtice : GL_CONSTANT_ATTENUATION : GL_LINEAR_ATTENUATION : GL_QUADRATIC_ATTENUATION

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

6.1.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

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 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. 6.2.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

55

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).

6.2.2

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

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 F8 F9 Accin Desactivar luces (en general, desactivar cualquier modo) Modo luces. Cada vez que se pulsa se pasa de una luz a otra:
Direccional Posicional Spotlight

6.2.3

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 Adelante/Atrs Accin 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. Movimiento de la luz con la cual se est interactuando a lo largo de un paralelo con centro en el eje Y. Movimiento de la luz a lo largo del vector que une la posicin de la luz con el centro de coordenadas de la escena.

Izquierda/Derecha

Adelante/Atrs con botn izquierdo pulsado

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 Adelante/Atrs

Accin Movimiento del extremo del vector de direccin del spotlight a lo largo de un meridiano con centro en la posicin de la luz. 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. Incremento/Decremento apertura del spotlight.. del ngulo de

Izquierda/Derecha

Adelante/Atrs con botn izquierdo pulsado

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


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

59

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


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

60

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). Representacin sin iluminacin (figura 3). Activar / desactivar el Z buffer. Establecer el color de fondo. Polgonos sin sombreado (figura 2).

Activar / desactivar el doble buffer. 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, 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(); GL_TEXTURE_WRAP_S, GL_REPEAT); GL_TEXTURE_WRAP_T, GL_REPEAT); GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_TEXTURE_MIN_FILTER, GL_LINEAR);

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


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; }

69

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 TRABAJO PROPUESTO

Figura 1. tecnunLogo con Imagen

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.

S-ar putea să vă placă și