OpenGL RenderizadoBásicoconC++
OpenGL RenderizadoBásicoconC++
OpenGL Renderizado Básico con C++
Primera Edición Diciembre 2011
Karina I. Batista A. Angel A. González P. P. Mayoli M.González Guadalupe del C. Pérez De La R. José Luis Pérez P érez P. P. José Carlos Rangel O. Rosmely R. Rodriguez R. Juan Antonio Santana G.
Universidad Tecnológica de Panamá Santiago, Veraguas 2011
Este Libro se elaboró como proyecto nal en la Asignatura Computación Gráca II, la cual fue impartida por la Profesora Milka de Gra -
cia, en el II Semestre 2011. Realizado por los estudiantes de Ingeniería de Sistemas y Computación de IV año del Centro Regional de Veraguas. Está dirigido especícamente a los estudiantes del curso de Computación Gráca II y
a cualquier persona interesada en entrar al mundo de la programación con OpenGL. Basado en el contenido de la Asignatura cuyo código es 8465, del plan de Estudio de la carrera Licenciatura en Ingeniería de Sistemas y Computación (2007). Sigue el esquema y la separación de los temas según el libro Computación Gráca: Manejo de Grácos con OpenGL, desarrollado
por el Dr. Euclides Samaniego González
A José Manuel Diaz “Zaid” (q.e.p.d), amigo y compañero.
Contenido Prefacio Introducción a Visual C++ 2010 con OpenGL 1.
Introducción a Visual C++ con OpenGL
xii 1 2
1.1 ¿Qué es OpenGL?
2
1.2 ¿Cómo funciona OpenGL?
2
1.3 Librerías relacionadas con OpenGL
3
1.4 Bibliotecas y Encabezados
3
1.5 Sintaxis de una orden OpenGL
4
1.6 Estudio de las partes de una orden OpenGL
4
1.7 Tipos de datos de una orden OpenGL
5
1.8 Estructura de un programa OpenGL
5
1.8.1 Manejo de ventanas.
6
1.8.2 Funciones de visualización.
6
1.8.3 Ejecución del programa.
7
1.8.4 Gestión de eventos.
7
1.8.5 Gestion de ventos en segundo plano.
7
1.8.6 Funciones de primitivas.
7
1.9 Microsoft Visual 2010 C++ y las Librerías Gracas de OpenGL
9
1.9.1 Instalación de las librerías Gracas de Open GL.
9
1.9.2 Pasos para iniciar un proyecto con Visual C++ y librerías de OpenGL
9
1.9.2.1 Nuevo Proyecto
9
1.9.2.2 Aplicación de consola
10
1.9.2.3 Selección de Proyecto Vacio
11
1.9.2.4 Añadir Archivo de código fuente C++
12
1.9.2.5 Compilación, vinculación y ejecución de proyectos
14
1.10 Recomendaciones para crear un proyecto con Visual C++ y OpenGL
14
1.11 Entorno de programación de OpenGL
15
1.11.1 Inclusión típica de encabezamiento inicial.
15
1.11.2 El cuerpo del programa de una aplicación en OpenGL
15
1.11.3 Modo de presentación de la Ventana OpenGL
16
vii
1.11.4 Creación de la ventana Open en pantalla
16
1.11.5 Establecer la devolución de llamada que dibuja el contenido de la ventana. 16 1.11.6 Congurando el estado a interpretación.
16
1.11.7 Bucle a la espera de eventos.
16
1.11.8 Llamadas de grácos OpenGL
17
1.11.9 Limpiando el búfer de color, borra todos los pixeles.
17
1.11.10
18
Limpiando la cola y los bufers de comando OpenGL
Referencias
18
Taller Nº 1
18
Taller Nº 2
19
Taller Nº 3
20
Ejercicio Nº 1
21
Conceptos Fundamentales de OpenGL
23
2.
24
Primitivas Geométricas Básicas 2.1 Sistemas De Coordenadas
24
2.2 Describiendo Puntos, Líneas Y Polígonos
26
2.2.1 Puntos
26
2.2.2 Líneas
26
2.2.3 Polígonos
27
2.2.4 Rectángulos
28
2.2.5 Curvas y supercies curvas
28
2.3 Especicando Vértices
29
2.4 Dibujando Primitivas En OpenGL
30
2.4.1 Restricciones sobre el uso de glBegin y glEnd
31
2.4.2 Utilizando glBegin, glEnd() y glVertex para dibujar primitivas
32
2.5 Gestión De Características De Estados OpenGL
34
2.6 Desplegando Puntos, Líneas Y Polígonos
35
2.6.1 Detalles de puntos
35
2.6.2 Detalles de líneas
35
2.6.3 Detalles de polígonos
37 40
Referencias
viii
Taller Nº 4
41
Taller Nº 5
44
Ejercicio Nº 2
47
Ejercicio Nº 3
47
OpenGL Básico en 3D
48
3.
49
OpenGL Básico en 3D 3.1 Menús desplegables
49
3.2 Creación de una animación sin parpadeo, eliminación de caras traseras
50
3.3 Denir, situar y colocar la cámara que usa OpenGL
52
3.4 La Proyección en OpenGL
54
3.5 Visibilidad: Ocultación de objetos (Z-Buffer)
57
3.6 Las Transformaciones en OpenGL
58
Referencias
61
Taller Nº 6
61
Taller Nº 7
65
Ejercicio Nº 4
66
Color, Materiales e Iluminación
68
4.
69
Color, Materiales e Iluminación 4.1 Especicación de un normal en OpenGL
69
4.2 Estableciendo el Modelo de Sombreado
70
4.3 Estableciendo las Propiedades del Material
72
4.4 Estableciendo el Modelo de Iluminación
74
4.4.1 Luz Ambiente
74
4.4.2 Luz Posicional
76
4.4.3 Luz Direccional
77
4.5 Gestión de un Foco de Luz
79
4.6 Gestión de la atenuación de la intensidad de la luz
80
Referencias
81
Taller Nº 8
81
Ejercicio Nº 5
84
Trazado del Mapa de Textura
86
ix
5.
Trazado del Mapa de Texturas
87
5.1 Texturas 2D para polígonos
87
5.2 Filtrado de Una Textura
93
5.3 Aplicación de texturas 2D sobre Primitivas GLUT
95
Referencias
105
Taller Nº 9
106
Taller Nº 10
108
Ejercicio Nº 6
111
Aspectos avanzados de OpenGL
112
6.
113
Aspectos Avanzados de OpenGL 6.1 Geometrías de las primitivas de los dibujos ecientes
113
6.2 Lista de Visualización
114
6.3 Especicación de eliminación de caras traseras
121
6.4 El efecto fusión en OpenGL
122
6.5 Uso de GlutIdleFunc y glutTimerFunc
124
6.5.1 Función GlutIdleFunc
124
6.5.2 Función GlutTimerFunc
125
6.6 Denición de varias áreas de dibujo.
125
6.7 Tratamiento de imagines en OpenGL: Guardar y recuperar imagines.
126
6.8 Especicación de los vectores de vértice en OpenGL.
131
6.9 Niebla
135
6.10 Cargar modelos .OBJ
140
Figura. Resultado de la ejecución
142
Referencias
143
Taller Nº 11
143
Taller Nº 12
146
Ejercicio Nº 7
147
OpenGL con otros Lenguajes
149
7.
150
OpenGL con otros Lenguajes
7.1 Implementación con C#
150
7.1.1 OpenTK
150
x
7.1.2 Comenzar un nuevo proyecto
150
7.1.3 Primera Aplicación con OpenTK
151
7.1.4 Windows Form y GLControl
158
7.2 Implementación con Java
164
7.2.1 Instalación de los complementos
165
7.2.2 Una aplicación JOGL
167 169
Referencias
xi
Prefacio
E
l mundo ha cambiado enormemente en las últimas décadas, estos cambios han sido propiciados en gran parte por un elemento común, la computadora, la cual desde su aparición ha tenido un gran desarrollo. Parte de este desarrollo es la infografía o grácos por computadora desde la aparición de inter faces que hacen más sencillo el trabajo con el equipo, hasta los actuales avances
en animación que van dirigidos al entretenimiento. En comparación con los inicios de la computación gráca donde el proceso de dibujar se basada en complicados
cálculos matemáticos y el ensayo y error, hasta la actualidad donde existen gran cantidad de programas para el diseño gráco se ha progresado mucho lo cual au gura un futuro prometedor en cuanto a esta área de la computación. Inmerso en este desarrollo se encuentra OpenGL el cual fue desarrollado en Silicon Graphics
Inc. a inicios de la década del 90. Esta es una herramienta que permite la creación de grácos en 2D y 3D, al igual que animaciones; creaciones las cuales pueden
interactuar con los usuarios a través de los diversos dispositivos de entrada. OpenGL Renderizado Básico en C++, incluye los conceptos básicos para aprender a programar grácos con OpenGL en C++, presenta un contenido car gado de ejemplos para aclarar lo más posible los conceptos presentados, así como también talleres y ejercicios para estimular la capacidad creativa de los estudiantes. Los contenidos del libro por capítulo se pueden resumir de la siguiente manera: En el capítulo 1 se presenta una descripción de que es OpenGL, deniendo los conceptos y reglas que rigen el lenguaje, como funciona, que elementos y li -
brerías se requieren y en que carpetas deben ser copiadas, para la construcción de una aplicación o programa en Visual C++ 2010 utilizando las librerías grácas de OpenGL. Además se mostraran los pasos para realizar la ejecución de un proyecto con Visual C++ 2010 utilizando OpenGL y los métodos para compilar y ejecutar
una aplicación. En el capítulo 2 se describen las primitivas geométricas en función a sus vér tices, a los cuales se les asocian coordenadas, que son las que denen los puntos de inicio y n de un segmento de línea o bordes de un polígono. En este capítulo explicaran como se dibujan primitivas mediante la especicación de un conjunto de vértices; y mostrar las funciones de OpenGL que permiten el dibujo de líneas apli -
xii
cando los patrones de líneas y los patrones de relleno para los polígonos. En el capítulo 3 mostraremos las diferentes funciones y métodos básicos que nos ofrece OpenGL para trabajar grácos en 3D, así como las distintas formas
de aplicar los mismos para obtener el resultado deseado en las diversas tareas a realizar que se nos presenten en el camino. En el capítulo 4, aprenderemos a implementar el uso de colores, materiales, sombras así como también la iluminación (llamase luces), que se le puede aplicar a los objetos creados para una mejor proyección de lo que se está realizan do. Describiremos las funciones adecuadas para dicho n, a la vez, detallando los cambios y la manera, en que se debe implementar dichas funciones para obtener
un buen resultado. En el capítulo 5 se presentan las funciones necesarias para aplicar textu -
ras a una primitiva (polígono, triangulo, etc.). Se muestran también los parámetros necesarios para la utilización de dichas funciones, y a la vez se pueden realizar algunos talleres en los que se puede practicar como se utilizan estas funciones en
aplicaciones de C++ con OpenGL. En el capítulo 6 se muestran conceptos avanzados de OpenGL como las listas de visualización, eliminacíon de caras traseras, niebla, denición de áreas de dibujo, entre otras. Estos conceptos combinados con los explicados en los capítu -
los anteriores enriquecen, los conocimientos sobre OpenGL, lo cual permite crear una gran variedad de aplicaciones diferentes. En el capítulo 7 se presenta una introducción al trabajo con OpenGL en otros lenguajes como lo es C#, explicando la manera de trabajar con este en el entorno
Visual Studio. También se aborda la implementación de OpenGL en Java con el entrono NetBeans.
xiii
<1> C a p í t u l o Introducción a Visual C++ 2010 con OpenGL OBJETIVOS: ♦ Conocer los conceptos fundamentales de
OpenGL para visualizar gráficos 3D en
una aplicación. ♦
♦
♦
♦
Enumerar las ventajas
de utilizar OPenGL al aislarnos del hardware disponible. Describir las librerías y el conjunto de co mandos utilizados para las aplicaciones con OpenGl. Conocer la estructura de un programa que utilice OpenGL. Presentar el código de una aplicación utiliozando OpenGL que permita observar la forma
DESCRIPCIÓN: En este capítulo se tratara sobre la introducción a OpenGL, como interface de pro gramación para crear gracos 3D. se de scribirá que es OpenGL, como funciona, que elementos requiere, sus librerías gracas:
“glut.dll”, “glut32.dll”, “glut32.lib”, “glut.lib”, “glut.h”. Además se presentaran los aspectos a considerar para la creación de un proyecto en OpenGL.
implementada
en la utilización de esta herramienta.
1
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.
Introducción a Visual C++ con OpenGL
1.1
¿Qué es OpenGL?
Se dene como una interface de programación de aplicación para crear grácos 3D. básicamente se trata de una librería de funciones que permiten visualizar grá cos 3D en una aplicación, además de que es una herramienta de programación con grácos portable, que ofrece una gran disponibilidad usando interfaces de pro gramación de aplicaciones para grácos 2D e imágenes, y gran potencia en el manejo de grácos 3D de manera fácil y rápida. Consta de unas 120 funciones distintas, que especican los obje tos y las op -
eraciones necesarias para producir aplicaciones interactivas en las que intervienen grácos en tres dimensiones. Esta diseñado de forma completamente independiente del hardware por lo que puede implementarse en plataformas muy diversas (PC, SGI, Digital, Sun,
etc…. El precio que hay que pagar en aras de esta portabilidad, es que OpenGL no incluye comandos para gestionar el sistema de ventanas, ni para capturar órdenes de los usuarios, ya sea por ratón o por teclado. En lugar de esto, debemos traba jar con la ayuda de cualquier sistema de ventanas que se utilice en la máquina en concreto en la que estemos trabajando. En nuestro caso utilizaremos el sistema de
ventanas de Windows.
1.2
¿Cómo funciona OpenGL?
Al trabajar con OpenGl se deben realizar una serie de pasos tales como llamadas
a los comandos de OpenGL que se necesitan para conseg uir cierto aspecto, apariencia o efecto; en vez de escribir la escena y como debe aparecer. Estos coman dos son utilizados para dibujar primitivas gracas en 3D(puntos, líneas, polígonos); transformación de primitiva, atención a eventos de teclado, raton y ventana; traza do de texturas; ltrado, denición de materiales, iluminación, sombreados; fusión; menus despegables; transpariencia; niebla, animación y otros muchos eventos y
opciones especiales. Cabe destacar que OpenGL funciona para muchas propiedades como una
máquina de estados. Es decir si a una propiedad se le asigna un valor determinado, todo lo que se haga a partir de ese momento se verá afectado por ese valor, hasta que este se modique o desactive de forma explícita. Por ejemplo, una de esas propiedades es el color actual, con el que se pin tan los objetos. De esta forma, si asignamos a la propiedad color actual por ejem plo el valor ROJO, todos los puntos, líneas y polígonos que se dibujen a continuación serán de color rojo, hasta que se modique este valor de forma explícita, mediante la función adecuada.
2
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL Las propiedades que funcionan de esta forma son:
♦
Color actual. Punto de vista.
♦
Transformaciones de proyección.
♦
Estilo de líneas y polígonos.
♦
Modos de dibujar polígonos.
♦
Convenciones de empaquetado de bits.
♦
Posición y características de las fuentes de iluminación.
♦
Propiedades de los materiales de los objetos.
♦
1.3
Librerías relacionadas con OpenGL
Las librerías relacionadas con OpenGl se han desarrollado con el n de simplicar
las tareas de programación. Se divide en tres partes funcionales: ♦
La librería OpenGL, que proporciona todo lo necesario para acceder a las funciones de dibujado de OpenGL.
♦
La librería GLU (OpenGL Utility Librar y), una librería de utilidades que proporciona acceso rápido a algunas de las funciones más comunes de OpenGL., a través de la ejecución de comandos de más bajo nivel, pertenecientes a la librería OpenGL propiamente
♦
dicha. GLX (OpenGL Extension to the X Window System) proporciona un acceso a OpenGL para poder interactuar con un sistema de ventanas X Window, y está incluido en la propia implementación de OpenGL (su equivalente en Windows es la librería WGL, externa a la implementación de OpenG L).
Además de estas tres librerías, la librería GLUT (OpenGL Utility Toolkit) pro porciona una interfaz independiente de plataforma para crear aplicaciones de ven -
tanas totalmente portables.
1.4
Bibliotecas y Encabezados
OpenGL es una biblioteca de programación que posee muchas implantaciones. La compatibilidad que ofrece Microsoft Windows para OpenGL es como un interpreta dor de software.
♦
opengl32.dll. Es una librería del software de Microsoft, de de -
3
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
sarrollo, biblioteca de vínculo dínámíco, en la que se encuentra la implantación del software de Microsoft, y está localizada en el directorio del sistema Windows (C:\Windows\System32). ♦
gl.h: Es el archivo encabezado que contiene todos los prototipos de funciones, tipos y superficies.
♦
glut.h. Es el archivo de encabezado que contiene todas las fun -
ciones de la biblioteca de utilidades. Estos 2 últimos archivos se encuentran localizados en un directorio especial en la ruta de acceso include (C:\Program Files\Microsoft Visual Studio 10.0\VC\
include).
1.5
Sintaxis de una orden OpenGL
Una orden OpenGL maneja un conjunto de prejos y sujos a identicar de datos o el número de parámetros con el que trabaja, entre otros. La sintaxis de una orden OpenGl es:
gl [234] [dsi…] [v] (args…) ♦
gl. El identificar de cada orden de OpenGL inicia siempre con el prefijo gl.
♦
: Es el comando raíz de OpenGL.
♦
Los sufijos definen el numero de parámetro de la orden(2,3 o 4) y el tipo de dato(doublé, short, int, float, …)
1.6
Estudio de las partes de una orden OpenGL
Las partes de la función OpenGL indican de que la biblioteca es la función, la cantidad y tipos de argumentos que acepta la función. Cada una de las funciones
OpenGL tienen una raíz que representa el comando OpenGL correspondiente. Ejemplo
glVertex2i (…) ♦
gl: función de la librería OpenGLglut
♦
vertex: comando raíz
♦
2: cantidad de argumentos que se envían.
♦
I: tipo de argumentos enteros.
glColor3f (…) ♦
gl: Prefijo que representa a la biblioteca GL.
4
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
♦
Color: comando básico que tiene la raíz color.
♦
3: sufijo que indica el numero de argumentos.
♦
F: sufijo que indica tipo de argumentos flotante.
1.7
Tipos de datos de una orden OpenGL
OpenGl dene sus propios tipos de datos que facilitan la portabilidad del código OpneGl de una plataforma a otra. A continuación, mostraremos el signicado de los sujos utilizados para es pecicar los distintos tipos: Sujo literal
Tipo de dato
Tipo de datos OpenGL
Denición como
en C
tipo C
b
Entero de 8 bits
signed char
s
Entero de 16 bits
short
GLshort
i
Entero de 32 bits
int o long
GLint, GLsizei
oat
GLoat, GLclampf
double
GLdouble, GLclampd
unsigned char
GLubyte, GLboolean
unsigned short
GLushort
unsigned int
GLuint, GLenum,
f
d ub us ui
Coma otante 32
bits
Coma otante 64
bits Entero de 8 bits sin signo Entero de 16 bits sin signo Entero de 32 bits sin signo
GLbyte
GLbiteld
Tabla Sujos de instrucciones OpenGL
1.8
Estructura de un programa OpenGL
OpenGl es una librería graca que permite el uso de más de doscientas órdenes
para la generación de aplicaciones interactivas. Las principales acciones que se pueden realizar mediante órdenes OpenGL incluyen las especicaciones de los objetos y las operaciones necesarias para producir aplicaciones interactivas en 3D. La librería OpenGL está formada por seis grupos de funciones: manejo de ventanas, funciones de visualización, ejecución del programa, gestión de eventos, gestión de eventos en segundo plano y funciones primitivas.
5
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.8.1 Manejo de ventanas. Este grupo de funciones permiten la inicialización del sistema para que abra una ventana graca para dibujar. Forman parte de estas funciones: ♦
glutInit(int *argc, char **argv); Inicializa las utilidades de OpenGL. Esta función es la que inicializa la GLUT, y negocia con
el sistema de ventana para abrir una. Además sus argumentos son los estándares para pasar información sobre los comandos de
línea. ♦
glutInitDisplayMode(unsigned int mode); Selecciona el modo pantalla. Define el modo en el que debe dibujar la ventana. Es decir, especifica el modo de visualización. Los parámetros se de finen como flags o mascaras de bits.
♦
glutInitWindowPosicion(int x, int y); Posiciona la ventana en la pantalla. Especifica la posición de la ventana. Posición x e y de
♦
la esquina superior izquierda de la nueva ventana con respecto al escritorio que se trate. glutInitWindowSize(int width, int size); Selecciona el tamaño de la ventana. Especica el ancho y alto de la nueva ventana.
♦
glutCreateWindow(char *cadena); Abre la ventana. Esta función es
la que crea una ventana de visualización habilitada para OpenGL y el parámetro es el nombre o titulo de la misma, es decir, la función
actúa poniendo el titulo indicado en la barra superior de la ventana.
1.8.2 Funciones de visualización. Dene la función que se llamara para visualizar la escena, y la que permite forzar
esta llamada. Verbigracia, cuando se produce un cambio en la escena. ♦
glutDisplayFunc(void (*func)(void)); Especifica la función que dibuja la escena. Esta función establece la función de devolución
de llamada de la presentación para la venta actual. ♦
glutPostRedisplay(void); Actualiza la ventana actual. Esta función informa a la GLUT que la ventana actual necesita actualizarse, es decir, refresca el dibujo de la escena.
6
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.8.3 Ejecución del programa. La función de este grupo comienza la ejecución del programa, visualiza todas las
ventanas creadas, permite el envió de órdenes y gestiona los eventos que se generan. ♦
glutMainLoop(); Desencadena la ejecución del programa, inicia el proceso de bucle pr incipal del GLUT. La función sede el control del flujo del programa a la GLUT.
1.8.4 Gestión de eventos. El grupo de funciones de la gestión de eventos especican las rutinas que se eje -
cutan cuando se produce un evento determinado. ♦
glutReshapeFunc (void (*func(int anc, int alt))); Gestion de
evento de redimensionamiento de la ventana. ♦
glutKeyboardFunc(void(*func (unsigned char tecla, int x, int y))); Gestion de eventos del teclado. Funciona cuando se pulsa
una tecla. ♦
glutMouseFunc(void (*func (int botón, int estado, int x, int y))); Gestión de eventos del raton. Funciona cuando se pulsa un
botón del raton. ♦
glutMotionFunc( void(*func (int x, int y))); Gestion de eventos
deraton. Funciona cuando se mueve el raton con un botón pulsado.
1.8.5 Gestion de ventos en segundo plano. La función de la gestión de eventos en segundo plano especica la rutina que se ejecuta cuando no hay otros eventos pendientes, se utiliza comúnmente para reali -
zar animaciones. ♦
glutldleFunc(void( *func(void));
1.8.6 Funciones de primitivas. Este grupo perimite visualizar las primitivas de objetos prdenidos de dibujos mas completjas que las que incluyen OpenGL.
♦
glutWireCone(base, heigth, height, slices, stacks)
♦
glutWireCube(size), glutSolidCube(size)
♦
glutWireDodecahedron(void), glutSolidDodecahedron(void)
7
stacks),
glutSolidCone(base,
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
♦
glutWirecosahedron(void), glutSolidcosahedron(void)
♦
glutWireOctahedron(void), glutSolidOctahedron(void)
♦
glutWireSphere(radius, slices, stacks), glutSolidSphere(radius, slices, stacks)
♦
glutWireTeapot(void), glutSolidTeapot(void)
♦
glutWireTetrahedron(void), glutSolidTetrahedron(void)
Cono
Cubo
Dodecaedro
Octaedro
8
Icosaedro
Esfera
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
Tetraedro
Torus
Tetera
1.9
Microsoft Visual 2010 C++ y las Librerías Gracas de OpenGL
En esta parte se explicara cómo crear un proyecto utilizando OpenGL y GLUT en Visual C++.
1.9.1 Instalación de las librerías Gracas de Open GL. Para poder trabajar con OpenGL. Se deben instalar los siguientes archivos:
Archivos Direccion de las carpetas glut.dll glut32.dll C:\Windows\System32 glut32.lib glut.lib C:\Program Files\Microsoft Visual Studio 10.0\VC\lib C:\Program Files\Microsoft Visual Studio 10.0\VC\include glut.h Estos archivos se pueden obtener de la siguiente dirección http://www.xmission. com/~nate/glut/glut-3.7.6-bin.zip.
1.9.2 Pasos para iniciar un proyecto con Visual C++ y librerías de OpenGL Los pasos a seguir son los siguientes:
1.9.2.1 Nuevo Proyecto Para crear un nuevo proyecto del tipo Aplicación de Consola Win32 se debe s eleccionar Archivo → Nuevo → Proyecto , como se indica en la gura 1.
9
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
Figura 1. Nuevo Proyecto 1.9.2.2 Aplicación de consola Estando la ventana Nuevo Proyecto activa, seleccionar la opcion Aplicación de Consola Win32. Indique el nombre del nuevo proyecto y el lugar donde se desea guardar.
Figura 2. Aplicación de Consola 10
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.9.2.3 Selección de Proyecto Vacio Al seleccionar aceptar en la ventana de Nuevo Proyecto (Figura 2) aparecera la ventana del Asistente para Aplicaciones Win32 (Figura 3), en este seleccionamos siguiente, con lo cual aparecera las opciones de conguración de la aplicación del
asistente(Figura 4), en esta seleccionamos proyecto vacio.
Figura 3. Asistente para Aplicaciones Win32
11
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
Figura 4 Conguración de la Aplicación
Recuerde que a partir de ahora, estamos trabajando con los espacios de trabajo (Workspoce), por lo tanto para seguir trabajando debemos abrir siempre el espacio de trabajo.
1.9.2.4
Añadir Archivo de código fuente C++
Para añadir un archivo de código fuente C++ se debe seleccionar Proyecto→Agregar
Nuevo Elemento como se indica en la Figura 5.
12
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
Figura 5. Añadir Nuevo Elemento Luego aparecera la ventana de Agregar nuevo elemento (Figura 6), donde seleccionamos Archivo C++ (.cpp) e indicamos el nombre para nuestro archivo.
Figura 6. Ventana de Agregar nuevo elemento
13
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
El archivo que agreguemos se ubicara bajo la carpeta Archivos de código fuente,
en el explorador de soluciones de Visual C++ 2010 (Figura 7).
Figura 7. Ubicación del elemento agregado 1.9.2.5
Compilación, vinculación y ejecución de proyectos
Para compilar podemos utilizar cualquiera de estos métodos:
Compilar (Compile) Generar Iniciar sin Depurar Iniciar Depuración
Ctrl + F7 F7 Ctrl + F5 F5
1.10 Recomendaciones para crear un proyecto con Visual C++ y OpenGL Es importante tomar en cuenta los siguientes puntos: ♦ ♦ ♦
Ahorro de espacio en la unidad de disco. Ahorro de tiempo al evitar tener que crear un proyecto nuevo con cada practica. Solo serán por tanto necesario tener almacenado un proyecto prototipo y los distintos ficheros correspondientes a los códigos fuentes de cada practica.
14
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.11 Entorno de programación de OpenGL Para ir familiarizándose un poco con la aplicación, tenemos este código ejemplo: #include #include #include
Void Mostrar(void) {
glClear(GL_COLOR_BUFFER_BIT) glfrush(); }
Void Iniciar(void) {
glClearColor(0.0, 1.0, 0.0, 1.0) int main(int argc, char **argv) {
glutInitDisplayMode(GLUT_SINGLE | GLUT_ glutCreateWindows(“Mi primer programa”); glutDisplayFunc(Mostrar); Iniciar(); glutMainLoop(); return 0; }
1.11.1 Inclusión típica de encabezamiento inicial. #include #include #include
1.11.2 El cuerpo del programa de una aplicación en OpenGL Int main (int argc, char **argv) { }
15
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.11.3 Modo de presentación de la Ventana OpenGL glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //Selecciona el modo pantalla ♦ Sintaxis: void glutInitDisplayMode (unsigned int mode)
♦
Propósito: Inicializa el modo de presentación de la ventana OpenGL
de la biblioteca GLUT. ♦
Parámetros: Mode: indica una marcara o combinación de mascar -
as de bits que describen las c aracterísticas de la ventana.
1.11.4 Creación de la ventana Open en pantalla glutCreateWindows(“Mi primer Programa”)
// Abre la ventana
♦
Sintaxis: int glutCreateWindows(Char *name)
♦
Propósito: crea una ventana GLUT de alto nivel habilitada para
OpenGL, que ers considerada ventana actual. ♦
Parámetros: Name: titulo o nombre de la ventana.
1.11.5 Establecer la devolución de llamada que dibuja el contenido de la ventana. glutDisplayFunc(mostrar)
//Registra la función redibujar.
♦
Sintaxis: void glutDisplayFunc(void(*func)(void));
♦
Propósito: indica a GLUT que debe llamar siempre que se tenga que dibujar el contenido de la ventana.
♦
Parámetros. Func: nombre de la función que ejecutaba la inter -
pretación.
1.11.6 Congurando el estado a interpretación. La línea de código Iniciar (); es la función que establece el contexto a seguir y que realiza cualquier iniciación de OpenGL que debería ejecutarse antes de la
interpretación.
1.11.7 Bucle a la espera de eventos. glutMainLoop(); ♦
Sintaxis: void glutMainLoop(void)
♦
Propósito: esta función inicia el proceso de evento principal de GLUT es el lugar donde se procesan todos los mensajes.
16
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
1.11.8 Llamadas de grácos OpenGL glClearColor(0.0, 0.0, 0.0, 1.0); ♦
Sintaxis: void glClearColor(GLclampf Glclampf blue, GLclampf alpha)
♦
Propósito: establece los valores de relleno que se utilizan cuando se borren los buferes de ojo, verde, azul y transparencia.
♦
Parámetros:
red,
GLclampf
green,
GLclampf red , componente rojo del valor de relleno GLclampf green , componente verde del valor de relleno Glclampf blue, componente azul del valor de relleno GLclampf alpha , componente transparencia del valor de relleno
COLOR COMPUESTO Amarillo Azul Blanco Cían Gris claro Gris oscuro Magenta Marrón Naranja calabaza
Negro Púrpura Rojo
Rosa Pastel Verde
COMPONENTE ROJO VERDE 1 0 0 0 1 1 0 1 0.75 0.75 0.25 0.25 1 0 0.6 0.4 0.98 0.625 0 0 0.6 0.4 1 0 0.98 0.04 0 1
AZUL
0 1 1 1 0.75 0.25 1 0.12 0.12 0 0.7 0 0.7 0
Tabla Algunos colores comunes y sus valores de componente 1.11.9 Limpiando el búfer de color, borra todos los pixeles. glClear(GL_COLOR_BUFFER_BIT);
La línea de código GLUT establece que OpenGL, para usar el color verde de borrado es la orden glClear. 17
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
La función borra un bufer o una combinación determinada, la sintaxis de la función es: void glClear(Glbitfdield mask) . Limpia los buffers especícos asignándoles los valores actuales. El argumento mask puede tener los siguientes valores:
Buffer
De color De fondo
De acumulación De patron
Nombre GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT GL_ACCUM_BUFFER_BIT GL_STENCIL_BUFFER_BIT
1.11.10
Limpiando la cola y los bufers de comando OpenGL La línea de código: glFlush(); es la encargada de realizar la limpieza y el borrado de los búferes de comando OpenGL. Este comando hace que se ejecute cualquier comando que esté esperando a ejecutarse. Por lo general, los comandos OpenGL se aplican en la cola y se eje -
cutan en secuencias de comando para optimizas el rendimiento. La función glFlush(); indica a OpenGL que debe proceder con las instrucciones de dibujo suministrada hasta el momento antes de esperar cualquier otro comando de dibujo.
Referencias Agenjo, J. (30 de Agosto de 2009). SegmentationFault. Recuperado el 25 de Agosto de 2011, de OpenGL y GLUT en Visual C++: http://www.segmentationfault. es/2009/08/opengl-glut-visual-cpp/ Samaniego González, E. Computación Gráca: Manejo de Grácos con OpenGL.
Panamá.
Taller Nº 1 Indicaciones: Para inicializar el sistema, crear la ventana de dibujo y comenzar el bucle de gestión
de eventos se debe utilizar código que se muestra a continuación. Int main(int numParametros; char **ListaParametros) {
/*Inicializacion y creación de venta */ //Inicializa toolkit glutInit(&numParametros, ListaParametros); //Selecciona el modo pantalla glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
18
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
//Selecciona el tamaño de la ventana glutInitWindowSize(anchoVentana, altoVentana); //Posiciona la ventana en la pantalla glutInitWindowPosition(posicionVentanax, posicionVentanay); //Abre la ventana glutCreateWindow(ListaParametros[0]); glutDisplayFunc(dibuja); //Registra la función de redibuja //Bucle a la espera de eventos. glutMainLoop();
}
La función Dibuja realiza el dibujo de la escena.
Taller Nº 2 Ahora se presenta un programa que genera una ventana de trabajo y dibuje primi -
tivas básicas sobre la misma. Este código trata acerca de la creación de una ventana usando la librería GLUT y Visual C++. Escriba el siguiente código y ejecute el programa: #include #include #include
Void Mostrar(void) {
//Limpia la pantalla. Borra los pixeles glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); //Establece el color a dibujar glBegin(GL_POLYGON); //Vértices glVertex3f(0.25, 0.25, 0.0); glVerter3f(0.75, 0.25, 0.0); glVerter3f(0.75, 0.75, 0.0); glVerter3f(0.25, 0.75, 0.0); glEnd(); }
Void iniciar(void)
//Mi inicio
{
//Selecciona el color de limpieza del fondo de la ventana glClearColor(0.0, 0.0, 0.0, 0.0);
19
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
//Inicialización de los valores de visualización. glMatrizMode(GL_PROJECTION); glLoadIdentify(); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 10.0); }
Int main(int argc, char **argv) {
glutInit(&argc, argv); //Inicializa toolkit //Selecciona el modo pantalla glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500, 500); //Selecciona el tamaño de la ventana. //Proporciona la ventana en la pantalla. glutInitWindowPosition(100, 100); //Abre la ventana glutInitCreateWindow(“Ejemplo Guia – Crear Ventana”); iniciar(); glutDisplayFunc(Mostrar); //Registra la función de redibujar. glutMainLoop(); //Bucle a la espera de eventos. return 0; }
Taller Nº 3 Aplicación de los comandos básicos de OpenGL. 1. Siga los pasos para iniciar un proyecto con Visual C++ y utilizando las librerías de OpenGL y cree un proyecto denominado “ Prueba1”. 2. Utilizando el código suministrado en la sección de reforzamiento. Re alizar los siguientes cambios, compilar y ejecutar mediante Build <
execute e indique que sucede. Cambiar el argumento de la orden, glColor3f, por: ♦
(0.0, 0.0, 1.0); __________ ____________ ___________ ___
♦
(0.0, 1.0, 0.0); __________ ____________ ___________ ___
♦
(0.0, 1.0, 1.0); ___________ ___________ ___________ ___
♦
(1.0, 0.0, 0.0); ___________ ___________ ___________ ___
♦
(1.0, 0.0, 1.0); ___________ ___________ ____________ __
♦
(1.0, 1.0, 0.0); ___________ ___________ ____________ __
20
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
Cambiar el argumentos de la orden, glutCreateWindow, por: ♦
Mi primera Ventana; ___________ ___________ __________
♦
Programa Prueba 1; ___________ ____________ ________
Cambiar el argumento de la orden, glutInitWindowSize, por: ♦
(800, 800); ______________________________________
♦
(400, 800); ______________________________________
♦
(400, 100); ______________________________________
Ejercicio Nº 1 Comandos básicos para escribir un programa con OpenGL. 1. ¿Cuál es el funcionamiento de la orden glutMainLoop(void)? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ ¿Cuál es la orden que indica al sistema que rutina se debe ejecutar? 2. _________________________________________________________________ _________________________________________________________________ _________________________________________________________________
3.
Mencione la orden de OpenGL a la que le pasa como parámetro la rutina que se ejecuta cada vez que sea necesario redibujar la escena.
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 4. ¿Qué rol juega la orden glutPostRedisplay(void)? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 21
Capítulo 1 - Introducción a Visual C++ 2010 con OpenGL
5.
¿Cuáles son los pasos para iniciar un proyecto con Visual C++ y las librerías OpenGL? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 6.
¿Cuáles son las principales acciones que se pueden realizar mediante órdenes OpenGL? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ ________________________________________________________________ 7.
¿Qué elementos están presentes en la estructura de un programa OpenGL? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ ______________________________________________________________ 8. ¿Cuáles son los grupos que están presentes en un programa OpenGL? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _______________________________________________________________
22
<2> C a p í t u l o Conceptos Fundamentales de OpenGL OBJETIVOS: ♦
Definir el área de tra bajo de en OpenGL. Describir las fun -
ciones básicas que hacen el llamado a las utilidades del OpenGL para abrir una ventana gráfica para dibujar. ♦
Conocer las herramientas de OpenGL que permiten el dibujo de
primitivas, así como también mostrar las funciones de OpenGL
que
el dibujo de líneas apli cando los patrones de líneas y rellenado de polígonos. ♦
permiten
DESCRIPCIÓN: En este capítulo se dará a conocer el área de trabajo en OpenGL. Donde se hará una descripción de funciones básicas que son empleadas en Microsoft C++ para hacer el
llamado a las utilidades del OpenGL para abrir una ventana gráca para dibujar.
Se
conocerán las herramientas de OpenGL que permiten el dibujo de primitivas básicas, el dibujo de líneas aplicando patrones de líneas, el dibujo de polígonos, rectángulos y el rel -
leno de polígonos.
Definir la sintaxis de
las instrucciones que cambian los valores por defecto del grosor
de los puntos y líneas que se dibujan en
OpenGL.
23
Capítulo 2 - Conceptos Fundamentales de OpenGL
2.
Primitivas Geométricas Básicas
En esta sección se explicara cómo se describen las primitivas en OpenGL. Todas las primitivas geométricas son descritas en función a sus vértices, a los cuales se le asocian coordenadas que son las que denen los puntos de inicio y terminación
de un segmento de línea o bordes de un polígono.
2.1
Sistemas De Coordenadas
Para comenzar a utilizar OpenGL hay que estar claro con el funcionamiento de las diversas funciones que vamos a utilizar muy a menudo.
Primero es necesario seleccionar un sistema de coordenadas cartesianas adecuado, denominado sistema de coordenadas de referencia del mundo, que puede ser bidimensional o tridimensional. Después se describen los objetos de la imagen proporcionando sus especicaciones geométricas en términos de la pos -
ición dentro de las coordenadas del mundo. Fragmento de código necesario para establecer el sistema de coordenadas del mundo:
glViewport(0, 0, 50.0, 50.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, 50.0, 0.0, 50.0);
Figura 1: sistema de coordenada establecido glViewport()
Establece el puerto o punto de vista. 24
Capítulo 2 - Conceptos Fundamentales de OpenGL
glMatrixMode()
Es el modo matriz donde decidimos que tipo de matriz vamos a modicar ya sea la matriz de proyección (GL_PROJECTION) o la matriz de visualización/modelado (GL_ MODELVIEW).
glLoadIdentity()
Función para cargar la matriz identidad como matriz activa, esta función trabaja en conjunto con glMatrixMode().
gluOrtho()
Este es el modo de proyección donde podemos especicar como va a afectar la posición de un objeto a su visualización. Tenemos dos maneras de visualizar el es pacio: con una proyección ortográca, o con una proyección perspectiva: ♦
La proyección ortográfica: La proyección ortográfica nos per mite visualizar todo aquello que se encuentre dentro de un cubo, delimitado por los parámetros de la función glOrto(). A la hora de visualizar, la distancia al observador solo se tiene en cuenta para determinar si el objeto está dentro o fuera del cubo.
Figura 2: Proyección Ortográca
♦
La proyección perspectiva: La proyección perspectiva delimita un volumen de visualización dado por un ángulo de cámara, y una relación alto/ancho. La distancia al observador determinará el
25
Capítulo 2 - Conceptos Fundamentales de OpenGL
tamaño con el que un objeto se visualiza.
Figura 3: Proyección perspectiva
2.2
Describiendo Puntos, Líneas Y Polígonos
2.2.1 Puntos Un punto está representado por un numero punto otante que es llamado vértice.
En OpenGL todos los cálculos internos son hechos como si los vértices estuvieran en tres dimensiones, y cuando el usuario especica las coordenadas del punto, solo lo hace trabajando en dos dimensiones, con solo las coordenadas x, y. y la
coordenada z es igualada a cero por OpenGL.
f
Figura 4: Serie de puntos. 2.2.2 Líneas En OpenGL, el término de línea se reere a un segmento de línea, permitiendo que haya más facilidad cuando se quiere especicar una serie de segmentos de líneas
26
Capítulo 2 - Conceptos Fundamentales de OpenGL
conectadas, o un plano cerrado, ver Figura 5. Pero aunque las líneas conforman
las series conectadas, estas se consideran como un segmento de líneas independientes, y especicadas en términos de sus vértices.
Figura 5: Serie conectada de segmentos de línea 2.2.3 Polígonos Los polígonos son áreas cerradas formadas solo por segmentos de líneas entrela zadas. Donde los segmentos de líneas están especicados por los vértices de sus puntos nales. Los polígonos típicamente están dibujados con los pixeles los cuales rellanan su interior, pero también se puede dibujar solo los bordes o poner
los solo los puntos del polígono. En general los polígonos pueden ser complicados, así que OpenGL impone algunas restricciones de cómo debe estar conformado una primitiva de polígono. ♦ ♦
Primero, los bordes de los polígonos en OpenGL no pueden interceptarse entre sí. Segundo, los polígonos de OpenGL deben de ser convexos, con esto nos referimos que no puede tener aberturas.
♦
Tercero, Todos los polígonos deben ser planares. Vea la gura 6 para algunos ejemplos de polígonos válidos e inválidos.
OpenGL, de cualquier modo no restringe el número de segmentos de líneas usadas para crear el límite del polígono convexo. Fíjese que los polígonos con huecos no
pueden ser válidos.
27
Capítulo 2 - Conceptos Fundamentales de OpenGL
Figura 6: Poligonos válidos e inválidos La razón por la que OpenGL tiene restricciones sobre los polígonos es porque sencillamente provee rapidez al momento del renderizado, puesto que un polígono sencillo puede ser renderizado rápidamente. Pero los difíciles son compli cados de detectar rápidamente, y para el máximo rendimiento OpenGL asume que los polígonos son simples. 2.2.4 Rectángulos Desde que los rectángulos son comunes en la aplicaciones grácas, OpenGL provee la función para dibujar rectángulo plano, glRect*(). Pero puedes dibujar
un rectángulo como un polígono, como se describirá más adelante, pero por su particular implementación OpenGL, con la función glRect*() optimiza el dibujado
de los rectángulos.
Figura 7: Rectángulo dibujado con la funcion glRect*() 2.2.5 Curvas y supercies curvas Cualquier línea o supercie circular puede ser el aproximado de cualquier grado
de exactitud arbitrario, por cortos segmentos de líneas o pe queñas regiones poligonales. De esta manera subdividiendo la líneas y supercies curvas sucientemente
y entonces aproximándolos con los segmentos de línea recta o polígonos planos se crean las curvas ver gura 8.
28
Capítulo 2 - Conceptos Fundamentales de OpenGL
Figura 8: Segmentos de lineas conectados para formar curvas
2.3
Especicando Vértices
En OpenGL, cada objeto geométrico es descrito como un conjunto de vértices orde nados. Para esto se utiliza la función glVertex*() donde se especica los vértices del objeto a dibujar.
void glVertex[234]{sifd}(TIPO coords); void glVertex[234]{sifd}v(const TIPO* coords); ♦
[2, 3, 4]: sufijos que especifican el número de parámetros de la
orden. ♦
[s, i, d, f]: especifica el tipo de dato: short, int , double, float.
♦
[v]: matriz de valores que contienen los dos, tres o cuatros valores necesarios para especificar el vértice.
Ejemplo: Segmento de código utilizando glVertex*() glVertex2s(4, 5); glVertex3d(0.0, 0.0, 3.1416); glVertex4f(2.3, 1.0, -2.2, 2.0); GLdouble dvect[3] = {5.0, 9.0, 1992.0}; glVertex3dv(dvect); Se emplea la función glVertex*() para especicar coordenadas para las posiciones de los puntos. De esta forma, se utiliza una misma función para los pun tos, las líneas y los polígonos; en la mayoría de los casos, se emplean recubrimien tos poligonales para describir los objetos de una escena.
29
Capítulo 2 - Conceptos Fundamentales de OpenGL
2.4
Dibujando Primitivas En OpenGL
Después de haber visto como se especican los vértices con la función glVertex*(), se necesita conocer como se le dice a OpenGL que cree un conjunto de
puntos, una línea, o un polígono a partir de esos vértices. Para hacer esto, usted tiene que colocar cada conjunto de vértices entre la función glBegin() y al función glEnd().
El argumento de glBegin() determina qué clase de primitiva se construirá con los vértices.
geométrica
void glBegin(GLenum modo);
Señala el comienzo de una lista de vértices que se utilizaran para denir la
primitiva. El tipo de primitiva se indica en modo que pueden ser cualquier valor de la tabla 1. void glEnd(void);
Señala el n de una lista de vértices.
TIPO GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN GL_QUADS GL_QUAD_STRIP GL_POLYGON
DESCRIPCIÓN Crea puntos individuales. Crea segmentos de línea individuales, para cada par de vértices. Crea una serie de segmentos de líneas conectados. Crea segmentos de línea conectados y cerrados. Crea un triángulo donde cada tres vértices se interpreta como un nuevo triangulo. Entrelazado de triángulos. Enlaza un abanico de triángulos. Cada cuatro vértices se interpreta como un cuadrado. Entrelazado de cuadrados. Crea un polígono convexo.
Tabla 1: Tipos de primitivas.
30
Capítulo 2 - Conceptos Fundamentales de OpenGL
Ejemplo: fragmento de código donde se utilizamos glBegin() y glEnd(). glBegin(GL_POINTS); glColor3f(0.0, 1.0, glColor3f(1.0, 0.0, glVertex(...); glColor3f(1.0, 1.0, glColor3f(0.0, 0.0, glVertex(...); glVertex(...); glEnd()
0.0); 0.0); 0.0); 1.0);
2.4.1 Restricciones sobre el uso de glBegin y glEnd La información más importante de los vértices son sus coordenadas, que son de nidas con la función de glVertex*(). Pero además se puede añadir información adicional para cada vértice que sea especicado, como color, un vector normal,
coordenadas de textura, o cualquier combinación de estas, usando comandos especiales. Los comandos validos entre la función glBegin y glEnd, son los que aparecen en la tabla 2:
Tabla.2: lista de comandos válidos entre glBegin() y glEnd(). COMANDO
OBJETIVO DEL COMANDO
glVertex*()
Conjunto de las coordenadas utilizadas
glColor*() glIndex*() glSecondaryColor*() glNormal*() glMaterial*() glFogCoord*() glTexCoord*() glMultiTexCoord*() glVertexAttrib*() glEdgeFlag*()
para los vértices. Establece un color RBGA. Establece el índice de color. Establece un color secundario, para el texturizado de la aplicación. Establece las coordenadas de un vector normal. Establece las propiedades de material. Establece coordenadas para el modo niebla. Establece las coordenadas de textura. Establece las coordenadas de textura para el multi-texturizado. Establece un atributo genérico para el vértice. Para el control de dibujo de bordes.
31
Capítulo 2 - Conceptos Fundamentales de OpenGL
Extrae vértices de un arreglo de datos. glArrayElement() glEvalCoord*(), glEvalPoint*() Genera coordenadas. Ejecuta un despliegue de lista(s). glCallList(), glCallLists()
Tabla 2: Continuacion de lista de comandos validos entre glBegin() y glEnd().
2.4.2 Utilizando glBegin, glEnd() y glVertex para dibujar primitivas En los siguentes fragmentos de códigos, se muestra como dibujar primitivas utili zando las funciones glBegin() y glEnd. Para esto se utilizada la funcion glVertex() que es para denir los vértices de las primitivas. El tipo de primitiva que se dibujará
va a depender del parámetro asignado a glBegin().
Dibujando polígono glBegin(GL_POLYGON); glVertex2f(0.0, 0.0); glVertex2f(0.0, 3.0); glVertex2f(4.0, 3.0); glVertex2f(6.0, 1.5); glVertex2f(4.0, 0.0); glEnd();
Dibujando puntos glBegin(GL_POINTS); glVertex2i(0, 0); glVertex2i(0, 3); glVertex2i(4, 3); glVertex2i(6, 1); glVertex2i(4, 0); glEnd();
Dibujando un triangulo glBegin(GL_TRIANGLES); glVertex2i(0, 0); glVertex2i(5, 0); glVertex2i(3, 5); glEnd();
32
Capítulo 2 - Conceptos Fundamentales de OpenGL
Dibujando un cuadrilátero glBegin(GL_QUADS); glVertex2i(0, 0); glVertex2i(4, 0); glVertex2i(0, 4); glVertex2i(4, 4); glEnd();
Figura 9: Tipo de primitivas. 33
Capítulo 2 - Conceptos Fundamentales de OpenGL
2.5
Gestión De Características De Estados OpenGL
OpenGL mantiene muchos estados y variables de estado. Un objeto puede ser renderizado con iluminación y texturarizado, eliminando la supercie oculta, niebla, y otros estados que afectan su apariencia. Por defecto, muchos de esos estados están inicialmente inactivos, ya que estos estados afectan al proceso de renderización al momento de ser activados,
puesto que si a una primitiva se le coloca textura, niebla o iluminación, el proceso de renderización se vuelve lento, y el tiempo de renderización dependerá del rendimiento del sistema. Pero de cualquier modo la imagen mejorara en calidad y tendrá una apari encia más realista. Debido al aumento de su capacidad gráca.
Para habilitar y deshabilitar estos estados, se utilizan únicamente dos comandos:
Void glEnable( GLenum característica ); Void glDisable (GLenum característica ); glEnable(): Es la función que habilita una característica de estado de OpenGL. glDisable(): Deshabilita una características de estado de OpenGL.
En la tabla 3 se muestra una lista de características de estados OpenGL, que pueden ser habilitados y deshabilitados con estas funciones.
Tabla 3: Características de estados de OpenGL. ESTADOS GL_FOG GL_COLOR_SUM GL_LIGHTING GL_BLEND GL_LIGHTi GL_POINT_SMOOTH GL_TEXTURE_CUBE_MAP GL_SCISSOR_TEST GL_DITHER GL_LINE_SMOOTH GL_LINE_STIPPLE
DESCRIPCIÓN Habilita el modo niebla. Habilita la suma de color. iluminación. Fundido de color. Número de luz i. Suavizado de punto. Mapa de textura de cubo. Recorte habilitado. Tramado. Suavizado de línea. Puntero de línea. 34
Capítulo 2 - Conceptos Fundamentales de OpenGL GL_CULL_FACE GL_POLYGON_SMOOTH GL_POLYGON_STIPPLE GL_TEXTURE_xD GL_STENCIL_TEST GL_DEPTH_TEST
Seleccionar polígono. Suavizado de polígono. Puntero de polígono. Textura de xD(1, 2, 3). Prueba de Plantilla. Prueba detallada.
Tabla 3: Continuación de las características de estados de OpenGL.
2.6
Desplegando Puntos, Líneas Y Polígonos
Por defecto, en OpenGL un punto se dibuja como un simple pixel en la escena, una línea como un sólido de un pixel de ancho, y los polígonos son dibujados como un
sólido rellenado. En esta sección se discutirá los detalles de cómo se cambian los modos de desplegar los puntos, líneas y polígonos.
2.6.1 Detalles de puntos Se puede controlar el tamaño de los puntos con la función glPoi ntSize(), a la cual se le suministran el tamaño deseado en pixeles como argumento de la función. void glPointSize (GLoat size)
Modica la anchura de los puntos.
Ejemplo: fragmento de código para cambia el grosos del punto a tamaño 4. glPointSize(4.0) // modicamos el tamaño del punto. glBegin(GL_POINTS); glVertex2f(0, 0); // Coordenadas del vértice. glEnd();
2.6.2 Detalles de líneas OpenGL tiene funciones que te permiten modicar y controlar el grosor de las líneas, así como también para crear patrones de líneas. Estas funciones son:
void glLineWidth(GLoat width) La nalidad de esta función es establecer el ancho en pixeles de las líneas dibujadas con cualquier primitiva basada en líneas.
Ejemplo: fragmento de código para cambiar el ancho de la línea a un valor de 8. glLineWidth(8.0);
// modicamos el tamaño de la línea a 8
35
Capítulo 2 - Conceptos Fundamentales de OpenGL
glBegin(GL_LINES); // Dibujamos una línea glVertex3f(-0.6,-0.2,0.0); // Coordenadas del primer vértice glVertex3f(0.6,-0.2,0.0); // Coordenadas del segundo vértice glEnd(); // Terminamos de dibujar Void glLineStipple(GLint factor, GLushort pattern) Esta función es para crear un patrón con líneas, ya sea punteado o guiones a lo cual se le denominara patrón.Ver la gura 10 donde se muestra ejemplos de pa -
trones de líneas. ♦
♦
Factor: Especifica un multiplicador que determina cuantos pixeles se verán afectados por cada bit en el parámetro pattern. El valor
predeterminado es 1 y el máximo es 2 25. Pattern: Establece el patrón del puntero de 16 bits.
Para usar esta función es necesario que se habilite la característica de es tado GL_LINE_STIPPLE. Este estado es habilitado con la función glEnable() y deshabilitada con glDisable().
Figura 10: Patrones de línea. Ejemplo: fragmento de código para crear un patrón de línea con un factor de 1 y un pattern de0x00FF. glLineStipple(1, 0x00FF); glEnable(GL_LINE_STIPPLE); tado GL_LINE_STIPPLE glBegin(GL_LINES); glVertex3f(-0.6,-0.2,0.0); glVertex3f(0.6,-0.2,0.0);
// se establece el patrón de la línea //se habilita la característica de es // Dibujamos un triángulo // Coordenadas del primer vértice // Coordenadas del segundo vértice
36
Capítulo 2 - Conceptos Fundamentales de OpenGL
glEnd(); // Terminamos de dibujar glDisable(GL_LINE_STIPPLE); //se deshabilita la característica de estado GL_LINE_STIPPLE
2.6.3 Detalles de polígonos OpenGL tiene una función que nos permite cambiar la forma en la que visualizamos
los polígonos que se despliegan en una escena, así como también para crear patrones de rellenos para los polígonos. Estas funciones son:
voidglPolygonMode(GLenum face, GLenum mode) ♦
face: especifica la cara del polígono que se verá afectado por el cambio de modo.los parámetros que puede tener son: GL_FRONT, GL_BACK, GL_FRONT_AND_BACK.
♦
mode: especifica el nuevo modo de dibujo. Los parámetros para mode son: GL_FILL generan los polígonos relleno, GL_LINE genera los esquemas del polígono, GL_POINT traza los puntos de los vér-
tices. La nalidad de esta función es cambiar la forma en la que se describen los
polígonos, haciendo que los polígonos no solo sean rellenos, sino que también se dibuje los vértices de este, o las líneas de su contorno.
Ejemplo: fragmento de código para crear un polígono al que se le cambia la forma de visualizarlos. glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // se establece el modo en que se verá afectado el polígono glBegin(GL_POLYGON); //dibuja el polígono glColor3f(1.0,0.0,0.0); glVertex3f(0.0, 0.0, 0.0);//coordenadas del primer vértice glColor3f(0.0,1.0,0.0); glVertex3f(0.0, 0.3, 0.0); //coordenadas del primer vértice glColor3f(0.0,0.0,1.0); glVertex3f(0.4, 0.3, 0.0); //coordenadas del primer vértice glColor3f(0.0,1.0,1.0); glVertex3f(0.6, 0.15, 0.0); //coordenadas del primer vértice glColor3f(1.0,0.0,1.0); glVertex3f(0.4, 0.0, 0.0); //coordenadas del primer vértice glEnd(); // Terminamos de dibujar
37
Capítulo 2 - Conceptos Fundamentales de OpenGL
void glPolygonStipple(const GLubyte *mask) Esta función es utilizada para rellanar un polígono de acuerdo a un patrón,
para hacer el patrón de relleno se crea un bitmap de 32x32 de tamaño organizado por las, cual será de tipo GLubyte. Esta bitmap es el que será usada como patrón de relleno para el polígono, este bitmap será rellenado de 1’s y 0’s. Esto nos dice que cuando aparece un 1, este corresponderá a un pixel que será dibujado en el polígono, y cuando aparece un 0 no se dibuja nada.
Para habilitar y deshabilitar el patrón de relleno del polígono, se utiliza el glEnable () y el glDisable () , donde habilitaremos la característica de estado GL_POLYGON_STIPPLE.
Ejemplo: código para hacer un patrón de relleno para polígonos. Utilizando la función glPolygonStipple(). void mostrar(void) {
glClearColor(0.0,0.0,0.0,0.0); // Color de fondo: negro glClear(GL_COLOR_BUFFER_BIT); // Boramos la pantalla glViewport(0, 0, 500.0, 500.0); glMatrixMode(GL_PROJECTION); // Modo proyección glLoadIdentity(); // Cargamos la matriz identidad gluOrtho2D(0.0,500.0, 0.0, 500.0); tro del cubo señalado
// Proyección ortográca, den -
glMatrixMode(GL_MODELVIEW); // Modo de modelado
GLubyte estilo[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 38 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
Capítulo 2 - Conceptos Fundamentales de OpenGL
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
glEnable (GL_POLYGON_STIPPLE); // habilita el patrón de relleno glPolygonStipple (estilo); // especica el patrón de relleno glBegin(GL_POLYGON); //dibuja el polígono glColor3f(1.0,0.0,0.0); glVertex3f(100.0, 100.0, 0.0);//coordenadas del primer vértice glColor3f(0.0,1.0,0.0); glVertex3f(100.0, 400, 0.0); //coordenadas del segundo vértice glColor3f(0.0,0.0,1.0); glVertex3f(400, 400, 0.0); //coordenadas del tercero vértice glColor3f(0.0,1.0,1.0); glVertex3f(400, 100.0, 0.0); //coordenadas del cuarto vértice glEnd(); // Terminamos de dibujar glDisable (GL_POLYGON_STIPPLE); glFlush(); }
int main(intargc, char * argv) {
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(20,20); glutInitWindowSize(500,500); glutCreateWindow(“patrones de relleno”); glutDisplayFunc(mostrar); glutMainLoop(); return 0; }
39
Capítulo 2 - Conceptos Fundamentales de OpenGL
Figura 11: Resultado de la ejecución.
Referencias Dave Shreiner, T. K. (Julio 2009). OpenGL Programming Guide (Seventh Edition ed.). Pearson Education, Inc. . González, D. E. Computación Gráca: Manejo de Grácos con OpenGL. Panamá,
Panamá. Hearn, D., & Baker, M. P. (2006). Gracos por Computadora con OpenGL (Tercera Edición ed.). Madrid: Pearson Educación S.A.
40
Capítulo 2 - Conceptos Fundamentales de OpenGL
Taller Nº 4 Dado el siguiente código, vea lo que genera el programa y después realice las modicaciones que se le indique en los diferentes puntos. #include #include #include #include
voidmostrar(void) {
glClearColor(0.0,0.0,0.0,0.0); // Color de fondo: negro glClear(GL_COLOR_BUFFER_BIT); // Borramos la pantalla glMatrixMode(GL_PROJECTION); // Modo proyección glLoadIdentity(); // Cargamos la matriz identidad glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); // Proyección ortográca, dentro del cubo señalado glMatrixMode(GL_MODELVIEW);
// Modo de modelado
glBegin(GL_TRIANGLES); // Dibujamos un triángulo glColor3f(1.0,0.0,0.0); // Color del primer vértice: rojo glVertex3f(0.0,0.8,0.0); // Coordenadas del primer vértice glColor3f(0.0,1.0,0.0); // Color del segundo vértice: verde glVertex3f(-0.6,-0.2,0.0); // Coordenadas del segundo vértice glColor3f(0.0,0.0,1.0); // Color del tercer vértice: azul glVertex3f(0.6,-0.2,0.0); // Coordenadas del tercer vértice glEnd(); // Terminamos de dibujar glFlush();
// Forzamos el dibujado
}
int main(int argc, char * argv) {
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(20,20); glutInitWindowSize(500,500); glutCreateWindow(“TALLER 1”); glutDisplayFunc(mostrar); glutMainLoop(); return 0;
41
Capítulo 2 - Conceptos Fundamentales de OpenGL
}
1.
Modifique las instrucciones del recuadro que aparce en el programa con el siguiente código:
glBegin(GL_POLYGON); glColor3f(1.0,0.0,0.0); glVertex3f(0.0, 0.0, 0.0); glColor3f(0.0,1.0,0.0); glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0,0.0,1.0); glVertex3f(0.4, 0.3, 0.0); glColor3f(0.0,1.0,1.0); glVertex3f(0.6, 0.15, 0.0); glColor3f(1.0,0.0,1.0); glVertex3f(0.4, 0.0, 0.0); glEnd();
42
Capítulo 2 - Conceptos Fundamentales de OpenGL
¿Cuál es la salida del programa ahora? ________________________________________________________ ________________________________________________________ 2.
Modifique las instrucciones del recuadro que aparce en el programa con el siguiente código:
glBegin(GL_POINTS); glColor3f(1.0,0.0,0.0); glVertex3f(0.0, 0.0, 0.0); glColor3f(0.0,1.0,0.0); glVertex3f(0.0, 0.3, 0.0); glColor3f(0.0,0.0,1.0); glVertex3f(0.4, 0.3, 0.0); glColor3f(0.0,1.0,1.0); glVertex3f(0.6, 0.1,0.0); glColor3f(1.0,0.0,1.0); glVertex3f(0.4, 0.0, 0.0); glEnd();
¿Cuál es la salida del programa ahora? ________________________________________________________ ________________________________________________________
3.
Modifique las instrucciones del recuadro que aparce en el programa con el siguiente código:
glBegin(GL_QUADS); glVertex3f(0.0, 0.0, glVertex3f(0.4, 0.0, glVertex3f(0.0, 0.4, glVertex3f(0.4, 0.4, glEnd();
0.0); 0.0); 0.0); 0.0);
¿Cuál es la salida del programa ahora? ________________________________________________________ ________________________________________________________ 43
Capítulo 2 - Conceptos Fundamentales de OpenGL
Taller Nº 5 Dado el siguiente código, vea lo que genera el programa y después realice las modicaciones que se le indique en los diferentes puntos.
#include #include #include #include
void mostrar(void) {
glClearColor(0.0,0.0,0.0,0.0); // Color de fondo: negro glClear(GL_COLOR_BUFFER_BIT); // Borramos la pantalla glMatrixMode(GL_PROJECTION); // Modo proyección glLoadIdentity(); // Cargamos la matriz identidad glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); // Proyección ortográca, dentro del cubo señalado glMatrixMode(GL_MODELVIEW); // Modo de modelado glLineWidth(1.0);// denimos el ancho de la línea glLineStipple(2, 0x00FF);// especicamos el patrón deesado glEnable(GL_LINE_STIPPLE);// habilitamos la característica de es tado glBegin(GL_LINES); // Dibujamos un triángulo glColor3f(0.0,1.0,0.0); // Color del segundo vértice: verde glVertex3f(-0.6,-0.2,0.0); // Coordenadas del segundo vértice glColor3f(0.0,0.0,1.0); // Color del tercer vértice: azul glVertex3f(0.6,-0.2,0.0); // Coordenadas del tercer vértice glEnd(); // Terminamos de dibujar glDisable(GL_LINE_STIPPLE);// deshabilitamos la característica de estado glFlush(); // Forzamos el dibujado }
int main(int argc, char * argv) {
44
Capítulo 2 - Conceptos Fundamentales de OpenGL
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(20,20); glutInitWindowSize(500,500); glutCreateWindow(“TALLER 2”); glutDisplayFunc(mostrar); glutMainLoop(); return 0; }
Figura 13: Resultado de la ejecución.
1.
Modifiquele el parámetro factor de la función glLineStipple(factor, pattern); con los siguientes parámetros: ♦ ♦ ♦ ♦
Factor = 4 Factor = 6 Factor = 8 Factor = 10
45
Capítulo 2 - Conceptos Fundamentales de OpenGL
¿Qué efecto se produce con las modicaciones hechas al programa?
________________________________________________________ ________________________________________________________ 2.
Modifique el parámetro pattern de la función glLineStipple(factor, pattern); con los siguientes parámetros: ♦ ♦ ♦ ♦ ♦
Pattern = 0x0001 Pattern = 0x0101 Pattern = 0x1010 Pattern = 0xAAAA Pattern = 0xFFFF
¿Qué efecto se produce con las modicaciones hechas al programa?
________________________________________________________ ________________________________________________________ 3.
Modifique el parámetrowidth de la función glLineWidth(width) con los siguientes parámetros: ♦ ♦ ♦ ♦
Width = 3 Width = 4 Width = 5 Width = 8
¿Qué efecto se produce con las modicaciones hechas al programa?
________________________________________________________ ________________________________________________________
46
Capítulo 2 - Conceptos Fundamentales de OpenGL
Ejercicio Nº 2 Hacer un programa que dibuje un polígono de cuatro vértices, donde cada vértice sea de un color diferente.
Ejercicio Nº 3 Con el programa del ejercicio 1, utilice la función glPolygonMode (face, mode) . Y asígnele los siguientes parámetros:
♦
face: GL_FRONT_AND_BACK
♦
mode: GL_LINE
Haga una breve descripción de lo que le sucede al polígono al momento de añadirle la función.
47
<3> C a p í t u l o OpenGL Básico en 3D OBJETIVOS ♦ Conocer la estructura de un programa que utilice OpenGL para la creaciòn de menùs desplegables. ♦ Presentar la sintaxis grafica de las librerias
♦
♦
de OpenGL para la generaciòn de aplicaciones interactivas en 3D. Describir la orden OpenGL que permite determinar el àrea en pantalla donde se proyectaran las imàgenes. Explicar las funciones
que se requieren para la definiciòn, ubi caciòn y orientaciòn de la càmara que usa OpenGL.
DESCRIPCIÓN: En esta sección se presentará la estructura que debe seguir un programa que utilice las librerías grácas de OpenGL para la creación de menús desplegables; se presentará la
sintaxis que se requieren para la generación de aplicaciones interactivas en 3D; se ex plicará la funcionalidad de los comandos de
OpenGL para la creación de una animación sin parpadeo. Adicionalmente, se indicarán cuáles son las instrucciones encargadas de realizarlas tareas necesarias para la creación de una ventana y se describirá la función de
OpenGL que permite determinar el área en pantalla donde se proyectarán las imágenes y cuáles son las funciones que se requieren para la denición, ubicación y orientación
de la cámara que usa OpenGL. Finalmente, se dará a conocer las instrucciones que se emplean en OpenGL para la ocultación de objetos y los comandos de OpenGL para re alizar transformaciones en la construcción de
aplicaciones 3D.
48
Capítulo 3 - OpenGL Básico en 3D
3.
OpenGL Básico en 3D
3.1
Menús desplegables
Para poder incluir menús desplegables en la aplicación se necesitan dos pasos. Primero la denición de la estructura de menús con la asignación del evento de
despliegue y, segundo, la asignación a cada opción de menú del código que se debe ejecutar al pulsar esa opción. La denición de la estructura de menús se puede realizar dentro de las fun ciones init() o main() de la siguiente forma: void init(); {
glutCreateMenu(menuapp); glutAddMenuEntry(“Borrar Pantalla”,1);
glutAddMenuEntry(“Salir”,2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
La Liberia GLUT incorpora un conjunto de instrucciones que ayudan de una manera fácil a que se añadan menús desplegables en una aplicación. Las fun ciones básicas para crear un menú desplegable con OpenGl son: ♦
Función que crea un menú desplegable: i nt (void(*función) (int valor));
glutCreateMenu
glutCreateMenu crea un nuevo menú emergente y devuelve un identicador único entero pequeño. La gama de asignar identicadores empieza a la una. El rango de identicador de menú es independiente de la gama de identicador de ventana.
Implícitamente, el menú actual se establece en el menú de nueva creación. Este identicador de menú se puede utilizar cuando se llama a glutSetMenu.
Cuando la devolución de llamada del menú es llamado por una entrada del menú es seleccionado para el menú, el menú actual es implícitamente establecido en el menú con la entrada seleccionada antes de la devolución de llamada se hace. ♦
Función que asigna al menú actual a un botón concreto del ratón: void glutAttachMenu (int boton);
glutAttachMenu concede un botón del ratón para el actual ventana para el identi cador el menú actual, glutDetachMenú desprende un botón conectado a la corriente ventana. Al colocar un identicador de menú a un botón, el menú l lamado se apare ció cuando el usuario presiona el botón especicado.
El botón debe ser uno de:
49
Capítulo 3 - OpenGL Básico en 3D GLUT_LEFT_BUTTON
botón izquierdo
GLUT_MIDDLE_BUTTON
botón medio
GLUT_RIGHT_BUTTON
botón derecho
Tenga en cuenta que se asocia el menú del botón de identicación, no por de ref -
erencia. ♦
Función que añade una opción al menú: void glutAddMenu Entry (char *nombre, int valor);
glutAddMenuEntry añade una entrada de menú en la parte inferior del menú actual .
El parametro denominado nombre se añade al menu actual y se identica
por el parametro valor. Este parametro es el que se utiliza para distinguir unas opciones de otras. Con lo visto hasta ahora ya es posible crear un menu con un conjunto de opciones. una posibilidad mas es que una opcion del menu a su vez sea otro menu:
es lo que se llama un submenu. un submenu se crea igual que un menu, es decir, con la orden glutCreatreMenu vista anteriormente ♦
Función que añade un nuevo menú como una opción: glutAddSubMenu (char *nom bre, int menu);
void
glutAddSubMenu añade un disparador de sub-menú de la parte inferior del menú
actual. El nombre de la cadena se muestra para el recién agregado sub-menú de disparo. Si el gatillo sub-menú es introducido, el menú numerado del sub-menú se mostrara en cascada, lo que permite sub-menú mostrar las opciones de menú a elegir.
3.2 Creación de una animación sin parpadeo, eliminación de caras traseras La animación es una de las aplicaciones más importantes de la computación gráca. En OpenGL el método que se utiliza para crear una animación es similar al utilizado en la proyección de una película. Por ejemplo las películas se graban empleando una secuencia de imágenes jas que son proyectadas en la pantalla a
una velocidad de 24 imágenes por segundo dando una sensación de continuidad. El procedimiento que se emplea para la proyección de una película inicia cuando se pone cada imagen delante del proyector, luego se abre el foco y la im agen se visualiza. Posteriormente, se cierra el foco momentáneamente, se pone la siguiente imagen delante del proyector y se vuelve a abrir el foco, y asi 24 veces por
segundo. El algoritmo que se utiliza para visualizar un millón de imágenes en una computadora es el siguiente:
50
Capítulo 3 - OpenGL Básico en 3D Abrir_Ventana(); For(i=0;i<1000000;i++) {
Borrar_Ventana(); Dibujar_Ventana(i); Proyeccion_de_una_pelicula(); }
Esta alternativa presenta un problema, al no mostrar las imágenes que fuer on terminadas, sino que el dibujo es visualizado mientras se está generando. Por tal razón es que en este tipo de aplicaciones aparece el efecto de parpadeo.
Las últimas versiones de los sistemas OpenGL usan un sistema de doble buffer que permite que se dibuje en un buffer sea visualizado en otro, y al termi narse de dibujar se intercambian. De esta forma, se logra que en un cuadro solo sea visualizado cuando está completamente dibujado y, con ello desaparece el
parpadeo. El algoritmo que ayuda a la eliminación del parpadeo, se muestra en el siguiente código: Abrir_Ventana(); For(i=0;i<1000000;i++) {
Borrar_Ventana(); Dibujar_Ventana(i); Cambiar_Buffer(); }
En un programa de OpenGL en el que se desea eliminar el parpadeo, se utilizan las siguientes funciones:
glutInitDisplayMode establece el modo de visualización inicial. El modo de visualización inicial se utiliza al crear ventanas de nivel superior, sub-ventanas y revestimientos para determinar el modo de visualización de la ventana de OpenGL a-ser-creado o superposición. Tenga en cuenta que GLUT_RGBA selecciona el modelo de color RGBA, pero no solicita ningún bit de la alfa (a veces llamado un buffer de alfa alfa o destino) se asignarán. Para solicitar alfa, especique GLUT_ALPHA. Lo mismo se aplica a GLUT_ LUMINANCE. glutSwapBuffers intercambia los buffers de la ventana actual si buffer doble. glutSwapBuffers Realiza un intercambio de buffer en la capa de uso de la ventana actual. En concreto, glutSwapBuffers promueve el contenido del búfer trasero de la capa en el uso de la ventana actual para convertirse en el contenido del búfer fron tal. El contenido del búfer de aquel entonces convertido en indenido. La actualiza ción suele tener lugar durante el refresco vertical del monitor, y no inmediatamente
51
Capítulo 3 - OpenGL Básico en 3D
después glutSwapBuffers se llama. Un glFlush implícita se hace glutSwapBuffers antes de que vuelva. Los siguientes comandos de OpenGL pueden ser emitidos inmediatamente después de llamar glutSwapBuffers, pero no se ejecutan hasta que el intercambio de buffer se
ha completado. Si la capa de uso no es el doble buffer, glutSwapBuffers no tiene ningún efecto. glutIdleFunc establece la devolución de llamada ociosa mundial para fun -
ciones por lo que un programa de GLUT se pueden realizar tareas de procesamiento en segundo plano o una animación continua en los eventos del sistema de ventanas no se están recibiendo. Si se activa, el callback idle está continuamente llamado cuando los acontecimientos no se están recibiendo. La rutina callback no
tiene parámetros. La ventana y menú actual no será cambiado antes de la devolución de llamada de inactividad. Programas con múltiples ventanas y / o menús debe establecer explícitamente la ventana actual y / o actuales del menú y no depender de su conguración actual. El monto de la computación y la prestación hecha en un callback idle de bería reducirse al mínimo para no afectar la respuesta interactiva del programa. En general, no más de un solo marco de la prestación debe hacerse en un callback
idle. Pasar NULL a glutIdleFunc desactiva la generación de la devolución de llamada de inactividad. glutPostRedisplay marca el plano normal de la ventana actual como la necesidad de volver a mostrar. La siguiente iteración a través de glutMainLoop, la
devolución de llamada de la ventana de visualización se llama para volver a mostrar plano normal de la ventana. Varias llamadas al glutPostRedisplay ante la posibilidad de devolución de llamada pantalla siguiente sólo genera una devolución de llamada vuelve a mostrar una sola. glutPostRedisplay puede ser llamado dentro de la presentación de una ventana o de devolución de llamada superposición de pantalla para volver a marcar la ventana para volver a mostrar. Lógicamente, la noticación normal de daño de avión para una ventana es tratado como un glutPostRedisplay en la ventana dañada. A diferencia de los daños
reportados por el sistema de ventanas, glutPostRedisplay no se establece en verdadero estado dañado el plano normal (devuelto por glutLayerGet (GLUT_NOR MAL_DAMAGED)).
3.3 ♦
Denir, situar y colocar la cámara que usa OpenGL Denición y colocación de la cámara
Una vez hemos denido toda nuestra escena en coordenadas mundo, tenemos que “hacerle la foto”. Para ello, tenemos que hacer dos cosas: colocar la cámara en el mundo (o sea, en la escena) y denir el tipo de proyección que realizará la cámara.
52
Capítulo 3 - OpenGL Básico en 3D
♦
Posición de la cámara
Tenemos que denir no sólo la posición de la cámara (o donde está), sino también
hacia dónde mira y con qué orientación (no es lo mismo mirar con la cara torcida que recta… aunque veamos lo mismo). Para hacer esto, basta con modicar la matriz ModelView para mover toda la
escena de manera que parezca que hemos movido la cámara. El problema de este sistema es que tenemos que pensar bastante las transformaciones a aplicar. Es por ello que la librería GLU viene al rescate con la función gluLookAt. Su sintaxis es la siguiente: void gluLookAt( eyeX, eyeY, eyeZ, cenX, cenY, cenZ, vp_X, vp_Y, vp_Z);
donde eye corresponde a la posición de la cámara, cen corresponde al punto hacia donde mira la cámara y vp es un vector que dene la orientación de la cámara. No podemos llamar a gluLookAt en cualquier momento, puesto que tiene postmulti-
plicar la matriz ModelView (por tanto, conviene llamarla lo primero de todo). El vector vp no puede ser paralelo al vector formado por eye y cen, es más, debería serle
perpendicular. Si no, el resultado es impredecible.
53
Capítulo 3 - OpenGL Básico en 3D
3.4
La Proyección en OpenGL
En esta parte analizaremos como denir la matriz de proyecci ón que también afecta a los vértices de la escena. Es importante recordar que de forma previa a la espe cicación de la matriz de proyección es necesario activar dicha matriz e inicializarla mediante las órdenes OpenGL: glMatrixMode(GL_PROJECTION); glLoadIdentity();
La proyección dene el volumen del espacio que va a utilizarse para formar la imagen; en el caso de la proyección perspectiva este volumen es una pirámide truncada o frustum. Por lo tanto, en esta proyección se produce un efecto tamaño distancia (los objetos aparecen más pequeños cuanto más alej ados están del punto
de vista) y es la proyección más usada en animación por ordenador o simulación visual, donde se requiere un alto grado de realismo. El frustum de visualización se dene en OpenGL de la forma siguiente: void glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble
54
Capítulo 3 - OpenGL Básico en 3D top, GLdouble near, GLdouble far) dónde los parámetros left, right, bottom, top, near y far denen el frustum tal y como se muestra en la gura siguiente:
Tal y como se muestra en la gura, el frustum no tiene porqué ser simétrico respecto al eje Z, ya que es posible utilizar valores distintos para left y right, o para
bottom y top. La especicación de una proyección perspectiva mediante glFrustum puede resultar complicada debido a que la forma de denición no resulta intuitiva. En lu -
gar de esta orden, podemos utilizar la rutina de la librería de utilidades de OpenGL gluPerspective. Esta rutina permite perm ite especicar el volumen de la vista de forma difer ente, utilizando el ángulo de visión sobre el plano XZ (fovy) y el ratio de la anchura
respecto a la altura (aspect). Mediante estos parámetros es posible determinar el volumen de la vista, tal y como se muestra en la gura siguiente:
Esta forma de denir la proyección resulta más intuitiva. La sintaxis de la rutina gluPerspective es la siguiente: void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble near, GLdou -
55
Capítulo 3 - OpenGL Básico en 3D ble far);
Cuando utilicemos la rutina gluPerspective tendremos que tomar precauciones con respecto a los valores de fovy y near. Una mala elección de dichos valores puede producir deformaciones en la imagen similares a las aberraciones ópticas habituales en las lentes fotográcas (v.g. efecto “ojo de pez”). Otra forma de denir la manera en que una cámara sintética observa una escena es mediante dos posiciones en el espacio: la del punto de interés o punto al que la cámara está enfocando, y la del punto de vista o punto dónde se encuen tra situada la cámara. Esta forma de denir la transformación de la vista es la que utiliza la orden de la librería de utilidades de OpenGL gluLookAt. La sintaxis de la orden es la siguiente: gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, gluLookAt(GLdouble GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz);
donde los parámetros eyex, eyey, eyez indican la posición del punto de vista; centerx, centery, centerz especican el punto de interés y upx, upy, upz la dirección
tomada como “arriba”, o inclinación de la cámara La proyección ortográca dene un volumen de la vista cuya geometría es la de un paralelepípedo rectangular (o informalmente, una “caja”). A diferencia de la proyección perspectiva, la distancia de un objeto a la cámara no inuye en el tama ño nal del mismo en la imagen. Este tipo de proyecciones son comunes en aplica -
ciones de diseño asistido por ordenador, ya que las medidas sobre la imagen son proporcionales a las reales de acuerdo a un determinado facto r de escala. Entre las proyecciones ortográcas más comunes en este tipo de sistemas cabe destacar la proyección ortográca (planta, alzado y perl) y la proyección isométrica. La caja de visualización se dene en OpenGL de la forma siguiente:
void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GL double top, GLdouble near, GLdouble far); dónde los parámetros left, right, bottom, top, near y far denen la caja tal y como se muestra en la gura siguiente:
56
Capítulo 3 - OpenGL Básico en 3D
3.5
Visibilidad: Ocultación de objetos (Z-Buffer)
El enunciado del problema es el siguiente: Dado un conjunto de objetos 3D y una especicación de la vista, se desea conocer las supercies de los objetos visibles desde la posición del observador, para evitar dibujar las ocultas.
De los algoritmos existentes para resolver dicho problema, uno de lo más importantes es el algoritmo del Z-buffer, por ser uno de los más simples de imple mentar (implementación hardware). Para su funcionamiento necesita denir una matriz de profundidad (Z-buffer) con un número de entradas igual al de pixels en la
ventana de visualización. Esta matriz almacena las coordenadas z de los puntos de la supercie del objeto a iluminar y debe inicializarse con el menor valor de z. Durante el proceso de visualización de los objetos, si el punto del objeto que iluminará el pixel (x, y) tiene un valor profundidad (coordenada z) mayor que el que se encuentra almacenado en el Z-buffer, se iluminará el pixel y se reemplazará el
antiguo valor de z por el nuevo. En caso contrario no es necesario iluminar ningún pixel pues el objeto en ese punto está oculto. Z-buffer en OpenGL Los pasos a seguir para utilizar el Z-buffer en OpenGL son los siguientes:
Creación de la ventana de d e la aplicación incluyendo el Z-buffer Z-buffer.. La creación de la ventana de la aplicación incluye el parámetro AUX_DEPTH para garantizar que se aplica ocultación por Z-buffer.
auxInitDisplayMode(AUX_SINGLE auxInitDisplayMo de(AUX_SINGLE | AUX_RGBA | AUX_DEPTH) Activar el Z-buffer y denir el tipo de comparación de profundidad.
La llamada a glEnable con parámetro GL_DEPTH_TEST activa la ocultación por ZBuffer. La función glDepthFunc dene la forma en que se realiza la comparación con el buffer de profundidad de OpenGL (ocultación de supercies). Por ejemplo
57
Capítulo 3 - OpenGL Básico en 3D
utilizando el argumento GL_LEQUAL se iluminarán los pixels de pantalla cuando sean menores o iguales a los ya dibujados.
glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST);
Inicializar el Z-buffer. La orden glClear debe borrar tanto la ventana de la aplicación ( GL_COLOR_BUFFER_ BIT) como el buffer de profundidad o Z-Buffer ( GL_DEPTH_ BUFFER_BIT ). glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
3.6
Las Transformaciones en OpenGL
Las funciones disponibles en OpenGL para especicar transformaciones en 3D son: traslación, rotación y escalado. Estas rutinas actúan sobre la matriz de Mod elo / Vista, por lo que serán de utilidad tanto para aplicar transformaciones a los distintos objetos de la escena, como para denir las transformaciones asociadas al
posicionamiento de dicha escena en el volumen de la vista. OpenGL utiliza dos matrices distintas durante el proceso de visualización, la matriz de Modelo / Vista y la matriz de proyección. Para distinguir sobre cual de dichas matrices van a actuar las distintas rutinas de transformación se utiliza la siguiente función OpenGL: void glMatrixMode (GLenum mode);
donde el parámetro mode especica la matriz a utilizar en las transformaciones siguientes mediante las constantes GL_MODELVIEW, GL_PROJECTION o GL_TEXTURE .
Independientemente de la matriz que vayamos a utilizar, la primera operación que deberemos realizar siempre será inicializar dicha matriz a la identidad. Para ello utilizaremos la función OpenGL: void glLoadIdentity (void);
Transformaciones del modelo Las tres rutinas que proporciona OpenGL para denir transformaciones son glTrans late*, glRotate* y glScale*. La rutina de traslación void glTranslate{fd} (TYPE x, TYPE y, TYPE z);
multiplica la matriz actual por una matriz de traslación con desplazamientos indicados por x, y, z. La rutina de giro void glRotate{fd} (TYPE angle, TYPE x, TYPE y, TYPE z);
multiplica la matriz actual por una matriz que gira el objeto en el sentido contrario a las agujas del reloj (sentido de la mano derecha o dextrogiro) alrededor del eje que
va desde el origen al punto indicado por x, y, z. Lo más habitual es girar sobre los 58
Capítulo 3 - OpenGL Básico en 3D
ejes de coordenadas, por lo que los valores de los parámetros serán: Giro sobre X: x = 1.0, y = 0.0, z = 0.0 Giro sobre Y: x = 0.0, y = 1.0, z = 0.0 Giro sobre Z: x = 0.0, y = 0.0, z = 1.0
Por último, la rutina de escalado void glScale{fd} (TYPE x, TYPE y, TYPE z);
multiplica la matriz actual por una matriz que amplia o reduce el objeto con respecto a los ejes coordenados. Cada coordenada (x, y, z) del objeto se multiplica por el argumento correspondiente x, y, z. Valores de estos parámetros inferiores a 1.0 reducen el objeto, mientras que valores superiores a 1.0 lo amplían. Respecto al orden en que se aplican las transformaciones, supongamos que eje cutamos la siguiente porción de código OpenGL: glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(1.0, 1.0, 1.0); glScalef(2.0, 2.0, 2.0);
Inicialmente, la matriz contiene la identidad, a la que llamaremos I. La orden gLTranslatef multiplica la identidad por una matriz de traslación a la que llamaremos T. Posteriormente, la orden gLScalef multiplica la matriz resultado por una matriz de escalado a la que llamaremos S. Por tanto, después de ejecutar el código la matriz de Modelo / Vista contiene el producto I•T•S. Cuando se aplique esta matriz a los distintos vértices del modelo tendremos: v’ = I•T•S•v = I•(T•(S•v)))
es decir, primero se aplicará el escalado y posteriormente la traslación, por lo que podemos concluir que las transformaciones siempre se aplicarán en orden inverso al que han sido denidas en OpenGL.
Transformación de la vista La transformación de la vista cambia la posición y orientación del punto de vista. Si recordamos la analogía con una cámara analizada con anterioridad, la transforma ción de la vista ajusta el trípode, enfocando la cámara hacia la escena. Dado que movemos la cámara hasta la posición deseada y después la giramos para enfocar la escena, la transformación de la vista puede realizarse mediante una composición
de operaciones de giro y traslación. Es importante mencionar que para conseguir una cierta disposición de la escena en la imagen nal, es equivalente mover la cámara para que enfoque a los objetos, o mover estos últimos para que queden
dentro del campo de visión de la cámara. Esta última aproximación es la que utili59
Capítulo 3 - OpenGL Básico en 3D
zaremos en informática gráca. Los parámetros que se pueden utilizar por ejemplo para denir la transfor mación de la vista de la cámara sintética se muestran en la gura siguiente:
Por tanto, la transformación de la cámara realizará las transformaciones 3D
necesarias para llevar la cámara a la posición de observación (situada en el origen de coordenadas y enfocando hacia el eje Z negativo). Estas transformaciones son las siguientes: Girar sobre Y un àngulo para llevar la cámara al plano YZ. Girar sobre X un ángulo para llevar la cámara al eje Z. Trasladar en Z un desplazamiento -dist para llevar la cámara al origen.
Manejo avanzado de transformaciones En este apartado analizaremos algunas rutinas incorporadas en OpenGL que pueden considerarse como rutinas avanzadas de manejo de transformaciones. En tre estas rutinas, estudiaremos las que permiten la aplicación jerárquica de transfor maciones y la rutina utilizada para denir la transformación de la vista.
Aplicación jerárquica de transformaciones A menudo, la denición de una escena requiere la construcción de objetos com plejos que se crean a partir de otros más simples. En estos casos es necesario poder aplicar transformaciones de forma jerárquica a los objetos. Veamos un ejem plo. Supongamos que estamos construyendo el modelo de un coche: podemos denir un modelo simple de una tuerca y utilizarla para crear una rueda que utiliza cuatro tuercas. Una vez denida la rueda, el coche la utilizará cuatro veces en su
60
Capítulo 3 - OpenGL Básico en 3D
denición. En la construcción del coche, cada pieza básica denida en su sistema de coordenadas local se transforma a un nuevo sistema externo, el cual a su vez puede transformarse nuevamente. Para permitir la aplicación jerárquica de transformaciones, OpenGL utiliza
una pila de matrices en la que puede almacenar estados anterior es del proceso. La pila de matrices se maneja mediante las ordenes OpenGL glPushMatrix y glPopMatrix, cuya sintaxis se muestra a continuación: void glPushMatrix(void); void glPopMatrix(void);
La orden glPushMatrix mueve todas las matrices en la pila una posición hacia abajo, dejando en la cabeza de la pila una copia de la matriz cabeza de la pila anterior. Por tanto, después de ejecutar una orden glPushMatrix, la primera y segunda matriz de la pila contienen los mismos valores. Si se efectúan más ordenes glPushMatrix de las permitidas, se produce un error.
La orden glPopMatrix elimina la matriz cabeza de la pila, moviendo el resto de matrices almacenadas en la pila una posición hacia arriba. Si la pila contiene una única matriz, al ejecutar glPopMatrix se produce un error. El uso conjunto de glPushMatrix y glPopMatrix permite almacenar estados intermedios de la transformación en la pila y recuperarlos posteriormente. El efecto de la orden glPushMatrix puede entenderse como “recuerda dónde estás” y el de glPopMatrix como “vuelve a dónde estabas”.
Referencias Jordi Linares Pellicer (2003). Prácticas Grácos por Computador José Ribelles Miguel (2003). Open GL en chas: una introducción práctica. Univer -
sitat Jaume I. España Cristina Cañero Morales. Apuntes de OpenGL y GLUT Informatica Gráca 2006-2007. (s.f.). Recuperado el 30 de Septiembre de 2011, de http://trevinca.ei.uvigo.es/~vluzon/Tutorial/ PyOpenGL 2.0.1.04 Man Pages. (s.f.). Recuperado el 10 de Octubre de 2011, de http://pyopengl.sourceforge.net/documentation/manual/index.xml
Taller Nº 6 Detalles de Poligonos y Menu Desplegable Objetivos: ♦
Poner en practica el uso de las funciones para mostrar los difer -
entes modos de los polígonos. 61
Capítulo 3 - OpenGL Básico en 3D
♦
Verificar el orden de aparición de los vértices de los polígonos en
pantalla. Instrucciones Iniciales: Escriba el siguiente código y responda las interrogantes
planteadas en esta sesion. #include #include #include
static int menu, cara, sentido, modo; void variables() {
if(modo==1) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); }
else if(modo==2) {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); }
if(sentido==3) {
glFrontFace(GL_CW); }
else if(sentido==4) {
glFrontFace(GL_CCW); }
if(cara==4) {
glCullFace(GL_FRONT); }
else if(cara==5) {
glCullFace(GL_BACK); }
else if(cara==6) {
glCullFace(GL_FRONT_AND_BACK); } }
void Dibuja() {
glClear(GL_COLOR_BUFFER_BIT);
62
Capítulo 3 - OpenGL Básico en 3D
glColor3f(0.4,0.6,0.0); glEnable(GL_CULL_FACE); variables(); glBegin(GL_POLYGON); glVertex2f(-35,-35); glVertex2f(-35,35); glVertex2f(35,35); glVertex2f(35,-35); glEnd(); glFlush(); glutSwapBuffers(); }
void eventoVentana(GLsizei ancho,GLsizei alto) {
glViewport(0,0,ancho,alto); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-50,50,-50,50,-1,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity();
}
void popupMenu(int m) {
switch(m) {
case 1: modo=1; break; case 2: modo=2; break; case 3: sentido=3; break; case 4: sentido=4; break; case 5: cara=5; break; case 6: cara=6; break; case 7:
63
Capítulo 3 - OpenGL Básico en 3D
cara=7; break; case 8: exit(0); }
glutPostRedisplay();
}
void prepararMenu() {
menu=glutCreateMenu(popupMenu); glutAddMenuEntry(“Contorno GL_LINE”,1); glutAddMenuEntry(“Sòlido GL_FILL”,2); glutAddMenuEntry(“Sentido Horario GL_CW”,3); glutAddMenuEntry(“Sentido Antihorario GL_CCW”,4); glutAddMenuEntry(“Descartar GL_FORNT”,5); glutAddMenuEntry(“Descartar GL_BACK”,6); glutAddMenuEntry(“Descartar GL_FORNT_AND_BACK”,7); glutAddMenuEntry(“Salir”,8); glutAttachMenu(GLUT_RIGHT_BUTTON);
}
int main(int argc, char* argv[]) {
glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); glutInitWindowPosition(0,0); glutInitWindowSize(500,500); glutCreateWindow(“Detalles_Poligonos/Menu Desplegable”); prepararMenu(); glClearColor(0.0,0.0,0.0,0.0); glutDisplayFunc(Dibuja); glutReshapeFunc(eventoVentana); glutMainLoop(); return 0;
} 1. ¿Cuáles son los modos de dibujo de polígonos? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________ 2.
¿Qué parámetros indican el sentido en que están ordenados los polígonos? 64
Capítulo 3 - OpenGL Básico en 3D
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________ 3. ¿Cuáles son los parámetros para especificar las caras del polígono? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________ 4. ¿Cuál es la salida que genera el programa? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________
Taller Nº 7 Creación de un menú desplegado con dos opciones. Objetivo: Crear un menú desplegado con dos opciones y un submenú con cinco opciones. Instrucciones iniciales: Tomando el código de la sección anterior, detalles de poligonos y menu desplegable. Crear un menú desplegable con dos opciones: (a) Relleno y (b): Rellenos/ Lineas. La segunda opción debe ser un submenú con cinco opciones: Linea Verde, Relleno Rojo, Relleno Amarillo, Descargar y Salir.
El siguiente código muestra como rear un menú desplegado con dos opcones y un submenú con cinco opciones:
menu=glutCreateMenu(popupMenu);
glutAttachMenu(GLUT_RIGHT_BUTTON); glutAddMenuEntry(“Relleno”,3); menuParalelo=glutCreateMenu(popupMenu); glutAddMenuEntry(“Linea Verde”,1); glutAddMenuEntry(“Relleno Rojo”,2); glutAddMenuEntry(“Relleno Amarillo”,5); glutAddMenuEntry(“Descargar”,4); glutSetMenu(menuPrincipal); glutAddSubMenu(“Rellenos yLineas”,menuParalelo);
65
Capítulo 3 - OpenGL Básico en 3D
1. ¿Se debe declarar alguna variable?Explique _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________ 2. ¿Què funciones dentro del programa deben ser alteradas?Sustente _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________ 3.
¿En que parte del programa se debe incluir el còdigo proporcionado para crear el menù desplegado con dos opciones y el submenù? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________ 4.
Modofique el programa y agregue dos opciones mas con sus respec -
tivos submenùes _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ __________________________________________________________________
Ejercicio Nº 4 Comandos para visualizar grácos 3D en una aplicación Objetivos: Evaluar los conocimientos adquiridos para escribir un programa con
OpenGL . Instrucciones: Coloque a lado de cada funcion de OpenGL la descripción de la
misma. ♦ ♦ ♦
glMatrixMode: _____________________________________
________________________________________________ glRotate: ________________________________________ ________________________________________________ glFrusturm: _______________________________________ ________________________________________________ 66
Capítulo 3 - OpenGL Básico en 3D
♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦
glOrtho: _________________________________________
________________________________________________ glScale: _________________________________________ ________________________________________________ glLoadIdentity: ____________________________________ _______________________________________________ glutAddMenuEntry: __________________________________ ________________________________________________ glutCreateMenu: ___________________________________ _______________________________________________ glClearColor: _____________________________________ ________________________________________________ glEnable/glDisable: _________________________________ ________________________________________________ glutAddSubMenu: ___________________________________ ________________________________________________ glTranslate: ______________________________________ ________________________________________________ glutAttachMenu: ___________________________________ ________________________________________________ gluPerspective: ____________________________________ _______________________________________________ glPopMatrix: ______________________________________ ________________________________________________ gluLookAt: ________________________________________ ________________________________________________ glutSetMenu: ______________________________________ ________________________________________________ glPushMatrix: _____________________________________ ________________________________________________ glViewPort: _______________________________________ ________________________________________________ glutInitDisplayMode: ________________________________ ________________________________________________ glDepthFunc: ______________________________________ ________________________________________________
67
<4> C a p í t u l o Color, Materiales e Iluminación OBJETIVOS: ♦ Describir las normales en OpenGL utilizadas para la iluminación que indican la orientación relativa de un objeto respecto a las fuentes de ilumi ♦
♦
especican la normal en OpenGL t que son
utilizadas para la iluminación, indicando la
nación. Presentar los modelos de los de sombreado para darle color a
orientación relativa de un objeto respecto a las fuentes de iluminación . Se describen los
una superficie en las
un color combinación de colores de los vértices.
aplicaciones creadas en OpenGL. Mostrar el uso de los comandos en OpenGL para la definción de las propie dades de material de un objeto.
♦
DESCRIPCIÓN: En este capítulo se presentsn rutinas que
Enumerar
las
fun -
comandos que permiten darle color a una supercie mediante OpenGL, contemplando las dos formas de relleno: con color sólido, o con
Adicionalmente, se muestran las funciones que denen las propiedades de un objeto y los comandos que especican la luz de una escena; se presentan los comandos emplea -
dos en la gestion de la atenuación de la intensidad de la luz y se explica la funcionalidad de los comandos para la gestión de un foco de
luz en OpenGL.
ciones que se usarán en las aplicaciones de OpneGLpara especificar la luz de una
escena
68
Capítulo 4 - Color, Materiales e Iluminación
4.
Color, Materiales e Iluminación
4.1
Especicación de un normal en OpenGL
Para iluminar una supercie (plano) necesitamos información sobre su vector nor mal asociado. De hecho en el caso de OpenGL, es necesaria la denición de un
vector normal para cada uno de los vértices de nuestra geometría. Supongamos que tenemos un objeto 3D (gura 1). Nos situamos en su cara superior, la formada por los vértices A, B, C y D. Encontramos la normal de esta cara, que por lo tanto es la asociada a cada uno de los vértices que la forman.
Sólo tenemos que calcular dos vectores pertenecientes a la cara y hacer su producto vectorial (el resultado será un vector perpendicular a ambos y por lo tanto una normal del plano, como se ve en la gura 1, en el punto 2).
Figura 1. A partir de tres vértices (A, B, C), creo dos vectores que tras su producto vectorial me generan el vector normal. Este vector ya puede asociarse a la correspondiente cara en 1. Una vez calculada la normal tenemos que normalizar, es decir, dividir ese vector por su propio módulo para que sea unitario. De esta forma tenemos un vec tor normal de módulo igual a la unidad que es lo que OpenGL necesita. Es importante el orden en que multiplicaras, porque de éste depende que el vector normal apunte hacia fuera o hacia dentro de la cara. Lo que queremos es que las normales apunten hacia fuera de la cara visible, y así le decimos a OpenGL que solo dibuje la parte visible de las caras. (FRONT).
OpenGL utilizará la normal asociada a cada vértice para evaluar la luz que incide sobre éste. Si un vértice pertenece a más de una cara, podemos o bien promediar para obtener unos cálculos correctos por parte de OpenGL, o bien repetir 69
Capítulo 4 - Color, Materiales e Iluminación
los vértices, cada uno con la normal que le corresponde. Para denir normales con OpenGL , se utilizan las siguientes funciones:
glBegin ( GL_POLYGON ) ; glNormal3f ( CoordX, CoordY, CoordZ ) ; glVertex3f ( ... ) ; glVertex3f ( ... ) ; glVertex3f ( ... ) ; glVertex3f ( ... ) ; glEnd( ) ; En este caso estamos deniendo un polígono de N vértices que comparten la nor mal, es decir, todos tienen la misma. Si no fuera el caso lo podríamos hacer así:
glBegin ( GL_POLYGON glNormal3f ( CoordX, glVertex3f ( ... ) ; glNormal3f ( CoordX, glVertex3f ( ... ) ; glNormal3f ( CoordX, glVertex3f ( ... ) ; glNormal3f ( CoordX, glVertex3f ( ... ) ; glEnd( ) ;
) ; CoordY, CoordZ ) ; CoordY, CoordZ ) ; CoordY, CoordZ ) ; CoordY, CoordZ ) ;
Entonces cada vértice tendría su propia normal asociada. En el caso de que no se normalice el vector normal, podemos utilizar:
glEnable ( GL_NORMALIZE ) ; automática */ glDisable ( GL_NORMALIZE ) ; ción automática */
/* Para activar la normalización /* Para desactivar la normaliza -
Para que OpenGL lo haga automáticamente por nosotros. No es para nada recomendable, pues se carga al sistema con cálculos innecesarios que ralentizarán aún más lo que ya de por sí es computacionalmente exigente, es decir, el cálculo automático de la iluminación.
4.2
Estableciendo el Modelo de Sombreado
Asumiendo que se puede computar vectores normales, dado un conjunto de fuentes
de luz y un observador, los modelos de luz e iluminación desarrollados pueden aplicarse a cada punto de una supercie. Se han visto muchas de las ventajas de usar modelos poligonales para los objetos. Una ventaja adicional, para polígonos planos, es que se puede reducir bastante el trabajo requerido para el sombreado. La mayoría de los sistemas grácos, incluyendo OpenGL, explota las posi bles eciencias para polígonos planos, descomponiendo supercies curvas en mu -
70
Capítulo 4 - Color, Materiales e Iluminación
chos polígonos planos pequeños, cada uno teniendo un vector normal bien de -
nido. Se considerarán tres maneras de sombrear polígonos: ♦ ♦ ♦ ♦
Sombreado plano o constante Sombreado interpolativo o Gouraud Sombreado Phong Sombreado Plano (Flat)
Los tres vectores, l, n y v, (gura 2), pueden variar según los puntos sobre una su percie, donde: ♦
Para un polígono plano, n es c onstante. Si se asume un observador distante (la bandera GL_DISTANT_VIEWER en OpenGL), v es constante sobre el polígono.
♦
Si la fuente de luz es distante, l es constante.
♦
Figura 2. Así podemos decir que, “DISTANT” se puede interpretar como una fuente o un observador en el innito; en particular, si los polígonos son pequeños, las distancias relativas para el innito no tienen que ser muy grandes. Los ajustes nec esarios, como cambiar la ubicación de la fuente u observador a la dirección de la fuente u observador, de forma correspondiente, puede hacerse a las ecuaciones de
sombreado y a su implementación. Si los tres vectores son constantes, entonces el cálculo de sombreado se lleva a cabo una sola vez para cada polígono, y se asignará la misma sombra a cada punto en el polígono. Esta técnica se conoce como sombreado plano o constante. 71
Capítulo 4 - Color, Materiales e Iluminación
En OpenGL, se especica sombreado plano mediante: glShadeModel(GL_FLAT).
Si se usa sombreado plano, OpenGL usará las normales asociadas con el primer vértice de un polígono sencillo para el cálculo de sombreado. Para primitivas como un strip de triángulo, OpenGL usa la normal del tercer vértice para el primer triángulo, la normal del cuarto vértice para el segundo, etc. Reglas similares se aplican para otras primitivas, como strips cuadriláteros. Sombreado plano mostrará diferencias de sombreado entre los polígonos. Si las fuentes de luz y el observador están cerca del polígono, los vectores v y l serán diferentes para cada polígono.
Sombreado Interpolativo y Gouraud Si se asigna el modelo de sombreado para que sea suave, mediante glShadeModel(GL_SMOOTH).
OpenGL interpolará colores para las primitivas, como las líneas. Si se permite sombreado y luz suaves, y se asigna a cada vértice la normal del polígono siendo sombreado, se calcularía la luz en cada vértice, determinando el color del vértice, usando las propiedades materiales y los vectores v y l se computan para cada vértice. Si la fuente de luz es distante, y el observador es distante o no hay reex -
iones especulares, entonces el sombreado interpolativo sombreara un polígono con un color constante. Como múltiples polígonos se juntan en vértices interiores, cada uno teniendo
su propia normal, la normal en los vértices es discontinua. Aunque esta situación pudiera complicar las matemáticas, Gouraud se dio cuenta que la normal en el vértice de puede denir de manera que se obtenga sombras más suaves mediante
interpolación. Desde la perspectiva de OpenGL, el sombreado Gouraud es deceptivamente sencillo. Se necesita solamente asignar correctamente las normales de vértices.
Sombreado Phong Phong propuso que, en lugar de interpolar intensidades de los vértices, según se hace en el sombreado Gouraud, se interpole normales a lo largo del polígono. El sombreado Phong producirá imágenes más suaves que con el sombreado Gouraud, pero a un costo computacional mayor. Existen varias implementaciones en hardware para el sombreado Gouraud, pero no así mismo para sombreado Phong.
4.3
Estableciendo las Propiedades del Material 72
Capítulo 4 - Color, Materiales e Iluminación
Para cada polígono de la escena hay que denir un material de forma que su re -
spuesta a la incidencia de luz varíe según sea el caso. Por tanto tenemos que decirle a OpenGL de qué forma tendrá que tratar a cada trozo de geometría. Se denen cinco características fundamentales para un material. Estas componentes son: ♦
Reflexión difusa (diffuse) o color de base, que reflejaría el ob jeto si incidiera sobre él una luz pura blanca.
♦
Reflexión especular (specular), que se refiere a los “puntitos brillantes” de los objetos iluminados.
♦
Reflexión ambiental (ambient) , define como un objeto (polígono) determinado refleja la luz que no viene directamente de una fuente
♦
luminosa sino de la escena en sí. Coeficiente de brillo o “shininess”. Define la cantidad de pun tos luminosos y su concentración. Digamos que variando este parámetro podemos conseguir un objeto más o menos cercano al metal por ejemplo.
♦
Coeficiente de emisión (emission) o color de la luz, que emite el objeto.
Las componentes ambiental y difusa son típicamente iguales o muy seme jantes. La componente especular suele ser gris o blanca. El brillo nos determinará el tamaño del punto de máxima reexión de luz. Se pueden especicar diferentes parámetros en cuanto a material para cada
polígono. Es una tarea ardua pero lógicamente a más variedad de comportamientos más real será la escena. El funcionamiento es el normal en OpenGL. Cada vez que se llama a la correspondiente función se activan esos valores que no cambi -
arán hasta llamarla de nuevo con otros. Por tanto todo lo que se “renderice” a partir de una llamada heredará esas características. Para denir los materiales usaremos la función:
glMaterialfv(cara, característica, parámetro) Los parámetros pueden llevar los siguientes valores:
Cara: ♦
GL_FRONT
♦
GL_BACK
♦
GL_FRONT_AND_BACK
Característica: 73
Capítulo 4 - Color, Materiales e Iluminación
♦
GL_DIFFUSE
♦
GL_AMBIENT
♦
GL_AMBIENT_AND_DIFFUSE
♦
GL_EMISSION
♦
GL_SPECULAR
♦
GL_SHININESS
Parámetro: Aquí ponemos los valores que queremos para el tipo denido. Tendremos que denir los valores para RGB, menos para GL_SHININESS que tendrá un valor entre 0 y 128. OpenGL también permite denir supercies que tengan componentes emi sivos que caracterizan fuente auto luminosas. Este método es útil si se quiere que una fuente de luz aparezca en la imagen. Este término no está afectado por ninguna otra de las fuentes de luz, y no afecta ninguna otra supercie. Agrega un color jo a las supercies y está especi -
cada de manera similar a las demás propiedades materiales. Por ejemplo: GLoat emission[]={0.0, 0.3, 0.3};
glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, emission; dene una pequeña cantidad de emisión azul-verde (cian).
4.4
Estableciendo el Modelo de Iluminación
Con OpenGL podemos manipular la luz y los objetos en una escena para crear diferentes clases de efectos.
Cuando iluminamos una escena el resultado de la iluminación depende de qué luz usamos y como los objetos de la escena reejan o absorben la luz.
4.4.1 Luz Ambiente La luz ambiente es aquella que proviene de una fuente que ha sido tan disipada
por el entorno que es imposible determinar su dirección. Cuando una luz ambiente golpea una supercie, esta es disipada igualmente en todas direcciones.
74
Capítulo 4 - Color, Materiales e Iluminación
Cada fuente de luz puede contribuir a la luz ambiente de la escena. Puede haber otra luz ambiente que no viene de una fuente en particular. Para especicar la intensidad RGBA de esa luz global usamos el parámetro: ♦
Para indicar a OpenGL que ha de realizar los cálculos de iluminación: glEnable (GL_LIGHTING)
♦
Para seleccionar el modelo de iluminación ambiente activo: void glLightModelfv (GL_LIGHT_MODEL_AMBIENT, GLoat params[4])
♦
Para establecer el material activo: void glMaterialfv (Glenum cara, Glenum nombre, GLoat params[4])
Donde cara, tiene los siguientes parámetros: ♦
GL_FRONT_AND_BACK
♦
GL_BACK
♦
GL_FRONT
Nombre: ♦
GL_SPECULAR
♦
GL_DIFFUSE
♦
GL_AMBIENT
La luz ambiental ilumina los objetos en todas las supercies y en todas las direcciones. Los objetos son siempre visibles y coloreados (o sombreados) inde -
pendientes de su rotación o ángulo de visualización. Se puede interpretar como un “factor de brillo global” apli cado por una fuente de luz.
Un ejemplo con Luz ambiente sería el siguiente: // Activar los cálculos de iluminación glEnable (GL_LIGHTING);
75
Capítulo 4 - Color, Materiales e Iluminación
// Seleccionar la luz ambiente GLoat LuzAmbiente[4] = {1.0, 1.0, 0.0, 1.0}; glLightModelfv (GL_LIGHT_MODEL_AMBIENT, LuzAmbiente); // Seleccionar el material GLoat MaterialAmbiente[4] = {1.0, 0.5, 0.5, 1.0}; glMaterialfv (GL_FRONT, GL_AMBIENT, MaterialAmbiente); // Dibujar el objeto glBegin (..) ...
Aquí diseñamos el objeto, y sus parámetros. ...
glEnd();
4.4.2 Luz Posicional El segundo tipo referido se conoce como fuente de luz posicional, ya que su pos ición exacta dentro de la escena determina el efecto que tiene sobre esta, especí -
camente, la dirección desde la cual vienen los rayos de luz. A la función glLight*() se le pasa un vector de cuatro valores (x,y,z,w) para el parámetro GL_POSITION. Si el último valor, w, es distinto de cero, la fuente de luz correspondiente es de tipo posicional y los valores (x,y,z) especican la localización de la fuente de luz.
Para luces en el mundo real, la intensidad de la luz decrece a medida que aumenta la distancia desde la fuente de luz. Ya que una luz direccional está in nitamente lejos, no tiene sentido atenuar su intensidad con la distancia, luego la
atenuación está desactivada para luz direccional. OpenGL atenúa una fuente de luz multiplicando la contribución de esa fuente por un factor de atenuación:
Donde: d : distancia entre la posición de la luz y el vértice c k : GL_CONSTANT_ATTENUATION l k : GL_LINEAR_ATTENUATION q k : GL_QUADRATIC_ATTENUATION
76
Capítulo 4 - Color, Materiales e Iluminación
Una luz posicional irradia en todas las direcciones, pero se puede restringir esto de forma que se produzca un cono de luz deniendo lo que se conoce como una luz tipo spotlight (por ejemplo la lámpara, gura 3.). Por lo tanto, para denir un spotlight hay que determinar la apertura deseada
del cono de luz. (Recordar que, puesto que las spotlights son luces posicionales, hay que darles una localización). Para especicar el ángulo entre el eje del cono y un rayo a lo largo del borde del cono, usar el parámetro GL_SPOT_CUTOFF.
Figura 3. Signicado del parámetro GL_SPOT_CUTOFF
Por defecto el valor del parámetro es 180º, es decir, irradia en todas las
direcciones(360º). Los valores que puede tomar, a parte del particular 180, están comprendidos en el intervalo [0,90]. También hay que especicar la dirección del eje del cono de luz, para lo cual se utiliza el parámetro GL_SPOT_DIRECTION. Hay dos formas de controlar la intensidad de la distribución de la luz dentro del cono: ♦
Fijando el factor de atenuación descrito anteriormente, el cual es
♦
multiplicado por la intensidad de la luz. Fijando el parámetro GL_SPOT_EXPONENT que controla cómo es la luz de concentrada. La intensidad de la luz es más alta en el centro del cono. La luz se atenúa hacia los bordes del cono luz, luego a mayor exponente resulta en una fuente de luz más localizada.
4.4.3 Luz Direccional La luz direccional es la distancia innita de los objetos donde todos los rayos son
paralelos. Un vector puede ser utilizado para cada punto de la escena, la cual se ejecuta rápidamente comparándolo con otras luces. La luz direccional imita efectos
luminosos como el sol. El modelo empleado por OpenGL es el propuesto por Blinn-Phong (Phong 77
Capítulo 4 - Color, Materiales e Iluminación
simplicado). Phong, “el componente especular es proporcional al coseno entre el vector reexión de la luz y el vector del ojo”
L= vector desde la luz hasta el vértice N= normal de la supercie Eye= vector desde el vértice al ojo/cámara R= vector reejado de L con respecto a N
La luz que viene de una dirección y sus “rayos” son paralelos porque vienen de una fuente de luz muy lejana (innitamente lejana). En el mundo real lo más
parecido es la luz del sol. A OpenGL le indicamos que es una luz direccional cuando la cuarta coordenada de la posición de la luz es 0.0 (por ejemplo. “ GLoat posición [] = { 0.0, -1.0, 0.0, 0.0 } ;”. Las primeras tres coordenadas serán el vector
de dirección hacia donde alumbra (no tiene sentido que sea la posición si es direccional).
La implantación de los parámetros para luz direccional sería la siguiente manera:
78
Capítulo 4 - Color, Materiales e Iluminación
GLoat light_diffuse [4] = {1.0, 1.0, 1.0, 1.0 }; GLoat light_ambient [4] = {0.2, 0.2, 0.2, 1.0 }; GLoat light_specular [4]= {1.0, 1.0, 1.0, 1.0 }; GLoat light_position [4]= { 1.0, 1.0, 1.0, 0.0 }; glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diffuse ); glLightfv( GL_LIGHT0, GL_SPECULAR, light_specular ); glLightfv( GL_LIGHT0, GL_POSITION, light_position ); Donde: ♦
GL_AMBIENT: es la intensidad RGBA amiente de la fuente
♦
GL_DIFFUSE: intensidad RGBA difusa de la fuente
♦
GL_SPECULAR: intensidad RGBA especular de la fuente
♦
GL_POSITION: dirección de la fuente
4.5
Gestión de un Foco de Luz
Las luces se insertan en la escena igual que cualquier elemento geométrico, estando afectados del mismo modo por las transformaciones geométricas de modelado denidas. Esto permite controlar la posición de la luz, haciendo que permanezca ja, se mueva, o esté ligada a algún objeto de la escena.
La luz se inserta en el modelo cuando se le asigna posición, siendo la transformación geométrica activa en ese punto la que se le aplicaría. Un foco de luz en una escena, permite que una imagen no se vea negra. Para esto OpenGL ofrece cuatro comandos de luces; dos escalares y dos vectori -
ales. Un foco de luz cuenta con: ♦
Luz propia: que es proporcionada por un foco de luz bien situado, del cual conocemos su ubicación, y que emite sus rayos de luz de forma radial o divergente.
♦
Luz impropia: que emite sus rayos de luz desde una ubicación muy distante, de forma que podemos considerar sus rayos como
paralelos entre sí. Colocación de un foco de luz: ♦
Para colocar una fuente de luz en OpenGL: glLightfv (GL_LIGHT0, GL_POSITION,LightPos);
♦
Si queremos le podemos dar el efecto foco: Se configura el ángulo del cono de luz. glLight (GL_LIGHT0, GL_SPOT_CUTOFF, 60.0f);
79
Capítulo 4 - Color, Materiales e Iluminación
♦
Configura el brillo del mismo: glLight (GL_LIGHT0, GL_SPOT_EXPO NENT, 100.0f);
GL_SPOT_CUTOFF: especica el máximo ángulo de apertura de la fuente de luz en el rango [0,90]. Si el valor de cualquier objeto forma un ángulo con la dirección de la luz superior al ángulo de corte, el objeto no sera iluminado por dicha luz. GL_SPOT_EXPONENT: especifíca la distribución de intensidad de luz en el rango [0,128]. Al ser más alto el rango, más se concentra la intensidad de la luz en el cen -
tro de su área de proyección. GL_POSITION: aquí se necesitan 4 elementos para especicar la posición de la luz
en coordenadas homogéneas. Para ver como los focos de luz interaccionan en una escena hay que hablar de: ♦
Iluminación local: cómo se comporta cada superficie al ser ilumi nada de forma individual.
♦
Iluminación global: iluminación de un determinado objeto en una escena, teniendo en cuenta los rayos provenientes varias fuentes de luz y varios objetos.
4.6
Gestión de la atenuación de la intensidad de la luz
En las fuentes de luz reales, la intensidad de la luz decrece a medida que la distan cia desde la fuente de luz se incrementa. Este efecto es conocido como atenuación. Debido a que una luz direccional esta innitamente lejos, no es necesario
atenuar su intensidad respecto a su distancia, entonces la atenuación estaría deshabilitada para una luz direccional. Sin embargo, la atenuación es importante para dar realismo con luces posicionales. En OpenGL la atenuación de una intensidad de luz. Hay tres tipos de atenuación: ♦
GL_CONSTANT_ATTENUATION
♦
GL_LINEAR_ATTENUATION
♦
GL_QUADRATIC_ATTENUATION
Las funciones utilizadas para la gestión de atenuación de intensidad de la luz son: ♦
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
♦
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);
♦
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);
Los valores de las contribuciones de luz ambiente, difusa y especular son
atenuados, solo el valor de emisión y luz ambiente global no son atenuados. También es importante recalcar que al involucrar cálculos matemáticos adicionales, especialmente divisiones, para cada color, el uso de luces atenuadas afecta el rendimiento de la aplicación.
80
Capítulo 4 - Color, Materiales e Iluminación
Referencias Brian, D. (Octubre de 2008). ANÁLISIS Y ESTUDIO DE LA ILUMINACIÓN Y COLOR EN OPENGL. Recuperado el 2011, de http://repositorio.utn.edu.ec/bit stream/123456789/601/1/An%C3%A1lisis%20y%20Estudio%20de%20la%20 Iluminaci%C3%B3n%20y%20Color%20en%20OpenGL.pdf García, O., & Guevara, A. (2004). Introducción a la Programación Gráca con
OpenGL. Recuperado el agosto de 2011 Hearn, D. (2006). Grácos por Computadora con OpenGL. Madrid: Pearson.
Montoya, Y. (2003). Tecnicas Avanzadas de Animacion 3D - OpenGL. Recuperado el 2011, de http://docentes.umss.edu.bo/fcyt/ymontoya/materias/animacion3D/Tex toAnimacion.pdf
Morales, C. (9 de Octubre de 2002). Apuntes de OpenGL y GLUT. Obtenido de http://dac.escet.urjc.es/docencia/IG/03-OpenGL_Apuntes4.pdf OpenGL. (s.f.). The Industry’s Foundation for High Performance Graphics. Obtenido de http://www.opengl.org/ Weitzenfeld, A. (Noviembre de 19999). Iluminación y Sombreado - OpenGL. Recu perado el agosto de 2011, de http://cannes.itam.mx/Alfredo/Espaniol/Cursos/Gra ca/Sombreado.pdf
Taller Nº 8 #include #include #include #include
void init(void) {
GLoat GLoat GLoat GLoat GLoat
mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; brillo_specular_fuerte[] = { 5.0 }; mat_specular_ninguno[] = { 0.0, 0.0, 0.0, 1.0 }; mat_shininess[] = { 50.0 }; light_position[] = { 1.0, 1.0, 1.0, 0.0 };
GLoat white_light[] = { 1.0, 1.0, 1.0, 1.0 }; GLoat lmodel_ambient[] = { 0.5, 0.5, 0.5, 1.0 }; GLoat color_difuso_y_ambiente[]={0.1,0.5,0.8,1.0}; glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH);
81
Capítulo 4 - Color, Materiales e Iluminación
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glMaterialfv(GL_FRONT,GL_AMBIENT,color_difuso_y_ambiente); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); }
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidSphere(1.0, 20, 16); glFlush(); }
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-1.5, 1.5, -1.5*(GLoat)h/(GLoat)w, 1.5*(GLoat)h/(GLoat)w, -10.0, 10.0); else
glOrtho(-1.5*(GLoat)w/(GLoat)h, 1.5*(GLoat)w/(GLoat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }
int main(int argc, char** argv) {
glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]);
init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
82
Capítulo 4 - Color, Materiales e Iluminación
Resultado de la ejecución
Realice los siguientes cambios: Cambiar el argumento glMaterialfv(GL_FRONT, GL_SPECULAR, 1. mat_specular) por glMaterialfv(GL_FRONT, GL_SPECULAR, mat_
specular_ninguno) ¿Qué observa? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 2.
Cambiar el argumento glMaterialfv(GL_FRONT, GL_SHININESS,mat_ shininess)por glMaterialfv(GL_FRONT, GL_SHININESS,brillo_specu lar_fuerte ) ¿Qué observa?
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 3.
Cambiar el argumento glMaterialfv(GL_FRONT,GL_AMBIENT,color_ difuso_y_ambiente)por glMaterialfv(GL_FRONT,GL_DIFFUSE,
83
Capítulo 4 - Color, Materiales e Iluminación
color_difuso_y_ambiente ) ¿Qué observa?
_________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _______ _______________ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________
Ejercicio Nº 5 1. Métodos que se utilizan para sombrear polígonos. _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ 2. Función que es utilizada para asignar el modelo de sombreado suave suave.. _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ 3.
Características fundamentales para establecer las propiedades del material y defina el parámetro de esta función.
_________________________________________________________________ ________________________________ _________________________________ _______ _______________ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ ______________________________________________________________ ________________________________ ______________________________ _______ _______________ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ Como podemos definir una luz ambiente 4. _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________
_________________________________________________________________ ________________________________ _________________________________ 84
Capítulo 4 - Color, Materiales e Iluminación
_______ _______________ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ 5. Como podemos definir una luz direccional _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _______ _______________ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ 6. Como podemos definir una luz posicional _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _______ _______________ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________
85
<5> C a p í t u l o Trazado del Mapa de Textura OBJETIVOS: ♦ Presentar los comandos necesarios para aplicar una textura 2D sobre un polígono. ♦
♦
Uti tili liza zarr la las s fu func ncio ione nes s
de OpenGL para realizar una repetición de textura en los programas que se aplica una textura 2D sobre un polígono. Hacer uso de las rutinas de OpenGL para lograr el filtrado
♦
de una textura en el proceso de aplicación de una textura 2D sobre un polígono, Desc r ibi r las la fun fu ciones de OpenGL que establecen los parámetros de trazado de mapas de texturas.
DESCRIPCIÓN: En el capítulo se hará uso de los tres comandos que dispone OpenGL para aplicar una textura 2D sobre un polígono, y de los comandos que permiten modicar los distintos
parámetros que se utilizan en el proceso de aplica una textura 2D sobre un polígono. Adicionalmente, se presentan las funciones de
OpenGL que establecen los parámetros de trazado de mapas de texturas, se describe el proceso de ltrado de la textura que dispone OpenGL y que permite modicar los distintos
parámetros que se utilizan en el proceso de aplicación de una textura 2D sobre un polígono.
86
Capítulo 5 - Trazado del Mapa de Textura
5.
Trazado del Mapa de Texturas
5.1
Texturas 2D para polígonos
Existen cuatro tipos básicos de texturas en OpenGL GL_TEXTURE_1D, GL_TEXTURE _2D, GL_TEXTURE _3D y GL_TEXTURE_CUBE_MAP. Al igual que con iluminación, culling y otras propiedades, el texturizado puede ser activado y desactivado vía glEnable() y glDisable(), utilizando cualquiera de los cuatro tipos de textura. Se puede decir que para mostrar una textura en OpenGL hay que hacer cuatro cosas básicas:
1.
Cargar la textura desde algún lugar de almacenamiento, lo que implica leerla desde algún tipo de formato ( png, bmp, jpg, gif, etc ) y ponerla en memoria.
2.
Configurar las características de presentación de la textura, es decir,
como OpenGL debe interpretarla y mostrar la. 3.
Generar un objeto-textura y con esto es necesario obtener un identi ficador para ésta.
4.
Asociar la textura a una o varias primitivas, especificando para cada caso la forma en que debe ser mapeada.
El cargar una textura en un programa con openGL, se puede hacer por medio de la función: void glTexImage2D(GLenum target, GLint level, GLint internalformat, GL sizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data);
Los parámetros de la función son: ♦
Target: indica el tipo de textura a utilizar. Debe ser GL_TEXTURE_2D o GL_PROXY_TEXTURE_2D.
♦
♦ ♦ ♦ ♦ ♦
Level: nivel de detalle, permite determinar si el patrón de textu ra tiene distintas resoluciones. En el caso de utilizar una única resolución, esta debe ser 0. internalformat: Formato interno de la información suministrada en data. width: El ancho en pixeles de la textura. height: La altura en pixeles de la textura. border: Cantidad de pixeles a agregar horizontal y verticalmente en los bordes de la imagen, habitualmente es 0. format: Indica el formato de los elementos de la textura y puede tomar los valores: GL_COLOR_INDEX, GL_RGB, GL_RGBA, GL_RED, GL_ BLUE, GL_ALPHA, GL_LUMINACE_ALPHA.
87
Capítulo 5 - Trazado del Mapa de Textura
type: Tipo de representados, indica el tamaño de cada compo-
♦
nente de color, transparencia y/o luminancia.
data: Es el contenido de la imagen.
♦
Dentro de los tipos posibles a utilizar como target se encuentran: ♦
GL_TEXTURE_2D
♦
GL_TEXTURE_PROXY_2D
♦
GL_TEXTURE_PROXY_CUBE_MAP
O alguna de las seis caras del cube map ♦
GL_TEXTURE_CUBE_MAP_POSITIVE_X
♦
GL_TEXTURE_CUBE_MAP_POSITIVE_Y
♦
GL_TEXTURE_CUBE_MAP_POSITIVE_Z
♦
GL_TEXTURE_CUBE_MAP_NEGATIVE_X
♦
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
♦
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
Adicionalmente a estos el soporte para manejar texturas con compresión es proveído mediante el mecanismo de extensiones, para interpretar formatos particu lares. Mediante la función glCompressedTexImage2D() se puede crear la textura gl, que posee los mismos parámetros de la función sin compresión, excepto por el format que no se encuentra y que data debe apuntar a un bloque de memoria que representa la imagen con la compresión correspondiente a internalformat. Esta tabla muestra los valores más comunes de internalformat utilizados, denominados formatos internos base:
FORMATO INTERNO GL_ALPHA GL_DEPTH_COMPONENT GL_LUMINANCE GL_LUMINANCE_ALPHA GL_INTENSITY GL_RGB GL_RGBA
VALORES TOMADOS A Depth R R, A R R,G,B
VALORES Transparencia Profundidad
Luminosidad Luminosidad y transparencia Intensidad Red, Green, Blue (rojo, verde y
azul) Red, Green, Blue, Alpha (rojo,
R,G,B,A
verde, azul y transparencia)
Existe una extensa tabla que muestra todos los posibles valores de bits para cada una de las combinaciones entre los diferentes formatos base, por ejemplo
GL_RGB8 que indica que las componentes tendrán R-8 bits G-8 bits y B-8 bits. 88
Capítulo 5 - Trazado del Mapa de Textura
Mipmaps Un problema en los principios de la computación gráca en tiempo real, especial mente en los videojuegos era la “pixelación” de las texturas a medida que un obser -
vador se acercaba a una primitiva texturizada. En principio esto se puede solucionar utilizando texturas de alta resolución, pero estas a su vez crean el inconveniente de requerir mayor tiempo de procesamiento y espacio en memoria utilizar este tipo de texturas.
La solución (parcial) entonces es utilizar mipmaps, que básicamente son versiones escaladas de una misma textura que se mantienen en memoria, con el n de cambiar a texturas más pequeñas (baja resolución) cuando la vista del usuario está lejos del objeto texturizado y a mas altas resoluciones cuando este se
encuentra cerca, evitando así la pixelación y los usos altos de pr ocesamiento, pero consumiendo mas memoria, aproximadamente un tercio más que con la imagen de más alta resolución únicamente. La imagen muestra una serie de mipmaps desde la textura con mas resolución hasta la textura con menor resolución. Los mipmaps deben ser alimentados manualmente cambiando el parámetro level en glTexImage2d(), aunque glu también posee una utilidad para crearlos automáticamente mediante gluBuildMipmaps().
Mapeo de texturas Debido a una textura es una imagen rectangular y una primitiva no necesariamente lo es, se debe especicar la forma en que la textura se “acoplará” a
la primitiva, esto se hace suministrando la coordenada denominadas s, t (en los programas de diseño generalmente se denominan u,v ). Estas coordenadas se suministran para cada vértice mediante el comando:
glTextureCoord{1234}{sifd}( T coords) que para el caso de texturas bidimensionales tomaría la forma usual de glTexture2f(GLoat param1, GLoat param2); , mientras que los otros parámetros
corresponden a textura 3d (u=0) y escala (w = 0). 89
Capítulo 5 - Trazado del Mapa de Textura
La imagen muestra a la izquierda una textura en el espacio (s,t) y a la derecha un triángulo con la textura aplicada, mostrando las coordenadas (s,t) para cada vértice de la primitiva. El espacio (s,t) es normalizado, así que la textura sin importar el tamaño siempre va estar contenida entre las coordenadas otantes (0.0, 0.0) y
(1.0, 1.0). Para asociar las coordenadas de textura basta con dar las (s,t) antes de las de cada vértice dentro de los llamados glBegin() – glEnd().
Este ejemplo de texturas muestra un cubo texturizado a partir de rectángu -
los, variando para algunas caras las coordenadas de textura. Para dibujar un cuadrado 2D denido mediante las coordenadas (0,0), (0,1),
(1,1), (1,0) con una textura. Se asignan a los distintos vértices del cuadrado coordenadas de textura en el rango [0,3].
90
Capítulo 5 - Trazado del Mapa de Textura
glBegin(GL_POLYGON); glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0); glTexCoord2f(0.0, 3.0); glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 1.0); glTexCoord2f(3.0, 3.0); glVertex2f(1.0, 1.0); gltexCoord2f(3.0, 0.0); glVertex2f(1.0, 0.0); glEnd();
91
Capítulo 5 - Trazado del Mapa de Textura
Parámetros de textura Una vez cargada la textura, es posible ajustar algunos parámetros que modican
la manera en que será vista cuando se aplique sobre una primitiva, esto se hace mediante la función:
Void glTexParameterf( enum target, enum pname, enum tparam );
De nuevo target es GL_TEXTURE_2D para el caso que se está tratando, pname corresponde al nombre del parámetro a ajustar y tparam al valor de este parámetro, una lista de posibles valores se puede observar a continuación:
Pname
tparam
GL_TEXTURE_WRAP_S
GL_CLAMP, GL_CLAMP_TO_EDGE, GL_REPEAT, GL_ MIRRORED_REPEAT, GL_CLAMP_TO_BORDER GL_CLAMP, GL_CLAMP_TO_EDGE, GL_REPEAT, GL_ MIRRORED_REPEAT, GL_CLAMP_TO_BORDER GL_NEAREST, GL_LINEAR, GL_NEAREST_MIMPMAP_ NEAREAST, GL_NEAREST_MIPMAP_LINEAR, GL_LIN EAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR GL_NEAREST, GL_LINEAR
GL_TEXTURE_WRAP_T GL_TEXTURE_MIN_FILTER
GL_TEXTURE_MAG_FILTER
Texture Wrap Corresponde a GL_TEXTURE_WRAP_S y GL_TEXTURE_WRAP_T Este parámetro sirve para determinar la manera en que se verá la textura, si algún parámetro s o t es mayor a 1.0, los modos son: ♦
GL_CLAMP : Recorta la textura una vez esta supera las coordenadas 1.0 en (s,t), dependiendo de los ajustes en los estados (se puede
hacer independiente sobre s y t). ♦
GL_CLAMP_TO_EDGE: Similar a clamp, con la diferencia que no muest -
♦
rea el texel del borde. GL_CLAMP_TO_BORDER: Similar a clamp, pero se utiliza el pixel de los bordes, con lo que se extiende como “textura” sobre texels mayores a 1.0 .
♦
GL_REPEAT: Después de 1.0 bien sea en s y/o t de acuerdo al ajuste,
la textura se repite. ♦
GL_MIRRORED_REPEAT: Similar a repeat, pero la textura se alterna en
coordenadas, por lo que la textura aparece invertida.
92
Capítulo 5 - Trazado del Mapa de Textura
5.2
Filtrado de Una Textura
Cuando se aplica una textura a un polígono, y tras realizar la conversión de este al espacio de pantalla, difícilmente cada pixel en la textura se corresponde con un pixel de la imagen nal obtenida. Dependiendo de las transformaciones utilizadas y de las coordenadas de textura denidos, un pixel de la pantalla se corresponderá con una porción de la
textura. Esta porción puede abracar desde una pequeña parte de un pixel de textura(magnicación) hasta una gran colección de pixeles(minicación).
Para obtener el color del pixel en la imagen de la pantalla deberán interpolarse o promediarse los valores de los pixeles de textura implicados. Este proceso se conoce como ltrado de la textura.
Función glTexParameteri Establece lo parámetros de textura Cuando la imagen de la textura no se adecua con el tamaño de la supercie que se quiere cubrir, OpenGL utiliza unos ltros de textura para interpolar entre los píxeles de la imagen y adecuarla a la supercie
Sintaxis void WINAPI glTexParameteri( GLenum target, GLenum pname, GLint param );
Parametros target La textura objetivo ,que debe ser GL_TEXTURE_1D o GL_TEXTURE_2D.
pname La constante simbolica de un parámetro de la textura de un solo siguientes símbolos son aceptados en pname.
93
va lo r. Los
Capítulo 5 - Trazado del Mapa de Textura
Valor
Signicado Valor aceptado en param -La función de minicación
es usada cuando el pixel que está siendo texturando se mapen a un área mayor (elemento de textura). La supercie a la que se le aplique la
GL_NEAREST
GL_LINEAR textura es menor que la texGL_NEAREST_MIPMAP_NEAR tura que se va a aplicar.
GL_TEXTURE_MIN_ Un pixel de la imagen repreFILTER
EST
senta a muchos del espacio GL_NEAREST_MIPMAP_LINEAR de texturas. GL_LINEAR_MIPMAP_NEAREST Se utiliza cuando el patrón de GL_LINEAR_MIPMAP_LINEAR texturas deba ser reducido, para encajar en las coorde nadas especicas
La textura de magnicación
se utiliza cuando el pixel que se esta texturando se mapea a un área menor (elemento de textura). Cuando la supercie a la que
se le aplique la textura sea mayor que la imagen(textura) G L _ T E X T U R E _ M A G _ que se va a aplicar . Esta esFILTER
tablece la magnicación de textura a GL_NEAREST o GL_ LINEAR
Es utilizada por las rutinas de texturado cuando una sección del patrón de texturas deba agrandarse para enca jar en un rango de coordena das especicas
94
GL_NEAREST GL_LINEAR
Capítulo 5 - Trazado del Mapa de Textura
Para asignar un color a (por ejemplo) el pixel blanco de la gura, se pueden consid erar dos estrategias: ♦
Considerar exclusivamente el centro texel más cercano al pixel, y usar el color de dicho texel. En la figura, y para el pixel blanco, se
♦
usaría el texel que tiene inmediatamente encima y a la derecha. Considerar los cuatro centros de texels más cercanos al pixel, y realizar una mezcla ponderada (según la distancia) de los cuatro colores (equivale a una interpolación lineal). En la figura, y para el
pixel blanco, se usarían los cuatro texel unidos a el con líneas. La segunda opción es ligeramente más costosa en tiempo, pero produce mejores resultados. OpenGL provee la técnica conocida como mip-mapping para mejorar el ltrado de texturas cuando un pixel cubre muchos texels. La función glTexParameter sirve para especicar cuál de los dos modos an -
teriores se usará. Se puede usar un modo para cuando los pixeles son más grandes que los texels, y otro (o el mismo) para cuando ocurre lo contrario.
5.3
Aplicación de texturas 2D sobre Primitivas GLUT OpenGL incorpora la posibilidad de asignar las coordenadas de textura a los
vértices evaluando una función que depende de las posiciones de los vértices. Esto facilita la asignación de coordenadas de textura, y hace posible la evaluación de esta función por el hardware gráco, con la consiguiente mejora en el rendimiento. En este caso, las coordenadas de textura especicadas con glTexCoord2 se igno -
95
Capítulo 5 - Trazado del Mapa de Textura
ran. Esta funcionalidad (que llamaremos generación automática de coordenadas
de textura, GACT) puede activarse (o desactivarse) independiente para cada componente (s o t) del par de coordenadas de textura (s,t), usando la función glEnable (o glDisable) con las constantes GL_TEXTURE_GEN_S (coord. s) y GL_TEXTURE_GEN_T (coord. t). En nuestro caso, activaremos (o desactivaremos) esta capacidad para
ambas componentes simultáneamente). OpenGL incorpora tres posibles funciones (o modos) para GACT. Cuando
GACT está activada, la selección del modo a usar se hace invocando a glTexGen. Para cada componente (s o t) esta llamada permite elegir una de entre tres posibilidades, usando cada una de las tres constantes que se indican a continuación ♦
Relativo al objeto (GL_OBJECT_LINEAR) :La correspondiente coorde -
nada de textura se calcula como la distancia más corta desde el vértice al que queremos asignarle coordenadas hasta un plano determinado. Por defecto, para la coordenada S se usa el plano
X=0 (la coordenada de textura S es la coordenada X del vértice), y para la coordenada T se usa el plano Y=0 (la coord. de textura T es la coordenada Y del vértice). Además de esto, el plano usado puede cambiarse dando los coeficientes de su ecuación implícita
con glTexGen, si bien en esta práctica usaremos los planos por defecto. La coordenada del vértice que se usa es la especificada en glVertex antes de aplicarle las transformación de instanciación
(matriz model-view), con lo cual el sistema de coordenadas usado es el sistema de coordenadas del objeto, lo cual tiene el efecto, en la práctica, de que la textura se transforma solidariamente con el polígono y por tanto aparece como fijada al objeto. ♦
Relativo al observador (GL_EYE_LINEAR) :Este esquema es similar anterior excepto que se usan las coordenadas del vértice en el sis tema de coordenadas del observador (el eye coordinate system), es decir, se usa el vértice después de aplicarle matriz de transfor mación model-view. El efecto es que la textura aparece fija en el espacio, sin que le afecte la transformación del objeto.
♦
Mapa de entorno esférico (GL_SPHERE_MAP) Este esquema se puede usar para producir imágenes en las que las superficies aparecen como espejos reflectantes. La textura se usa como un mapa de entorno (environment map). Esto significa que la textura codifica
la irradiación entrante desde cualquier dirección posible. Cuando se usa este modo, OpenGL calcula el vector reflejado r respecto
del vector hacia el observador v (para ello se usa la normal n al vértice). El vector r se usa entonces para seleccionar un texel de la textura. La función que permite obtener el texel a partir de r está diseñada de forma que el mapa de entorno pueda obtenerse
96
Capítulo 5 - Trazado del Mapa de Textura
directamente de una fotografía de una bola con una superficie es pecular en la cual se refleje el entorno.
Sintaxis de glTexGen void glTexGen{ifd}{v}(GLenum coord, GLenum pname, TYPE param);
Parametro
Funcion
Valores posibles GL_S
indicar cuál de las coorde- GL_T nadas de textura debe GL_R generarse
coord,
GL_Q, GL_TEXTURE_GEN_MODE
pname
GL_OBJECT_PLANE GL_EYE_PLANE. GL_OBJECT_LINEAR, Si pname es GL_TEX- EYE_LINEAR TURE_GEN_MODE GL_SPHERE_MAP.
param
GL_
Ejemplo El siguiente ejemolo mustra el uso de las funciones para el trazado de texturas
#include #include #include #include
#ifdef _WIN32 #dene oorf(x) ((oat)oor((x))) #endif static static static #dene #dene
oat transx = 1.0, transy, rotx, roty; int ox = -1, oy = -1; int mot = 0; PAN 1 ROT 2
void pan(const int x, const int y) { transx += (x -ox)/5.; transy -= (y-oy)/5.; ox = x; oy = y;
97
Capítulo 5 - Trazado del Mapa de Textura
glutPostRedisplay();
}
void rotate(const int x, const int y) { rotx += x-ox; if (rotx > 360.) rotx -= 360.; else if (rotx < -360.) rotx += 360.; roty += y-oy; if (roty > 360.) roty -= 360.; else if (roty < -360.) roty += 360.; ox = x; oy = y; glutPostRedisplay(); }
void motion(int x, int y) { if (mot == PAN) pan(x, y); else if (mot == ROT) rotate(x,y); }
void mouse(int button, int state, int x, int y) { if(state == GLUT_DOWN) { switch(button) { case GLUT_LEFT_BUTTON: mot = PAN; motion(ox = x, oy = y); break; case GLUT_MIDDLE_BUTTON: mot = ROT; motion(ox = x, oy = y); break; case GLUT_RIGHT_BUTTON: break; }
} else if (state == GLUT_UP) mot = 0; }
#dene stripeImageWidth 32
98
Capítulo 5 - Trazado del Mapa de Textura
GLubyte stripeImage[4*stripeImageWidth]; void makeStripeImage(void) { int j; for (j = 0; j < stripeImageWidth; j++) { stripeImage[4*j] = (GLubyte) ((j<=4) ? 255 : 0); stripeImage[4*j+1] = (GLubyte) ((j>4) ? 255 : 0); stripeImage[4*j+2] = (GLubyte) 0; stripeImage[4*j+3] = (GLubyte) 255; } }
void hsv_to_rgb(oat h,oat s,oat v,oat *r,oat *g,oat *b) {
int i; oat f, p, q, t; h *= 360.0; if (s==0) { *r = v; *g = v; *b = v; } else {
if (h==360) h = 0; h /= 60; i = oorf(h); f = h - i; p = v*(1.0-s); q = v*(1.0-(s*f)); t = v*(1.0-(s*(1.0-f))); switch (i) { case 0 : *r = v; *g = t; *b = p; break; case 1 : *r = q; *g = v; *b = p; break;
99
Capítulo 5 - Trazado del Mapa de Textura
case 2 : *r = p; *g = v; *b = t; break; case 3 : *r = p; *g = q; *b = v; break; case 4 : *r = t; *g = p; *b = v; break; case 5 : *r = v; *g = p; *b = q; break;
} } }
GLubyte rainbow[4*stripeImageWidth]; void makeRainbow(void) { int j; for (j = 0; j < stripeImageWidth; j++) { oat r, g, b; hsv_to_rgb((oat)j/(stripeImageWidth-1.f), 1.0, 1.0, &r, &g, &b); rainbow[4*j] = r*255; rainbow[4*j+1] = g*255; rainbow[4*j+2] = b*255; rainbow[4*j+3] = (GLubyte) 255; } }
/* planes for texture coordinate generation */ static GLoat xequalzero[] = {1.0, 0.0, 0.0, 0.0}; static GLoat slanted[] = {1.0, 1.0, 1.0, 0.0}; static GLoat *currentCoeff; static GLenum currentPlane; static GLint currentGenMode;
100
Capítulo 5 - Trazado del Mapa de Textura
void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH);
makeStripeImage(); makeRainbow(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LIN -
EAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LIN EAR); glTexImage1D(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_ RGBA, GL_UNSIGNED_BYTE, stripeImage); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); currentCoeff = xequalzero; currentGenMode = GL_OBJECT_LINEAR; currentPlane = GL_OBJECT_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode); glTexGenfv(GL_S, currentPlane, currentCoeff);
glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_1D); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glFrontFace(GL_CW); glCullFace(GL_BACK); glMaterialf (GL_FRONT, GL_SHININESS, 64.0);
}
void tfunc(void) { static int state; if (state = 1) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_ REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,
101
Capítulo 5 - Trazado del Mapa de Textura
GL_LINEAR); glTexImage1D(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rainbow); } else {
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_ REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage1D(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); }
glutPostRedisplay();
}
void display(void) { static GLUquadric *q; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#if 0
glPushMatrix(); glTranslatef(0., 0., transx); glRotatef(rotx, 1.0, 0.0, 0.0); glRotatef(45.0, 0.0, 0.0, 1.0); glutSolidTeapot(2.0);
if (!q) q = gluNewQuadric(); gluQuadricTexture(q, GL_TRUE); gluCylinder(q, 1.0, 2.0, 3.0, 10, 10); #endif glPopMatrix(); glutSwapBuffers(); }
void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-3.5, 3.5, -3.5*(GLoat)h/(GLoat)w, 3.5*(GL oat)h/(GLoat)w, -3.5, 3.5);
else
glOrtho(-3.5*(GLoat)w/(GLoat)h,3.5*(GLoat)w/(GLoat)
102
Capítulo 5 - Trazado del Mapa de Textura
h, -3.5, 3.5, -3.5, 3.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }
/*ARGSUSED1*/ void keyboard (unsigned char key, int x, int y) { switch (key) { case ‘e’: case ‘E’: currentGenMode = GL_EYE_LINEAR; currentPlane = GL_EYE_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGen Mode); glTexGenfv(GL_S, currentPlane, currentCoeff); glutPostRedisplay(); break; case ‘o’: case ‘O’: currentGenMode = GL_OBJECT_LINEAR; currentPlane = GL_OBJECT_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGen Mode); glTexGenfv(GL_S, currentPlane, currentCoeff); glutPostRedisplay(); break; case ‘s’: case ‘S’: currentCoeff = slanted; glTexGenfv(GL_S, currentPlane, currentCoeff); glutPostRedisplay(); break; case ‘x’: case ‘X’: currentCoeff = xequalzero; glTexGenfv(GL_S, currentPlane, currentCoeff); glutPostRedisplay(); break; case ‘t’: tfunc(); break; case 27: exit(0); break;
103
Capítulo 5 - Trazado del Mapa de Textura
default: break; }
}
int main(int argc, char*argv[]) { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(512, 512); glutInitWindowPosition(100, 100); glutInit(&argc, argv); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glutMainLoop(); return 0; }
Resultado del Ejemplo Este ejemplo produce la siguiente imagen, la textura de la imagen se puede cam -
biar utilizando las teclas e, o, s, x, t. También se puede mover la iluminación utilizando el botón izquierdo del ratón y moviendo este en el sentido del eje Y.
104
Capítulo 5 - Trazado del Mapa de Textura
Referencias Hearn, D., & Baker, M. (2006). Gráfcos por Computadora con OpenGL. Madrid:
Pearson Prentice Hall. Microsoft. (9 de Julio de 2011). MSDN . Recuperado el 8 de Septiembre de 2011, de Microsoft Developer Network: http://msdn.microsoft.com/en-us/library/
dd368641(v=vs.85).aspx Universidad de Valencia. (s.f.). Recuperado el 5 de Septiembre de 2011, de Depar tamento de Informatica: http://informatica.uv.es/iiguia/AIG/docs/texturas.htm
Ureña, C. (2010). Universidad de Granada. Recuperado el 12 de Septiembre de 2011, de Departamento de Lenguajes y Sistemas Informaticos.: http://lsi.ugr. es/~curena/doce/vr/pracs.10-11/04/
105
Capítulo 5 - Trazado del Mapa de Textura
Taller Nº 9 Copie el siguiente código: #include #include #include #include
GLubyte texArray [32][32][4]; void iniciar () {
glClearColor(.5,0.2,0,0); gluOrtho2D(0,110,0,110); glFlush(); glutSwapBuffers();
}
void Dibuja() {
glClear(GL_COLOR_BUFFER_BIT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_ NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_ NEAREST); glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glTexImage2D (GL_TEXTURE_2D, 0, GL_INTENSITY, 32, 32, 1, GL_ RGBA, GL_BYTE, texArray) ; glEnable (GL_TEXTURE_2D);
glBegin (GL_QUADS); glColor3f(1,0,1); glTexCoord2f (0.0, glVertex2f (100,100); glColor3f(0,1,0); glTexCoord2f (1.0, glVertex2f (100,10); glColor3f(0,0,1); glTexCoord2f (1.0, glVertex2f (10,10); glColor3f(1,1,0); glTexCoord2f (0.0, glVertex2f (10,100);
0.0);
0.0);
1.0);
1.0);
106
Capítulo 5 - Trazado del Mapa de Textura
glEnd ( ); glDisable (GL_TEXTURE_2D);
glFlush(); glutSwapBuffers();
}
void almacenarDatosTex () {
int x, y, z; for (z = 0; z < 4; z++){ for (x = 0; x < 32 ; x ++){ for ( y = 0 ; y < 32 ; y++){ if( (x + y + z) % 2 == 0) texArray[x][y][z] = 55;
else
texArray[x][y][z] = 100; } } } }
int main( int argc, char *argv[]) {
almacenarDatosTex(); glutInit( &argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(0,0); glutInitWindowSize( 500, 500); glutCreateWindow(“Detalles de Texturas”); iniciar(); glutDisplayFunc( Dibuja); glutMainLoop(); return 0; }
En el fragmento de código: glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, 32, 32, 1, GL_RGBA, GL_BYTE, texArray) ; cambie el valor del elemento GL_INTENSITY por: 3, 4, GL_RGBA, GL_LU MINACE4, GL_RGB12.
Anote sus observaciones En el fragmento de código:
107
Capítulo 5 - Trazado del Mapa de Textura glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, 32, 32, 1, GL_RGBA, GL_BYTE, texArray) ;cambie el valor del elemento GL_BYTE por: GL_BITMAP, GL_SHORT,
GL_UNSIGNED_SHORT. Anote sus resultados En la función almacenarDatosTex Remplace su código por el siguiente:
int x, y, z; for (z = 0; z < 4; z++){ for (x = 0; x < 32 ; x ++){ for ( y = 0 ; y < 32 ; y++){ if( (x + y + z) % 2 == 0) texArray[x][y][z] = 0; if( (x + y + z) % 3 == 0) texArray[x][y][z] = 25; if( (x + y + z) % 4 == 0) texArray[x][y][z] = 50; if( (x + y + z) % 5 == 0) texArray[x][y][z] = 75;
else
texArray[x][y][z] = 100; } } }
Anote sus observaciones.
Taller Nº 10 Copie el siguiente código: #include #include #include #include
void iniciar () {
//glClearColor(1,0.2,0,0); glClearColor(0.0,1.0,0.0,1.0); gluOrtho2D(0,110,0,110); glFlush(); glutSwapBuffers();
}
void Dibuja()
108
Capítulo 5 - Trazado del Mapa de Textura
{
GLint k; GLubyte texLine [16]; // Matriz de texturas de 16 elementos. /* Denir dos elementos verdes para el patrón de textura. /* Cada color de textura se especica en cuatro posiciones de la matriz. */
for (k = 0; k <= 2; k += 2){ texLine[4*k] = 0; texLine [4*k+1] = 255; texLine [4*k + 2] = 0 ; texLine [4*k + 3] = 255; }
/*
Denir dos elementos rojos para el patrón de textura. */ for (k = 1;k<=3;k+=2){ texLine [4*k] = 255; texLine [4*k+1]= 00; texLine [4*k + 2]= 0; texLine [4*k + 3]= 255; }
glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_ NEAREST) ; glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_ NEAREST) ; glTexImage1D (GL_TEXTURE_1D, 0, GL_RGBA, 4, 0, GL_RGBA, GL_ UNSIGNED_BYTE, texLine); glEnable (GL_TEXTURE_1D) ; /* Asignar el rango completo de colores de textura a un segmento de línea. */
glLineWidth(40.0); glBegin (GL_LINES) ; glTexCoord1f (0.0); glVertex3f (10,10,0) ; glTexCoord1f (1.0) ; glVertex3f (100,100,0) ; glEnd ( ) ; glDisable (GL_TEXTURE_1D) ; glFlush(); glutSwapBuffers();
}
int main( int argc, char *argv[])
109
Capítulo 5 - Trazado del Mapa de Textura
{
glutInit( &argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(0,0); glutInitWindowSize( 500, 500); glutCreateWindow(“TEXTURAS EN LINEAS”); iniciar(); glutDisplayFunc( Dibuja); glutMainLoop(); return 0;
}
Modique el fragmento de código
glBegin (GL_LINES) ; glTexCoord1f (0.0); glVertex3f (10,10,0) ; glTexCoord1f (1.0) ; glVertex3f (100,100,0) ; glEnd ( ) ; Cada ejercicio inicia con este código
♦
Cambie las líneas glTexCoord1f (0.0); y glTexCoord1f (1.0) ; por glTexCoord1f (-2.0); y glTexCoord1f (1.0) ;, respectivamente
♦
Cambie las líneas glTexCoord1f (0.0); y glTexCoord1f (1.0) ; por glTexCoord1f (1.0); y glTexCoord1f (-2.0) ;, respectivamente
♦
Cambie las líneas glTexCoord1f (0.0); y glTexCoord1f (1.0) ; por glTexCoord1f (0.0); y glTexCoord1f (-16.0) ;, respectivamente
♦
Cambie las líneas glTexCoord1f (0.0); y glTexCoord1f (1.0) ; por glTexCoord1f (-14.0); y glTexCoord1f (1.0) ;, respectivamente
Anote sus observaciones en cada caso.
110
Capítulo 5 - Traz Trazado ado del Mapa de Textura
Ejercicio Nº 6 1. Mencione y explique los 4 aspectos fundamentales para utilizar una textura en OpenGL:
_________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ 2.
Nombre de la función que permite se ajusten los parámetros que mod ifican y son utilizados en una textura:
_________________________________________________________________ ________________________________ _________________________________
Explique en qué consiste el filtrado de una textura: 3. _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _______________ _______ _______________ _______________ ________________ _______________ _______________ ________________ ____________ ____ _________________________________________________________________ ________________________________ _________________________________
4. Mencione las 3 funciones que OpenGL incorpora para GACT: _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ 5. Explique el uso de la función glTexParametri: glTexParametri: _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________ _________________________________________________________________ ________________________________ _________________________________
111
<6> C a p í t u l o Aspectos avanzados de OpenGL OBJETIVOS: ♦ Presentar los pasos necesarios para crear e invocar una lista de visualización. ♦
♦
Se hará uso de una lista de visualización,
y comandos para la eliminación de caras traseras. Proporcionar las órdenes de OpenGL
es decir de un grupo de funciones OpenGL que han sido almacenadas para su ejecución
escalera o aliasing. Mostrar los comandos OpenGL que permite la realización de trabajos con varias áreas de dibujo.
♦
En el capitulo presentamos las diferentes primitivas de dibujos que ayudaran a mejo rar la eciencia de nuestras aplicaciones.
Defi De fini nirr la las s fu fun nci cion ones es
para evitar el efecto ♦
DESCRIPCIÓN:
Describir los comandos de OpenGL para guardar el contenido
posterior, y que cuando se invoca una lista de visualización las funciones que la forman se ejecutan en el mismo orden en que fuer -
on almacenadas. Y, la eliminación de caras traserasSe presentan los comandos para denir el efecto escalera o aliasing, las fun ciones Glutidlefunc y Gluttimer: se hace uso de las funciones que permiten dividir el área de la ventana en varías subáreas con el n n de
mostrar a los mismos tiempos distintos vistas y del conjunto de instrucciones para añadir
menús desplegables a una aplicación. Se us-
de la ventana gráfica en un fichero y recu -
aran las funciones para guardar el contenido de la ventana gráca en un chero, como mostrar la imagen que contiene en chero en una ventana, y la denición de vectores de
perar imágenes.
vértices y niebla.
112
Capítulo 6 - Aspectos avanzados de OpenGL
6.
Aspectos Avanzados de OpenGL
6.1
Geometrías de las primitivas de los dibujos ecientes
En algunas aplicaciones con OpenGL se requiere dibujar tiras de segmentos de
líneas, lazos de segmentos de líneas, tiras de triángulos, abanicos de triángulos, tiras de romboides. Para lograrlo, se usa la función de OpenGL void glVertex[2 3 4] {s i d f} [v] (TYPE coordenadas) que es la que dene los vértices que especican la
geometría de las primitivas básicas de OpenGL. El código que describe la geometría de las primitivas ecientes se especica entre llamadas a las funciones, void glBegin(GLenum modo) y void glEnd(void) donde glEnum modo indica el tipo de primitivas pudiendo ser: ♦
GL_LINE_LOOP: Lazo de segmentos de líneas
♦
GL_LINE_STRIP : Tira de segmento de línea
♦
GL_QUAD_STRIP : Tira de romboides
♦
GL_TRIANGLE_FAN : Abanico de triángulos
♦
GL_TRIANGLE_STRIP : Tira de triángulos
Se debe tener presente que los segmentos de línea se dibujan con el último
color seleccionado, el último grosor seleccionado y el último patrón de líneas seleccionado. El segmento de código que se presenta a continuación indica cómo se dibuja la geometría de las primitivas ecientes:
void dibuja() {
Gloat v[8][2] ={{0.0f,0.0f},{ ={{0.0f,0.0f},{0.1f,1.0f},{0.9f, 0.1f,1.0f},{0.9f,0.2f},{1.1f,1.1f 0.2f},{1.1f,1.1f},{ },{ 1.9f,0.3f}{1.8f,0.9f},{2.7f,0.0f} 1.9f,0.3f}{1.8f, 0.9f},{2.7f,0.0f},{2.9f,1.2f}}; ,{2.9f,1.2f}}; glPushMatrix(); glTranslate(4.0,2.0,0.0); glBegin(GL_LINE_LOOP); glVertex2fv(v[0]); glVertex2fv(v[0] ); glVertex2fv(v[1]; glVertex2fv(v[1];) ) glVertex2fv(v[3]); glVertex2fv(v[3] ); glVertex2fv(v[5]; glVertex2fv(v[5];) ) glVertex2fv(v[7]); glVertex2fv(v[7] ); glVertex2fv(v[6]; glVertex2fv(v[6];) ) glVertex2fv(v[4]); glVertex2fv(v[4] ); glVertex2fv(v[2]; glVertex2fv(v[2];) ) glEnd(); glPopMatrix(); …
glPushMatrix(); glTranslate(2.0,-2.6,0.0); glBegin(GL_QUAD_STRIP); glVertex2fv(v[0]); glVertex2fv(v[0] ); glVertex2fv(v[1]; glVertex2fv(v[1];) ) glVertex2fv(v[2]); glVertex2fv(v[2] ); glVertex2fv(v[3]; glVertex2fv(v[3];) )
113
Capítulo 6 - Aspectos avanzados de OpenGL
glVertex2fv(v[4]); glVertex2fv(v[5];) glVertex2fv(v[6]); glVertex2fv(v[7];) glEnd(); glPopMatrix(); }
6.2
Lista de Visualización
Una lista de visualización o display list es un conjunto de comandos que se al macenan para ser ejecutados posteriormente. La mayoría de los comandos de OpenGL se pueden ejecutar de dos maneras: ♦
Modo inmediato: Los comandos se ejecutan conforme se encuen tran en el programa. Hasta ahora todos los ejemplos vistos se eje -
cutan de modo inmediato. ♦
Modo diferido: Los comandos se almacenan en una lista de visual ización y son ejecutados en otro punto del programa
Los modos de ejecución no son excluyentes, es decir, en un mismo pro grama pueden aparecen comandos que se ejecuten en modo inmediato y en modo diferido. Para crear una lista de visualización utilizamos las funciones: ♦
gl NewList: marca el inicio del conjunto de funciones que se alma -
cenan en la lista ♦
glEndList : marca el final del conjunto de funciones que se alma -
cenan en la lista. En la función, void glNewList (GLuint lista, GLenum modo) , la lista es un entero que identica a la lista, y debe ser único, y el modo, que indica el modo de la lista. Puede ser GL_COMPILE (sólo compila la lista) o GL_COMPILE_AND_EXECUTE (la compila y la ejecuta a la vez). Y la función void glEndList (void) , indica el nal de
la lista de visualización.
Ejemplo: glNewList (1, GL_COMPILE) glColor3f (1.0, 0.0, 0.0); glBegin (GL_POLYGON) glVertex3f (50.0, 100.0, 50.0); glVertex3f (100.0, 200.0, 10.0); glVertex3f (10.0, 200.0, 50.0); glEnd (); glTranslatef (3.0, 0.0, 0.0); glEndList ();
114
Capítulo 6 - Aspectos avanzados de OpenGL
El uso de listas de visualización resulta más rápido que la ejecución en modo inmediato y, por lo tanto, resulta conveniente utilizarlas. Además, facilitan el en capsulamiento y la reutilización de objetos. Creando una lista y ejecutándola donde
necesitemos, estamos realizando un encapsulamiento de las instrucciones que la componen. La ventaja principal de realizar este encapsulamiento con una lista de visualización en vez de con una función, es que las operaciones que incluye se
realizan al compilar la lista. En el siguiente ejemplo dibujamos un círculo en modo inmediato y utilizando
una lista de visualización. El cálculo de los vértices es un proceso computacionalmente costoso debido a las funciones trigonométricas que aparecen. La versión con lista de visualización resulta mucho más rápida al ejecutarla, puesto que los
cálculos se realizan en tiempo de compilación.
Ejemplo // Versión en modo inmediato dibujarCirculo () {
GLint i; GLoat coseno, seno; glBegin (GL_POLYGON); for (i=0; i<100; i++) {
coseno = cos (i*2*PI/100.0); seno = sin (i*2*PI/100.0); glVertex2f (coseno, seno); }
glEnd (); }// Versión con lista de visualización #dene LISTA_CIRCULO 1 dibujarCirculo () {
GLint i; GLoat coseno, seno; glNewList (LISTA_CIRCULO, GL_COMPILE); glBegin (GL_POLYGON); for (i=0; i<100; i++) {coseno = cos (i*2*PI/100.0); seno = sin (i*2*PI/100.0);glVertex2f (coseno, seno);} glEnd (); glEndList (); }
115
Capítulo 6 - Aspectos avanzados de OpenGL
Después de a ver creado la lista de visualización, podemos ejecutarla en cualquier lugar del programa, y tantas veces como queramos. La función que la ejecuta es glCallList. En la función void glCallList (GLuint lista) , la lista identica la lista. En el ejemplo siguiente, aplicamos la función glCallList.
Ejemplo main () { ...
// Crear la lista de visualización dibujarCirculo (); ...
// Ejecutar la lista de visualización glCallList (LISTA_CIRCULO); ...
glCallList (LISTA_CIRCULO); ... }
El incremento en la velocidad de proceso que se produce al utilizar listas de visualización, depende de la implementación concreta de OpenGL y del hardware sobre el que esté instalado. En cualquier caso, como mínimo el uso de listas de visualización es tan rápido como el modo inmediato. Por otro lado, debemos tener en cuenta al utilizar listas de visualización, que algunos comandos son sensibles al contexto. Además, los cambios que se produzcan en el contexto dentro de la lista, repercutirán a continuación en los demás comandos, estén dentro de una lista o se ejecuten en modo inmediato. En el siguiente ejemplo, la instrucción glTranslatef, hace que cada vez que se ejecuta la lista, se acumule una traslación en la matriz de modelo y vista y que, por lo tanto, los objetos que se dibujen a continuación, incluso la propia lista si se eje cuta de nuevo, sufran esta traslación. De igual manera, el cambio de color afecta a todos los objetos que se ejecuten a continuación.
Ejemplo void creaTriangulo () {
glNewList (1, GL_COMPILE); glColor3f (1, 0, 0);
116
Capítulo 6 - Aspectos avanzados de OpenGL
glBegin (GL_TRIANGLES); glVertex2f (0, 0); glVertex2f (1, 0); glVertex2f (0, 1); glEnd (); glTraslatef (1.5, 0, 0); glEndList (); }
Para conseguir que no se altere el contexto, debemos utilizar las funciones: ♦
gl PushMat ri x
♦
glPopMatrix
♦
glPushAttrib
♦
glPopAttrib.
Ejemplo void crearTriangulo () {
glNewList (1, GL_COMPILE); glPushMatrix (); glPushAttrib (GL_CURRENT_BIT); glColor3f (1, 0, 0); glBegin (GL_TRIANGLES); glVertex2f (0, 0); glVertex2f (1, 0); glVertex2f (0, 1); glEnd (); glTraslatef (1.5, 0, 0); glPopAttrib (); glPopMatrix (); glEndList (); }
Debemos destacar que no todas las funciones de OpenGL pueden guard arse en una lista de visualización, esto ocurre con las funciones que pasan algún parámetro por referencia, o que devuelven un valor.
Estas funciones son: ♦
glDeleteList
♦
glFeedbackBuffer
117
Capítulo 6 - Aspectos avanzados de OpenGL
♦
glFinish
♦
glFlush
♦
glGenLists
♦
glGet
♦
glIsEnabled
♦
glIsList
♦
glPixelStore
♦
glReadPixels
♦
glRenderMode
♦
glSelectBuffer
Si se incluye alguna de estas funciones, se ejecutará durante la creación
(compilación) de la lista, pero no se almacenará en la misma. Es posible crear listas jerárquicas, es decir, listas que ejecutan otras listas. Las listas jerárquicas son muy útiles cuando estamos deniendo objetos formados por varias componentes, espe -
cialmente si algunas de ellas se repiten varias veces. En el siguiente ejemplo, empleamos una lista de visualización para crear una bicicleta, suponiendo que creamos otras listas para denir el pedal, el cuadro y las
ruedas.
Ejemplo #dene PEDAL 1 #dene CUADRO 2 #dene RUEDA 3 #dene BICICLETA 4 glNewList (PEDAL, GL_COMPILE); ...
glEndList (); glNewList (CUADRO, GL_COMPILE); ...
glEndList (); glNewList (RUEDA, GL_COMPILE); ...
glEndList (); glNewList (BICICLETA, GL_COMPILE); glCallList (PEDAL); glCallList (CUADRO); glTranslatef (1.0, 0.0, 0.0); glCallList (RUEDA);
118
Capítulo 6 - Aspectos avanzados de OpenGL
glTranslatef (3.0, 0.0, 0.0); glCallList (RUEDA); glEndList () Los identicadores de las listas de visualización deben ser enteros positivos
únicos, lo que implica que debemos tener un especial cuidado es no duplicar índices. Cuando se manejan muchas listas de visualización puede ser útil recurrir a las siguientes funciones determinadas de OpenGL que proporcionan índices de listas de visualización no utilizados: GLuint glGenLists (GLsizei rango): el rango es el número de ín dices que queremos obtener. Esta función nos proporciona tantos
♦
índices para listas de visualización no usados como indiquemos con el parámetro rango. Devuelve el primer índice vacío y éste junto con los demás, que son correlativos, se marcan como ocu pados. ♦
GLboolean glIsList (GLuint indice) : el índice, como su palabra lo
♦
dice, sería el índice de la lista. Indica si el índice está usado. glDeleteLists (GLuint indice, GLsizei rango) , el índice, sería el índice inicial, rango: número de índices que queremos borrar. Esta función borra un conjunto de listas de visualización correlativas, definidas a partir de un índice inicial y un rango.
Ejemplo GLuint indiceLista; indiceLista = glGenLists (1); if (glIsList (indiceLista)) {
glNewList (indiceLista, GL_COMPILE); ...
glEndList(); }...
glDeleteLists (indiceLista, 1); OpenGL proporciona también la posibilidad de ejecutar varias listas de visu -
alización con una única llamada. Para ello es necesario guardar los índices en un array (que puede ser de cualquier tipo) y utilizar las siguientes funciones:
void glCallLists (GLsize n, GLenum tipo, const GLvoid *listas):
119
Capítulo 6 - Aspectos avanzados de OpenGL
Donde n, sería el número de elementos del array de índices de listas, el tipo, sería el tipo de datos del array. Puede ser GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_ UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, GL_2_BYTES, GL_3_BYTES o GL_4_BYTES, y las listas, son array de índices de las listas. Esta función ejecuta un conjunto de listas de visualización cuyos índices se encuentran en el array listas. void glListBase (GLuint base) :
La base es el valor del offset, el cual ja un valor como offset que debe añadirse a los índices del array que se ejecuta con glCallLists. La ejecución de varias listas con glCallLists se utiliza, por ejemplo, para escribir texto. En el siguiente ejemplo, tenemos una función que crea una lista de visual ización para cada letra del alfabeto. Una segunda función escribe una cadena de
caracteres utilizando llamadas alas listas de visualización correspondientes.
Ejemplo GLuint CrearFuente () {
GLuint fuente; fuente = glGenLists (26); /* Crear lista para la letra A */ glNewList (fuente, GL_COMPILE); . ...
glEndList(); /* Crear lista para la letra B */ glNewList (fuente+1, GL_COMPILE); ...
glEndList(); ...
return (fuente); }void EscribirCadena (GLuint fuente, char *cadena) {
if (fuente == 0 || cadena == NULL) return; /* Se pone como base el primer índice de la fuente y le restamos 65. Así, para la A (código ASCII 65), se mostrará la primera lista, para la B la segunda ... */ glListBase (fuente-65); glCallLists (strlen (cadena), GL_UNSIGNED_BYTE, cadena); }main ()
120
Capítulo 6 - Aspectos avanzados de OpenGL
{ ...
GLuint fuente; fuente = CrearFuente (); EscribirCadena (fuente, “OPENGL”);
...
6.3
Especicación de eliminación de caras traseras
Dado un conjunto de objetos 3D y una especicación de la vista, se desea conocer las supercies de los objetos visibles desde la posición del observador. Si los ob jetos que utilizamos están cerrados, no poseen agujeros, podemos evitar el coste de dibujar las caras traseras que no son visibles por el observador La eliminación de caras posteriores se lleva a cabo mediante las funciones,
glEnable (GL_CULL_FACE); glCullFace (mode);
donde al parámetro mode se le asigna el valor GL_BACK. De hecho, podemos utilizar esta función para eliminar en su lugar las caras frontales, o podríamos incluso elimi nar tanto las caras frontales como las posteriores. Por ejemplo, si nuestra posición de visualización se encuentra dentro de un edicio, entonces lo que queremos es
ver las caras posteriores (el interior de las habitaciones). En este caso, podríamos asignar al parámetro mode el valor GL_FRONT o podríamos cambiar la denición de qué cara de los polígonos es la frontal utilizando la función glFrontFace que se explica más adelante. Entonces, si la posición de visualización se desplaza al exterior del edicio, podemos eliminar las caras posteriores de la imagen. Asimismo,
en algunas aplicaciones, puede que sólo queramos ver otras primitivas dentro de la escena, como los conjuntos de puntos y los segmentos de líneas individuales. En este caso, para eliminar todas las supercies poligonales de una escena, asig naríamos al parámetro mode la constante simbólica OpenGL GL_FRONT_AND_BACK. De manera predeterminada, el parámetro mode en la función glCullFace tiene el valor GL_BACK. Por tanto, si activamos la eliminación de caras posteriores mediante la función glEnable sin invocar explícita-mente la función glCullFace, se
eliminarán las caras posteriores de la escena. La rutina de eliminación se desactiva mediante, gIDisable
(GL_CULL_FACE);
La función de cara frontal de OpenGL Aunque, de manera predeterminada, la ordenación de los vértices de un polígono controla la identicación de las caras frontal y trasera, podemos etiquetar de for ma independiente las supercies seleccionadas de una escena como frontales o traseras con la función: glFrontFace (vertexOrder);
121
Capítulo 6 - Aspectos avanzados de OpenGL
Si cambiamos el argumento vertexOrder a la constante de OpenGL GL_CW, un polígono denido a continuación con una ordenación de sus vértices en el sen tido de las agujas del reloj se considera que es de can frontal. Esta característica
de OpenGL se puede utilizar para intercambiar las caras de un polígono, en el que hayamos especicado sus vértices en el orden correspondiente al sentido horario. La constante GL_CCW etiqueta una ordenación de los vértices en sentido contrario a las agujas del reloj como de cara frontal, que es LA ordenación predeterminada.
Si denimos esa cara como ABC, el sentido de giro será como las agujas del reloj. Si seguimos la regla de la mano derecha, la cara frontal queda hacia dentro de la pantalla. Si denimos la cara como CBA, ocurre al contrario, la cara frontal es
la que nosotros vemos.
6.4
El efecto fusión en OpenGL
OpenGL provee una serie de funciones que ayudan a evitar el efecto que se pro duce al asignar a un pixel el color de la primitiva que se está dibujando, sin tener en
cuenta si la primitiva cumple el total o solo parte del pixel. Para eliminar el efecto fusión, también conocido como (efecto escalera o antialiasing), el proceso utilizado por OpenGL consiste en calcular la supercie de
pixel que verdaderamente estaría cubierta por la geometría y, en modo RGBA, hacer el resto del pixel transparente. Cabe destacar que para que esto se logre, se requiere habilitar la transparencia y luego iniciar los parámetros necesarios. Los comandos establecidos son los siguientes:
122
Capítulo 6 - Aspectos avanzados de OpenGL glEnable(GL_BLEND) glBlendFunc(GLenun sfactor, GLenun dfactor);
♦
La orden glBlendFunc, establece los factores de origen y de des tino de la fusión de color.
♦
El primer parámetro de la orden sfactor indica la función de la fusión del color origen.
♦
El segundo parámetro, dfactor indica la función de fusión del color
♦
destino. Adicionalmente, hay que llamar a glEnable(GL_BLEND) para activar la función de fusión de color.
♦
Las configuraciones predeterminadas glBlendFunc(GL_ONE, GL_ZERO).
para
la
fusión
son
Ahora mostraremos una lista de factores de fusión validos: ♦
GL_ZERO
♦
GL_ONE
♦
GL_SRC_COLOR
♦
GL_ONE_MINUS_SRC_COLOR
♦
GL_DST_COLOR
♦
GL_ONE_MINUS_DST_COLOR
♦
GL_ONE_SRC_ALPHA
♦
GL_ONE_MINUS_SCR_ALPHA
♦
GL_DST_ALPHA
♦
GL_ONE_MINUS_DST_ALPHA
♦
GL_CONSTANT_COLOR
♦
GL_ONE_MINUS_CONSTANT_COLOR
♦
GL_CONSTANT_ALPHA
♦
GL_ONE_MINUS_CONSTANT_ALPHA
♦
GL_SRC_ALPHA_SATURATE
Es importante tener claro que en el momento que se desea aplicar los factores de fusión de OpenGL, el primer paso a realizar es habilitarlo con la función glEnable, enviándole como parámetros la geometría que se desea suavizar, de esta manera:
123
Capítulo 6 - Aspectos avanzados de OpenGL
♦
GL_POINT_SMOOTH,
♦
GL_LINE_SMOOTH,
♦
GL_POLYGON_SMOOTH,
♦
entre otras. Por ejemplo: glEnable(GL_LINE_SMOOTH). Ahora bien, Para mejorar la calidad del efecto fusión se utiliza la siguiente
rutina que permite controlar la relación entre calidad de la imagen y velocidad de dibujo: Void glHint(GLenum objetivo, Glenum modo);
La función glHint permite un control opcional de determinados comportami-
entos de interpretación. El parámetro objeto indica que comportamiento está siendo controlado y especica la calidad de la imagen de puntos, líneas y polígonos durante las opera ciones del efecto de fusión. Los valores posibles son: ♦
GL_POINT_SMOOTH_HINT
♦
GL_LINE_SMOOTH_HINT
♦
GL_POLYGON_SMOOTH_HINT
El parámetro modo puede ser: ♦
GL_FASTEST, Para indicar que se elige la opción más eficiente.
♦
GL_NICEST, Se elige la opción de mayor calidad.
♦
GL_DONT_CARE , Para no indicar ninguna referencia.
6.5
Uso de GlutIdleFunc y glutTimerFunc
6.5.1 Función GlutIdleFunc glutIdleFunc establece la devolución de llamada de espera global. glutIdleFunc vacío (void (* func) (void));
cional para que en un programa de GLUT se puedan realizar tareas de procesamiglutIdleFunc establece la devolución de llamada de espera global para ser fun
ento de fondo o una animación continua en los eventos del sistema de ventanas no se están recibiendo. Si está activado, el callback idle está continuamente llamado cuando los eventos no se están recibiendo. La rutina callback no tiene parámetros.
La ventana y menú actual no será cambiado antes de la devolución de llamada de inactividad. Programas con múltiples ventanas y / o menús debe establecer explícitamente la ventana actual y / o actuales del menú y no depender de su con -
124
Capítulo 6 - Aspectos avanzados de OpenGL
guración actual. El monto de la computación y la prestación a cabo en un callback idle de bería reducirse al mínimo para no afectar la respuesta interactiva del programa. En general, no más que un solo marco de la prestación debe hacerse en un callback
idle. Pasando NULL a glutIdleFunc se desactiva la generación de la devolución de llamada de inactividad.
6.5.2 Función GlutTimerFunc glutTimerFunc registra una devolución de llamada de temporizador que se activa en un número especicado de milisegundos. glutTimerFunc vacío (unsigned int milisegundos, void (* func) (int valor), valor); GlutTimerFunc registra la función de devolución de llamada del temporizador que
se activa por lo menos en milisegundos milisegundos. El parámetro valor a la devolución de llamada del temporizador será el valor del parámetro valor a glutTimerFunc. Devoluciones de llamadas de temporizador múltiples, a veces iguales o difer entes pueden ser registradas de forma simultánea. El número de milisegundos es un límite inferior en el tiempo antes que la
devolución de llamada se genera y se indica por unsigned int milisegundos. GLUT intenta entregar el temporizador de devolución de llamada tan pronto como sea posible después de la expiración del intervalo de tiempo de la devolución de llamada. No hay soporte para cancelar una devolución de llamada registrada. En su lugar, ignorar una devolución de llamada en función de su valor del parámetro cuan do se activa.
6.6
Denición de varias áreas de dibujo.
Es posible realizar tareas donde se quieran visualizar varias sub-áreas del dibujo al
mismo tiempo es decir que una misma ventana pueda dividirse mostrando visualizaciones diferentes. Como por ejemplo supongamos que hemos creado un progra ma de diseño de modelos 3D, sería posible visualizar cada una de sus perspectivas al mismo tiempo. El resultado de la proyección se ja mediante la llamada a la función glView port. Y el prototipo de esta función es la siguiente:
void glViewport (GLint x, GLint y, GLsizei ancho, GLsizei alto) Los parámetros x e y de esta función especican las esquina inferior izquierda de la vista dentro de la ventana, y los parámetros ancho y largo especican las dimen -
siones en pixeles de dicha área. Frecuentemente cuando se llama esta función con dos parejas de números
125
Capítulo 6 - Aspectos avanzados de OpenGL
especicando el área de dibujo en la ventana se produce un error, ya que en reali -
dad se trata de las dimensiones en lugar de un segundo punto. Luego de haber especicado el tipo de proyección, dibujada la escena, y lógicamente denido el área de dibujo; si lo que se desea es dividir el área de la
ventana para visualizar varias a la vez se deben seguir los siguientes pasos suponiendo que una misma ventana será dividida en dos sub-áreas: ♦
Definir el área de dibujo.
♦
Especifica la proyección.
♦
Dibuja la escena.
♦
Define el área de dibujo 2.
♦
Especifica la proyección.
♦
Dibuja la escena.
Esto se repite la cantidad de veces que se desea dividir el área de la ventana. Para realizar esto se debe considerar lo siguiente: ♦
Al trabajar con una sola área de dibujo, la función glViewport se llamara dentro de la rutina de eventos de la ventana, con la finali dad de que el área de dibujo se pueda redimensionar si el tamaño
de la ventana lo hace también. ♦
Cuando se trabaja con distintas áreas la función glViewport se lla -
mara cada vez que haya una área distinta y cada una de ellas debe ordenar que se dibuje la escena que le corresponda, por lo que se deberá indicar desde la rutina para dibujar la escena.
6.7 Tratamiento de imagines en OpenGL: Guardar y recuperar imagines. A lo largo de trabajar en OpenGL nos resulta necesario guardar lo que tenemos en nuestra ventana graca en un chero o mostrar la imagen que contiene en chero en una ventana gráca. En OpenGL lo podemos hacer transriendo de la memoria del sistema gráco a la memoria principal o de la memoria principal y luego hacia la memoria del sistema gráco. Este proceso de transferir los datos realiza en dos pasos: primero los datos se transere de la memoria del sistema gráco a la me moria principal y segundo los datos se transere de la memoria principal al archivo. Las funciones que nos permiten realizan estas tranferencias son glReadPixels y glDrawPixels. Para transferir los datos de la memoria del sistema gráco a la memoria prin cipal se utiliza la orden en OpenGL: void glReadPixels(GLint x, GLint y, GLsizei ancho, GLsizei alto,
126
Capítulo 6 - Aspectos avanzados de OpenGL GLenum format, GLenum tipo, GLvoid*pixeles);
Con esta orden podemos denir el área rectangular de nuestra ventana grá ca que deseamos transferir a la memoria principal.
Parámetros ♦
El parámetro x y el parámetro y se utilizan para definir el vértice inferior izquierdo en coordenadas de ventana.
♦
Los parámetros alto y ancho indican la altura y ancho del rectángulo de píxeles. Si se escribe en anchura y altura “1” como parámetros de valor, esto correspondera a un solo píxel.
♦
El parámetro formato nos indica de que elemento está formado un pixel. Se aceptan estos valores simbólicos:
Valor
Signicado
Los índices de color se leen de la memoria de color seGL_COLOR_INDEX
leccionado por glReadBuffer. Cada índice se convierte en punto jo, desplazado hacia la izquierda o derecha, de pendiendo del valor y el signo de GL_INDEX_SHIFT, y se añade a GL_INDEX_OFFSET. Si es GL_MAP_COLOR GL_TRUE ,
los índices son reemplazados por sus asignaciones en el GL_PIXEL_MAP_I_TO_I.
GL_STENCIL_INDEX
GL_DEPTH_COMPONENT
Stencil valores se leen desde el stencil buffer. Cada índice se convierte en punto jo, desplazado hacia la izquierda o derecha, dependiendo del valor y el signo de GL_INDEX_ SHIFT, y se añade a GL_INDEX_OFFSET. Si es GL_MAP_STENCIL GL_TRUE, los índices son reemplazados por sus asignaciones en el GL_PIXEL_MAP_S_TO_S. Los valores de profundidad se leen en el búfer de profundi dad. Cada componente se convierte en punto otante por ejemplo que los mapas de profundidad mínima de valor a
0.0 y los mapas de valor máximo de 1,0. Cada componente se multiplica por GL_DEPTH_SCALE, sumado a GL_DEPTH_ BIAS y, nalmente, anclada en el rango [0,1].
127
Capítulo 6 - Aspectos avanzados de OpenGL
Procesamiento diere dependiendo de si los índices de buffers de color almacenar el color o los componentes
RGBA de color. Si los índices de color se almacenan, se leen de la memoria de color seleccionado por glReadBuffer. Cada índice se convierte en punto jo, dependi endo del valor y el signo de GL_INDEX_SHIFT, y se añade GL_GREEN, a GL_INDEX_OFFSET. Los índices son luego reemplazados
GL_RED, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_BGR_EXT, GL_ BGRA_EXT, GL_LUMINANCE, GL_LUMINANCE_ALPHA
por el rojo, verde, azul y alfa obtenida por la indexación de los GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G, GL_ PIXEL_MAP_I_TO_B y tablas GL_PIXEL_MAP_I_TO_A. Si los componentes de color RGBA se almacenan en el buffer
de color, que se leen de la memoria de color seleccionado por glReadBuffer . Cada componente de color se convi erte a tal punto otante que los mapas de intensidad. Cada componente se multiplica por GL_c_SCALE y se añade a GL_c_BIAS, donde c es GL_RED, GL_GREEN, GL_BLUE y GL_ALPHA. Por último, si es GL_MAP_COLOR GL_TRUE , cada
componente de color c se sustituye por su asignación en la tabla GL_PIXEL_MAP_c_TO_c. ♦
El parámetro tipo se debe especificar de que tipo de elementos
consta cada pixel, debe ser uno de los siguientes valores.
Tipo
Índice de la máscara
GL_UNSIGNED_BYTE 2 8 1 GL_BYTE 271 GL_BITMAP GL_UNSIGNED_ SHORT GL_SHORT GL_UNSIGNED_INT_ GL_INT GL_FLOAT
♦
Componente de conversión (2 8 1) c [(2 7 1) c -1] / 2
1 2 16 1
1 (2 16 1) c
2 15 1 2 32 1 2 31 1 ninguno
[(2 15 1) c 1] / 2
(2 32 1) c [(2 31 1) c 1] / 2
c
Parámetro pixeles es un apuntador a los datos de pixeles en la imagen.
Función glDrawPixels Es la función que escribe en un bloque de píxeles para el framebuffer.
Para utilizarla es con la orden void glDrawPixels ( 128
Capítulo 6 - Aspectos avanzados de OpenGL GLsizei ancho, GLsizei alto, GLenum formato, GLenum tipo, const GLvoid píxeles * );
Parámetros ♦
♦ ♦
El parámetro Ancho se utiliza para asignar la dimensión de la anchura del rectángulo de píxeles que se escribirá en el uso de este dispositivo. El parámetro Alto es usado para asignar una altura al dispositivo. El parámetro formato se usa para asignar el formato de los datos en píxeles. Utiliza estas constantes:
Valor
Signicado
GL_COLOR_INDEX
Cada pixel es un valor único, un índice de color. La función glDrawPixels convierte cada pixel en formato de punto jo.
GL_STENCIL_INDEX
Cada pixel es un valor único, un índice de la plantilla.La función glDrawPixels convierte en formato de punto jo.
GL_DEPTH_COMPONENT
Cada pixel es un componente de un solo fondo. La función glDrawPixels convierte datos de coma otante directamente a un in terno de formato de punto otante con una precisión sin especicar.
Cada pixel es un grupo de cuatro compoGL_RGBA
nentes en este orden: rojo, verde, azul, alfa. Convierte valores de punto otante directa -
mente. Cada pixel es un componente rojo. La fun -
ción convierte este componente a lo interno GL_RED
en un punto otante de la misma manera que el componente rojo de un píxel es RGBA, y
luego lo convierte en un pixel RGBA con el conjunto verde y azul, después se lee como
un pixel RGBA. 129
Capítulo 6 - Aspectos avanzados de OpenGL
Cada pixel es un componente verde único. La función convierte este componente a lo interno en un punto otante de la misma GL_GREEN
manera que el componente verde de un píxel es RGBA, y luego lo convierte en un pixel RGBA con el conjunto rojo y azul, después
se lee como un pixel RGBA. función convierte este componente a lo in terno formato de punto otante de la misma
GL_BLUE
manera que el componente azul de un píxel es RGBA, y luego lo convierte en un pixel RGBA con el conjunto rojo y verde. La fun ción convierte este componente a lo interno en un punto otante de la misma manera que
el componente azul de un píxel es RGBA, y luego lo convierte en un pixel RGBA con el conjunto rojo y verde, después se lee como
un pixel RGBA. GL_ALPHA
Cada pixel es un componente alfa solo.
Cada pixel es un grupo de tres componentes GL_RGB
en este orden: rojo, verde, azul. La función glDrawPixels convierte cada componente a lo interno formato de punto otante de la misma manera que los componentes rojo,
GL_LUMINANCE
verde y azul de un píxel se RGBA. Cada pixel es un componente de luminancia solo. Cada pixel es un grupo de dos componentes
GL_LUMINANCE_ALPHA
en este orden: luminancia, la alfa.
Cada pixel es un grupo de tres componentes en este orden: azul, verde, rojo. GL_BGR_EXT proporciona un formato que coincida con GL_BGR_EXT
el diseño de memoria de Windows, mapas de bits independientes del dispositivo. Por lo tanto, las aplicaciones pueden utilizar los mismos datos con llamadas a funciones de Windows y las llamadas OpenGL pixel fun -
GL_BGRA_EXT
♦
ción. Cada pixel es un grupo de cuatro componentes en este orden: azul, verde, rojo, alfa.
El parámetro tipo se utiliza para especificar el formato de cada 130
Capítulo 6 - Aspectos avanzados de OpenGL
pixel. Se aceptan los siguientes:
Valor
GL_UNSIGNED_BYTE GL_BYTE GL_BITMAP GL_UNSIGNED_SHORT GL_SHORT GL_UNSIGNED_INT GL_INT GL_FLOAT ♦
6.8
Signicado
Sin signo de 8 bits sin signo Entero de 8 bits sin signo Bits individuales de 8 bits sin signo enteros Sin signo de 16 bits sin signo Entero de 16 bits sin signo Sin signo de 32 bits sin signo Entero de 32 bits Un solo punto otante de precisión
Parámetro pixeles es un puntero a los datos en pixeles. Especicación de los vectores de vértice en OpenGL.
Cuando se quiere dibujar primitivas geométricas en OpenGL, es necesario llamar a muchas funciones. Por ejemplo para dibujar un polígono de 20 bordes, necesitas llamar por lo menos a 22 funciones: una para llamar a glBegin(), una función para cada uno de los vértices, y para terminar la función de glEnd(). Y si se le quiere añadir más información como colores RBGA, índices de color y normales, para cada uno de los vértices; esto puede duplicar o triplicar el número de funciones que
se necesitarían llamar, para una solo primitiva geométrica. Y esto puede impedir la buena ejecución del programa y también a afectar el rendimiento del sistema.
Pero para evitar esto OpenGL tiene vectores de vértices que permite especicar un grupo de vértices relacionados en unos pocos arreglos y accediendo a los datos de estos. Esto nos da la opción de llamar a menos funciones. Hay tres pasos que se utilizan en la especicación de vectores de vértice son:
1.
Activar el vector apropiado, existen de diferentes tipos: en la sigu -
iente tabla se muestra la lista de vectores que pueden ser llamados en OpenGL. Vector GL_VERTEX_ARRAY GL_NORMAL_ARRAY GL_COLOR_ARRAY GL_INDEX_ARRAY GL_FOG_COORD_ARRAY GL_TEXTURE_COORD_ARRAY
Descripción Coordenadas de vértices Normales Colores RBGA Índice de color Coordenadas de niebla Coordenadas de textura 131
Capítulo 6 - Aspectos avanzados de OpenGL
Banderas de aristas de Polígonos Tabla 1: vectores que pueden ser llamados en OpenGL.
GL_EDGE_FLAG_ARRAY
En OpenGL estos vectores son llamados con la función glEnableClientState(), y son desactivados con la función de glDisableClientState().
2.
Especificando los datos parta los vectores: hay diferentes funciones para especificar datos para un vector, una función para cada tipo de
vector. ♦ Coordenadas de vértices. void glVertexPointer(GLint tamaño, GLenum tipo, GLsizei empaqueta miento, const GLvoid *puntero); ♦
Colores RBGA.
void glColorPointer(GLint tamaño, GLenum tipo, GLsizei empaquetamiento, const GLvoid *puntero);
♦
Índice de color.
void glIndexPointer(GLenum tipo, GLsizei empaquetamiento, const GLvoid *puntero); ♦
Normales.
void glNormalPointer(GLenum tipo, GLsizei empaquetamiento, const GLvoid *puntero); ♦
Coordenadas de niebla.
void glFogCoordPointer(GLenum tipo, GLsizei empaquetamiento, const GLvoid *puntero); ♦
Coordenadas de textura.
void glTexCoordPointer(GLint tamaño, GLenum tipo, GLsizei em paquetamiento, const GLvoid *puntero); ♦
Banderas de aristas de Polígonos.
void glEdgeFlagPointer(GLsizei empaquetamiento, const GLvoid *puntero)
Donde: ♦ ♦ ♦
Puntero es la dirección de memoria donde residen los datos. Tipo indica el tipo de dato en el vector ( GL_SHORT, GL_INT, GL_ FLOAT, GL_DOUBLE). Tamaño indica el número de coordenadas por vértice que pueden ser 2, 3, o 4. 132
Capítulo 6 - Aspectos avanzados de OpenGL
Empaquetamiento indica el espacio, en bytes, entre coordenadas sucesivas de un vértice, si es cero, los datos se encuentran uno tras otro sin ningún tipo espacio adicional entre ellos.
♦
Ejemplo Fragmento de código para habilitar vectores de vértices. static GLint vertices[] = {25, 25, 100, 175, 175, 250,
325, 25, 325, 25,
325, 325}; static GLoat colors[] = {1.0, 0.2, 0.2, 0.2, 0.2, 1.0, 0.8, 1.0, 0.2, 0.75, 0.75, 0.75, 0.35, 0.35, 0.35,
0.5, 0.5, 0.5}; glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3, GL_FLOAT, 0, colors); glVertexPointer(2, GL_INT, 0, vertices);
3.
Hacer referencia de la información para su utilización. Existen varias forma de referenciar los datos que se encuentran en los vectores, estas son: ♦
Hacer referencia a un único elemento del vector, Para esto se uti liza la función void glArrayElement(GLint posición).
Ejemplo Fragmento de código usando glArrayElement(). glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3, GL_FLOAT, 0, colors); glVertexPointer(2, GL_INT, 0, vertices); glBegin(GL_TRIANGLES);
133
Capítulo 6 - Aspectos avanzados de OpenGL
glArrayElement(2); glArrayElement(3); glArrayElement(5); glEnd(); ♦
Hacer referencia a una lista de elementos del vector, para esto se pueden utilizar funciones como: glArrayElement(), glDrawEle ments(), glMultiDrawElements(), glDrawRangeElements().
Ejemplo Fragmento de código usando glDrawElements(). static GLubyte frontIndices[] = {4, 5, 6, 7}; static GLubyte rightIndices[] = {1, 2, 6, 5}; static GLubyte bottomIndices[] = {0, 1, 5, 4}; static GLubyte backIndices[] = {0, 3, 2, 1}; static GLubyte leftIndices[] = {0, 4, 7, 3}; static GLubyte topIndices[] = {2, 3, 7, 6}; glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, frontIndices); glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, rightIndices); glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, bottomIndices); glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, backIndices); glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, leftIndices); glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, topIndices);
Ejemplo Fragmento de código usando glMultiDrawElements(). static static static static
GLubyte oneIndices[] = {0, 1, 2, 3, 4, 5, 6}; GLubyte twoIndices[] = {7, 1, 8, 9, 10, 11}; GLsizei count[] = {7, 6}; GLvoid * indices[2] = {oneIndices, twoIndices};
glMultiDrawElements(GL_LINE_STRIP, count, GL_UNSIGNED_BYTE, indi ces, 2); ♦
Hacer una referencia a una secuencia aleatoria de elementos,
Cuando se desea extraer una secuencia aleatoria de elementos se pueden utilizar funciones: glArrayElement(), glDrawElements , glDrawRangeElements() y glDrawArrays().
134
Capítulo 6 - Aspectos avanzados de OpenGL
Ejemplo Fragmento de código usando glDrawArrays(). for (i = 0; i < primcount; i++) { if (count[i] > 0) glDrawArrays(mode, rst[i], count[i]); }
6.9
Niebla
La niebla es un efecto especial de fácil uso que dispone OpenGl y que fusiona un color de niebla que podemos especicar en el elemento geométrico una vez efec -
tuados los cálculos. La cantidad de color de niebla mezclada con el elemento varía con la distancia desde el origen a la cámara. Las funciones utilizadas para la niebla son:
Void Void Void Void
glFogf(GLenum glFogi(GLenum glFogf(GLenum glFogi(GLenum
atributo, atributo, atributo, atributo,
GLoat valor) GLoat valor) GLoat* valor) GLoat *valor)
Donde: ♦
Atributo es el valor enumerado que determina la funcionalidad a
gestionar. ♦
Valor contiene un conjunto de valores que sustituirá a los antiguos
atributos. En la siguiente tabla se muestra la lista de atributos que tiene OpenGL para el manejo de la niebla.
Atributo GL_FOG_COLOR
Descripción Especica exactamente el color que se desea para la nie -
bla. GL_FOG_DENSITY GL_FOG_END
Especica la densidad de la niebla. Especica la distancia máxima a la que se aplica la niebla.
GL_FOG_INDEX
Determina el índice de color de niebla.
135
Capítulo 6 - Aspectos avanzados de OpenGL GL_FOG_MODE
Especica el modo de niebla, que se desea. GL_LINEAR,
GL_EXP, GL_EXP2. GL_FOG_START
Especica la distancia a la que se empieza a aplicar la nie -
GL_FOG_COORD_SRC
bla. Niebla de vértice interpolado.
Tabla 2: Lista atributos para la niebla en OpenGL. El uso de la función glhint(GL_FOG_HINT,mode) permite el cálculo de la niebla con precisión, donde el parámetro modo indica la precisión deseada por eJ usuario. Las opciones disponibles son las siguientes: ♦
GL_FASTEST. Emplea el algoritmo de niebla mas efici ente, pero tam -
bién el mas inexacto. ♦
GL_NICEST. Algoritmo menos eficiente, pero genera resultados con
la mayor calidad posible. ♦
GL_DONT_CARE . El programador no tiene preferencias. Decide el paquete gráfico.
Cuando el cálculo de niebla por píxel no se soporta ecientemente por la imple mentación OpenGL empleada, GL_DONT_CARE o GL_FASTEST usaran una interpol-
ación lineal por vértices.
Ejemplo Código para el manejo de la niebla en OpenGL. #include #include #include #include #include
static GLint modo_niebla; static void iniciar(void) {
GLoat posicion[] = { 0.5, 0.5, 3.0, 0.0 }; glEnable(GL_DEPTH_TEST); glLightfv(GL_LIGHT0, GL_POSITION, position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); {
136
Capítulo 6 - Aspectos avanzados de OpenGL
GLoat mat[3] = {0.1745, 0.01175, 0.01175}; glMaterialfv(GL_FRONT, GL_AMBIENT, mat); mat[0] = 0.61424; mat[1] = 0.04136; mat[2] = 0.04136; glMaterialfv(GL_FRONT, GL_DIFFUSE, mat); mat[0] = 0.727811; mat[1] = 0.626959; mat[2] = 0.626959; glMaterialfv(GL_FRONT, GL_SPECULAR, mat); glMaterialf(GL_FRONT, GL_SHININESS, 0.6*128.0); }
glEnable(GL_FOG); {
GLoat color_niebla[4] = {0.5, 0.5, 0.5, 1.0}; Modo_niebla = GL_EXP; glFogi(GL_FOG_MODE, modo_niebla); glFogfv(GL_FOG_COLOR, color_niebla); glFogf(GL_FOG_DENSITY, 0.35); glHint(GL_FOG_HINT, GL_DONT_CARE); glFogf(GL_FOG_START, 1.0); glFogf(GL_FOG_END, 5.0); }
glClearColor(0.5, 0.5, 0.5, 1.0); //color de niebla }
static void renderSphere(GLoat x, GLoat y, GLoat z) {
glPushMatrix(); glTranslatef(x, y, z); glutSolidSphere(0.4, 16, 16); glPopMatrix(); }
//desplegar() dibuja cinco esferas diferentes. void desplegar (void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderSphere(-2., -0.5, -1.0); renderSphere(-1., -0.5, -2.0); renderSphere(0., -0.5, -3.0); renderSphere(1., -0.5, -4.0); renderSphere(2., -0.5, -5.0); glFlush(); }
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
137
Capítulo 6 - Aspectos avanzados de OpenGL
glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-2.5, 2.5, -2.5*(GLoat)h/(GLoat)w, 2.5*(GLoat)h/(GLoat)w, -10.0, 10.0); else
glOrtho(-2.5*(GLoat)w/(GLoat)h, 2.5*(GLoat)w/(GLoat)h, -2.5, 2.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }
void teclado(unsigned char key, int x, int y) {
switch (key) { case ‘f’: case ‘F’: if (modo_niebla == GL_EXP) { modo_niebla = GL_EXP2; printf(“El modo de niebla es: GL_EXP2\n”); }
else if (modo_niebla == GL_EXP2) { modo_niebla = GL_LINEAR; printf(“El modo de niebla es: GL_LINEAR\n”); }
else if (modo_niebla == GL_LINEAR) { modo_niebla = GL_EXP; printf(“El modo de niebla es: GL_EXP\n”); }
glFogi(GL_FOG_MODE, modo_niebla); glutPostRedisplay(); break; case 27: exit(0); break; default: break; } }
int main(int argc, char** argv) {
glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
138
Capítulo 6 - Aspectos avanzados de OpenGL
glutInitWindowSize(500, 500); glutCreateWindow(argv[0]); iniciar(); glutReshapeFunc(reshape); glutKeyboardFunc(teclado); glutDisplayFunc(desplegar); glutMainLoop(); return 0; }
Figura: Resultado de la ejecucion.
139
Capítulo 6 - Aspectos avanzados de OpenGL
6.10 Cargar modelos .OBJ Para cargar este formato de archivo, el cual puede ser creado en diversos progra mas de modelado gráco, se requiere la librería glm.h la cual fue desarrollada por Nate Robin, esta se encuentra en la siguiente dirección : http://www.megaupload. com/?d=QGWIEZD7. Como primer paso se debe crear un nuevo proyecto en Vis -
ual Studio 2010. A este proyecto se le agregaran los archivos glm.cpp y glm.h que están en el archivo descargado anteriormente. Para la ejecución de este programa es necesario utilizar los archivos virus.obj y virus.mtl los cuales se encuentran en la siguiente dirección: http://www.megaupload.com/?d=EMHCDLDH, después de
descomprimirlos los agregaremos a una carpeta que se llamara modelos, en donde hemos guardado nuestro proyecto Después se creara un archivo de código fuente en el cual se copiara el siguiente
código. #include
#include “glm.h” #include GLMmodel* objeto; //////////
GLoat luzAmbient[4] = {0.0,0.0,0.0,1.0}; GLoat luzDiff[4] = {1.0, 1.0, 1.0,1.0}; GLoat luzSpec[4] = {1.0, 1.0, 1.0,1.0}; ///////// //////////
GLoat matAmbient[4] = {0.11,0.06,0.11,1.0}; GLoat matDiff[4] = {0.42, 0.0, 0.79,1.0}; GLoat matSpec[4] = {0.33, 0.33, 0.52,1.0}; GLoat matEmision[4] = {0.0,0.0,0.0,0.0}; GLint shininess=128; /////////
void init(){ glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); objeto = glmReadOBJ(“../modelos/virus.obj”); }
void luz(){ //luces del modelo
glLightfv(GL_LIGHT0, GL_AMBIENT, luzAmbient); glLightfv(GL_LIGHT0, GL_DIFFUSE, luzDiff);
140
Capítulo 6 - Aspectos avanzados de OpenGL
glLightfv(GL_LIGHT0, GL_SPECULAR, luzSpec); }
void cambiarTamano(int largo, int ancho) { // esta funcion re sive los parametros largo y ancho del callback que lo llamo (glutReshapeFunc) if(ancho==0) ancho=1; // Previene que dividamos por 0 // Afectaciones de vistas o tomas de perspectiva glMatrixMode(GL_PROJECTION); //Escojemos la matriz de proyeccion glLoadIdentity(); // Se resetea la matriz glViewport(0,0,ancho, largo); // Se va a usar toda la ventana para mostrar gracos gluPerspective( 60 , (oat)largo/(oat)ancho, 1, 260); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 8.5, 0.0, 0.0, 5.0,1.0, 7.0, 0.0); }
void dibujar() { glClearColor (1.0,1.0,1.0,1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); luz(); glTranslatef(0,0,-5); glRotatef(1,1,1,1); glmDraw(objeto, GLM_SMOOTH); glFlush(); }
int main(int argc, char **argv) {
glutInit( &argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(0,0); glutInitWindowSize( 600, 600); glutCreateWindow(“Cargar Modelos .OBJ”); init(); glutDisplayFunc(dibujar); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); glutReshapeFunc(cambiarTamano); glutMainLoop();
141
Capítulo 6 - Aspectos avanzados de OpenGL
glFlush(); return 0;
} Al ejecutarse se mostrara la siguiente imagen
Figura. Resultado de la ejecución
142
Capítulo 6 - Aspectos avanzados de OpenGL
Referencias Sanchez, A. (abril de 2009). Scribd. Recuperado el 18 de Noviembre de 2011, de Lista de Visualizacion. Hearn, D., & Baker, M. (2006). Grácos por Computadora con OpenGL. Madrid:
Pearson Prentice Hall. Ortega, A. L. (s.f.). Introducción a OpenGL (II). Recuperado el 19 de Noviembre de 2011, de http://www.alobbs.com/revistas/opengl2
Kilgard, M. (23 de Febrero de 1996). The OpenGL Utility ToolKit . Recuperado el 21 de Noviembre de 2011, de The OpenGL Utility ToolKit: http://www.opengl.org/ resources/libraries/glut/spec3/node63.html
Dave Shreiner, T. K. (Julio 2009). OpenGL Programming Guide (Seventh Edition ed.). Pearson Education, Inc. . González, D. E. Computación Gráca: Manejo de Grácos con OpenGL. Panamá,
Panamá. Microsoft. (9 de Julio de 2011). MSDN. Recuperado el 24 de Noviembre de 2011, de Microsoft Developer Network: http://msdn.microsoft.com/en-us/library/
dd374211(v=VS.85).aspx The Kanetrix’s GC. (5 de Octubre de 2009). Recuperado el 28 de Noviembre de 2011, de Grácos por Computador y otras cosas: http://kanetrixgc.wordpress. com/2009/05/10/modelosobj/#comments
Taller Nº 11 Copie el Siguiente código #include < glut.h >
GLoat angle = 0.0; GLoat density = 0.3; GLoat fogColor [ 4 ] = { 0.5, 0.5, 0.5, 1.0 } ; void cube ( void ) { glRotatef ( angle, 1.0, 0.0, 0.0 ) ; glRotatef ( angle, 0.0, 1.0, 0.0 ) ; glRotatef ( angle, 0.0, 0.0, 1.0 ) ; glColor3f ( 0.4, 1.0, 0.0 ) ; glutSolidCube ( 2.5 ) ; }
143
Capítulo 6 - Aspectos avanzados de OpenGL
void init ( void ) { glEnable ( GL_DEPTH_TEST ) ; glEnable ( GL_FOG ) ; glFogi ( GL_FOG_MODE, GL_EXP ) ; glFogfv ( GL_FOG_COLOR, fogColor ) ; glFogf ( GL_FOG_DENSITY, density ) ; glHint ( GL_FOG_HINT, GL_NICEST ) ; } void display ( void ) { glClearColor ( 1.0,1.0,1.0,1.0 ) ; glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; glLoadIdentity ( ) ; gluLookAt ( 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ) ; cube ( ) ; glutSwapBuffers ( ) ; angle += 0.1 ; }
void reshape ( int w, int h ) { glViewport ( 0, 0, ( GLsizei ) w, ( GLsizei ) h ) ; glMatrixMode ( GL_PROJECTION ) ; glLoadIdentity ( ) ; gluPerspective ( 60, ( GLoat ) w / ( GLoat ) h, 1.0, 100.0 ) ; glMatrixMode ( GL_MODELVIEW ) ; }
int main ( int argc, char * * argv ) { glutInit ( & argc, argv ) ; glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH ) ; glutInitWindowSize ( 500, 500 ) ; glutInitWindowPosition ( 100, 100 ) ; glutCreateWindow ( “Pruebas con Niebla” ) ; init ( ) ; glutDisplayFunc ( display ) ; glutIdleFunc ( display ) ; glutReshapeFunc ( reshape ) ; glutMainLoop ( ) ; return 0; }
Indicaciones ♦ Cambie el valor de la variable density en un rango de valores de 0.1 a 0.9 Anote sus observaciones 144
Capítulo 6 - Aspectos avanzados de OpenGL
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 2.Restablesca el valor de density a 0.3, en la línea glFogi ( GL_ FOG_MODE, GL_EXP2 ) ;, cambie el parámetro GL_EXP2 por: GL_LINEAR y por GL_EXP. Anote sus observaciones ♦
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________
Resultado de ejecución 145
Capítulo 6 - Aspectos avanzados de OpenGL
Taller Nº 12 Utilizando el código original del Taller Nº 11 realice los siguientes cambios: ♦
En la funcion void init ( void ) agregue las líneas de código:
glFrontFace(GL_CW); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); El resto de la función permanece igual.
♦
En la función void cube ( void ) agregue las líneas de código:
glColor3f(1,0,0); glutSolidTeapot(1); ♦
Ejecute el programa y anote sus observaciones, el resultado de la ejecución se muestra en la imagen.
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________ ♦
Cambie el argumento de la función glCullFace() por el valor GL_ FRONT, ejecute y anote los resultados:
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________ ♦
Cambie el argumento de la función glFrontFace() por el valor GL_CCW y el argumento de la función glCullFace() por GL_FRONT, ejecute y anote sus resultados:
_________________________________________________________________ _________________________________________________________________ _________________________________________________________________
146
Capítulo 6 - Aspectos avanzados de OpenGL
Resultado de la Ejecución Ejercicio Nº 7 Que accion se ejecuta el siguiente fragmento de código: glBegin(GL_ 1. QUAD_STRIP);
_________________________________________________________________ 2.
Mencione la acción que realizan las siguientes funciones: ♦
glCullFace:_______________________________________
♦
glFrontFace :______________________________________
3. Describa la accion de la función glutIdleFunc(): _________________________________________________________________ _________________________________________________________________ 147
Capítulo 6 - Aspectos avanzados de OpenGL
_________________________________________________________________ 4. Funciones que se usan para crear una lista de visualización: _________________________________________________________________ _________________________________________________________________ 5.
Al manejar varias listas de visualización, ¿Que funciones se requiere
utilizar? _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ _________________________________________________________________ 6.
Mencione la función que se utiliza para proyectar el área de dibujo y
muestre su prototipo. _________________________________________________________________ _________________________________________________________________ _________________________________________________________________
148
<7> C a p í t u l o OpenGL con otros Lenguajes OBJETIVOS: ♦ Conocer las acciones para desarrollar aplicaciones con OpenGL en otros lenguajes de Programación. ♦ Mostrar los conceptos básicos para programar OpenGL con C#. ♦ Presentar OpenTK. ♦ Ejemplificar los conceptos de GLControl y GameWindow. ♦ Conocer los requerimientos para utilizar OpenGL con Java en NetBeans. ♦ Mostrar los procedimientos para el uso de JOGL. ♦ Desarrollar una aplicación básica con Java y OpenGL.
DESCRIPCIÓN:
En este capitulo se muestra como desarrollar aplicaciones con OpenGL en lenguajes diferentes a C++. Se muestra
una descripción de OpenTK, la cual se trabajara con el Lenguaje C# en Visual
Stuido 2010. De igual manera se plantea el uso JOGL para ejecutar OpenGL con
Java desde NetBeans .
149
Capítulo 7 - OpenGL con otros Lenguajes
7.
OpenGL con otros Lenguajes
7.1
Implementación con C#
Para la implementación de OpenGL con C# en Visual Studio 2010 es necesaria la instalación OpenTK la cual se descarga de manera gratuita de su pagina http:// www.opentk.com/.
7.1.1 OpenTK OpenTK es un proyecto libre que permite el uso de las API’s de OpenGL, OpenGL ES, OpenCL y OpenAL. Este toolkit inició como una sección experimental de Tao Framework en el año 2006. Su propósito original era proveer un contenedor (wrap per) para Tao.OpenGL, pero su enfoque fue creciendo rápidamente. ♦
Algunas de las características de OpenTK son:
♦
Escrita en C# y usable por F#, Boo, VB.Net, C++/CLI.
♦
Usable para aplicaciones stand-alone o integradas con Windows. Forms. Binarios portables en .Net y Mono sin recompilación. Soporte para Windows, Linux, Mac OSX, y iPhone (en progreso).
♦ ♦ ♦
Adecuada para juegos, aplicaciones de visualización científica y todos los tipos de software que requieran gráficos avanzados.
♦
Biblioteca matemática (Math) integrada con soporte de vectores, matrices, planos, quaternions, etc.
7.1.2 Comenzar un nuevo proyecto Con OpenTK es posible utilizar dos tipos de ventana de visualización, las cuales poseen características diferentes, hablamos de GLControl y del GameWindows,
por lo cual al iniciar un nuevo proyecto es necesario decidir que ventana utilizaremos. ¿En qué casos usar el GL Control en vez del Game Windows de OpenTK? Lo primero que debemos determinar al momento de desarrollar una aplicación gráca usando el componente GLControl de OpenTK es: ¿Realmente necesita la complejidad que proporciona Windows.Forms + GLControl en vez de usar el GameWindow?. A continuación algunos casos en los que agregar esa complejidad son inevitables: ♦
♦
Se desea desarrollar una interfaz de usuario enriquecida en don -
de se pueda hacer uso de controles de Windows.Forms (botones, paneles, etiquetas, menúes, cajas de texto, etc.), por ejemplo: edi tores de niveles, visualizadores o modeladores de geometría pudieran entrar en esta categoría. Se desea embeber el despliegue de OpenGL dentro de paneles o controles de una aplicación Windows.Forms. 150
Capítulo 7 - OpenGL con otros Lenguajes
♦
Se desea hacer drag-and-drop hacia el panel de despliegue, por ejemplo, arrastrar un archivo .OFF a la aplicación y que este se
♦
visualice. Se desea hacer una aplicación con varios viewports (ventanas de despliegue) tipo 3DS Max Studio en donde se pueda visualizar un elemento desde distintos puntos de vista.
7.1.3 Primera Aplicación con OpenTK Para realizar nuestra primera aplicación el paquete OpenTK debe estar instalado(ver 7.1 ). Nuestra aplicación usara el GameWindows de OpenTK, como primer paso crearemos un nuevo proyecto de Windows Forms como se muestra en la Figura 1., asignamos el nombre y ubicación del proyecto.
Figura 1. Creación de un Nuevo Proyecto En este caso no será necesario el Windows form que se crea por defecto por lo cual puede ser eliminado. Al igual que el código que hace referencia a este en el main
del programa. Luego es necesario la inclusión de las referencias a OpenTK para lo cual seleccion amos en el menú Proyecto la opción de Agregar Referencia…. Como se muestra
en la Figura 2
151
Capítulo 7 - OpenGL con otros Lenguajes
Figura 2. Agregar referencia… Seguido aparecerá la ventana Agregar Referencia, donde seleccionamos las pestaña .NET y seleccionamos las opciones : OpenTK.Compatibility, OpenTK y
OpenTK.GLControl. Como se muestra en la Figura 3.
Figura 3. Agregar Referencias Luego se deben agregar las directivas requeridas 152
Capítulo 7 - OpenGL con otros Lenguajes
using OpenTK; using OpenTK.Graphics.OpenGL; using System.Drawing;
La directiva using System.Drawing; permite utilizar la clase color, esta se puede agregar de a misma manera que se agregaron las referencias a OpenTK.
Incluir la siguiente clase con sus métodos class MainWindow : OpenTK.GameWindow {
protected override void OnLoad(EventArgs e) {
base.OnLoad(e); GL.ClearColor(Color. WhiteSmoke); }
protected override void OnRenderFrame(FrameEventArgs e) {
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask. DepthBufferBit); GL.End(); SwapBuffers(); } }
El método protected override void OnLoad(EventArgs e) será el método que sobreescribirá el OnLoad de GameWindow, que se ejecutará al cargarse el control. Aquí tan solo hemos hecho dos cosas, por un lado ejecutar OnLoad en la clase base GameWindow y por otro designar el color WhiteSmoke como el color que mostrará la ventana por defecto.
El método protected override void OnRenderFrame(FrameEventArgs e) es donde se realiza el renderizado. Primero se hace un Clear que resetea los buffers presentes, en este caso el de color y el de profundidad. Después del clear vendrían
las instrucciones de renderizado y después el método End para indicar que ya hemos terminado las llamadas OpenGL. Para terminar, llamamos a SwapBuffers que lo que hace es intercambiar el buffer trasero por el frontal. Para que el programa de se ejecute es necesario modicar el Program.cs, donde ya eliminamos todo el código de dentro del Main y incluiremos el siguiente:
MainWindow doMain = new MainWindow(); doMain.Run();
153
Capítulo 7 - OpenGL con otros Lenguajes
Al ejecutar aparecerá una ventana con el color de fondo seleccionado. Ahora podemos incluir en la función OnRenderFrame(FrameEventArgs e) el siguiente código entre GL.Clear(ClearBufferMask.ColorBufferBit | ClearBuffer Mask.DepthBufferBit);y SwapBuffers();
GL.Begin(BeginMode.Triangles ); GL.Color3(Color.Red); GL.Vertex3(0.0f, 0.2f, 0.0f); GL.Color3(Color.Yellow); GL.Vertex3(-0.2f, -0.2f, 0.0f); GL.Color3(Color.Green); GL.Vertex3(0.2f, -0.2f, 0.0f);
GL.Color3(Color.Gold); GL.Vertex3(0.1f, 0.2f, -0.1f); GL.Color3(Color.Magenta); GL.Vertex3(-0.1f, -0.2f, 0.1f); GL.Color3(Color.Lime); GL.Vertex3(0.3f, -0.2f, 0.1f); GL.End();
GL.Enable(EnableCap.DepthTest);
El resultado se muestra en la Figura 4.
Figura 4. Resultado de la Ejecución 154
Capítulo 7 - OpenGL con otros Lenguajes
Ejemplo Para este ejemplo seguiremos los mismos pasos de la creación de un nuevo proyecto. Se deben agregar las siguientes directivas:
using using using using
OpenTK; OpenTK.Graphics; OpenTK.Graphics.OpenGL; OpenTK.Input;
El código de la clase que se creara es el siguiente. class Game : GameWindow {
private oat mAngulo = 0.0f; private int mNumeroDePuntos = 10; private oat mA = 3.0f; private oat mOffsetAngulo = 0.0f; private oat mVelocidadAngular = 0.00001f ; private oat mVelocidadOffet = 0.0001f; public Game() : base(600, 600, GraphicsMode.Default, “OpenTK Prueba”) { }
protected override void OnLoad(EventArgs e) {
base.OnLoad(e); // GL.ClearColor(1.0f, 1.0f, 1.0f, 0.0f); // asig nación de color mediante números GL.ClearColor(Color4.White); GL.LineWidth(3.0f); Keyboard.KeyDown += new EventHandler(Keyboard_KeyDown); }
void Keyboard_KeyDown(object sender, KeyboardKeyEventArgs e) {
if (Keyboard[Key.Escape]) {
Exit(); } else if (Keyboard[Key.A]) {
this.mNumeroDePuntos++; }
155
Capítulo 7 - OpenGL con otros Lenguajes
else if (Keyboard[Key.Z]) {
if (this.mNumeroDePuntos > 1) {
this.mNumeroDePuntos--; } }
else if (Keyboard[Key.S]) {
this.mA += 0.5f; }
else if (Keyboard[Key.X]) {
this.mA -= 0.5f; }
else if (Keyboard[Key.D]) {
mVelocidadOffet += 0.0001f; }
else if (Keyboard[Key.C]) {
mVelocidadOffet -= 0.0001f; }
else if (Keyboard[Key.F]) {
mVelocidadAngular += 0.000001f; }
else if (Keyboard[Key.V]) {
mVelocidadAngular -= 0.000001f; } }
protected override void OnResize(EventArgs e) {
base.OnResize(e); GL.MatrixMode( MatrixMode.Projection ); GL.LoadIdentity(); GL.Ortho( 0 , this.Width , 0 , this.Height, -1 , 1 ); GL.Viewport(ClientRectangle.X, ClientRectangle.Y, Cli entRectangle.Width, ClientRectangle.Height); }
156
Capítulo 7 - OpenGL con otros Lenguajes
protected override void OnUpdateFrame(FrameEventArgs e) {
base.OnUpdateFrame(e); }
protected override void OnRenderFrame(FrameEventArgs e) {
base.OnRenderFrame(e); GL.Clear(ClearBufferMask.ColorBufferBit); GL.Begin(BeginMode.LineStrip); oat angulo = this.mAngulo; oat step = (oat)(2.0 * Math.PI / this.mNumeroDePuntos); int radio = 290; while (angulo < this.mAngulo + 2.0 * Math.PI) {
oat r = (oat)Math.Sin(this.mA * angulo + this.mOffsetAn gulo) * radio; int x = 300 + (int)(r * Math.Cos(angulo)); int y = 300 + (int)(r * Math.Sin(angulo)); oat R = (oat)Math.Abs(Math.Cos(angulo)); oat B = (oat)Math.Abs(Math.Sin(angulo)); oat G = (oat)Math.Abs(Math.Sin(angulo + Math.PI / 3.0)); GL.Color3(R, G, B); GL.Vertex2(x, y); angulo += step; }
GL.End(); SwapBuffers(); this.mAngulo += this.mVelocidadAngular; this.mOffsetAngulo += this.mVelocidadOffet; }
} En Program.cs se modicara el método main con el siguiente código:
using (Game game = new Game()) {
game.Run( 30.0 ); }
Este programa permite la interacción con el usuario a través de los siguientes controles: A, Z
: agregar, quitar línea
157
Capítulo 7 - OpenGL con otros Lenguajes
S, X : cambiar el valor del Angulo D, C : velocidad de desplazamiento F, V : velocidad angular Esc
: salir
Figura 5. Resultado de la ejecución 7.1.4 Windows Form y GLControl El siguiente ejemplo presenta la utilización del GLControl, para este ejemplo se debe crear un nuevo proyecto de Windows Forms, agregar las referencias, pero no se debe eliminar el Form1 que Visual Studio crea por defecto. En el Form1 se deben agregar las siguientes directivas:
using System;
158
Capítulo 7 - OpenGL con otros Lenguajes
using using using using
System.Drawing; System.Windows.Forms; OpenTK.Graphics; OpenTK.Graphics.OpenGL;
El siguiente paso es agregar el componente GLControl a nuestro Cuadro de Herramientas para poder arrastrarlo a nuestro formulario como cualquier otro
componente de Windows.Forms y poder utilizarlo. Para ello hagamos clic derecho sobre un área vacía del Cuadro de Herramientas luego selecciona la opción Elegir Elementos. Nos aparecerá el cuadro Elegir elementos del cuadro de herramientas (Figura 6), en la pestaña Componentes de .NET Framework seleccionamos Ex aminar, buscamos el directorio de instalación de OpenTK y el directorio Binaries/ OpenTK/Release se encuentra un DLL llamado OpenTK.GLControl.dll se debe
seleccionar y pulsa el boton abrir.
Figura 6 Elegir Elementos
159
Capítulo 7 - OpenGL con otros Lenguajes
Figura 7. Directorio de Instalación de OpenTK Por último se verica que el control esté seleccionado y pulsa el botón
Aceptar. Ya se ha agregado el Control a nuestro Cuadro de Herramientas. Hecho esto arrastremos el GLControl al form.
Cuando se ha añadió el GLControl de debe programar el evento Paint, el cual se encuentra en la lista de los eventos del objeto en el panel de propiedades,
desde la vista de diseño. Dentro del evento Paint agregamos el siguiente código GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.Depth BufferBit); GL.Begin(BeginMode.Quads); {
GL.Color3(Color.Orange); GL.Vertex2(-0.5f, 0.5f); GL.Color3(Color.Lime); GL.Vertex2(-0.5f, -0.5f); GL.Color3(Color.Magenta); GL.Vertex2(0.5f, -0.5f); GL.Color3(Color.Cyan); GL.Vertex2(0.5f, 0.5f);
}
GL.End();
160
Capítulo 7 - OpenGL con otros Lenguajes
glControl1.SwapBuffers();
Las líneas GL.Clear(ClearBufferMask.ColorBufferBit | ClearBuffer Mask.DepthBufferBit); y glControl1.SwapBuffers();que acabamos de agregar se encargarán de limpiar los buffers de salida para poder desplegar lo que desea mos en pantalla. El resto del código dibuja un cuadrado en la pantalla.
Procedamos a agregar el evento Load para el glControl (igual a agregar el evento Paint o simplemente hacer doble clic sobre el glControl en la vista de diseño). Incluimos dentro el siguiente código:
GL.ClearColor(Color.Black); SetupViewport();
Hasta ahora el método SetupViewport(); no ha sido creado para crearlo copiamos el siguiente fragmento:
private void SetupViewport() {
int w = glControl1.Width; int h = glControl1.Height; oat aspectRatio = (oat)w / (oat)h; GL.Viewport(0, 0, w, h); GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); GL.Ortho(-aspectRatio, aspectRatio, -1, 1, -1, 1); GL.MatrixMode(MatrixMode.Modelview); GL.LoadIdentity();
}
Esto nos permite congurar el Viewport de manera adecuada.
Las líneas oat aspectRatio = (oat)w / (oat)h; y GL.Ortho(-aspectRatio, aspectRatio, -1, 1, -1, 1); nos permiten calcular la proporción entre ancho y alto a lo que se le llama aspect ratio, de esta manera podremos mantener la proporción de lo que dibujemos sin importar el tamaño de la ventana.
En la vista de diseño, seleccionamos el glControl y cambiamos la propiedad Dock a Fill, lo cual permite que el glControl se adapte al tamaño de la ventana de forma automática. Al ejecutar nuestra aplicación y cambiar el tamaño de nuestra ventana. El
cuadrado se mueve por toda la ventana. Para solucionar este problema se hace lo siguiente. Creamos el evento Resize del GLControl (como paint y load ) y copiamos lo siguiente 161
Capítulo 7 - OpenGL con otros Lenguajes
SetupViewport(); glControl1.Invalidate();
Lo que estamos haciendo es actualizar de nuevo nuestro viewport con el tamaño actual del controlador y posteriormente estamos repintando nuestro cuadrado llamando al método Invalidate del glControl. Lo siguiente será crear dos botones: ♦
Un botón con la propiedad .text = Rojo, y el evento click con el
siguiente código GL.ClearColor(Color.Red); glControl1.Invalidate(); ♦
Un botón con la propiedad .text = Beige y el evento click con el
siguiente código GL.ClearColor(Color.Beige); glControl1.Invalidate();
Estos botones cambiaran el color de nuestro glControl. Al ejecutar el programa se genera la siguiente salida.
Figura 8. Resultado de Ejecución 162
Capítulo 7 - OpenGL con otros Lenguajes
Se presenta también el estado nal de la clase form1.cs
using System; using System.Drawing; using System.Windows.Forms; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; namespace HelloOpenTK {
public partial class Form1 : Form {
public Form1() {
InitializeComponent(); }
private void glControl1_Load(object sender, EventArgs e) {
GL.ClearColor(Color.Beige); SetupViewport(); }
private void glControl1_Paint(object sender, PaintEven tArgs e) {
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBuffer Mask.DepthBufferBit);
GL.Begin(BeginMode.Quads); {
GL.Color3(Color.Orange); GL.Vertex2(-0.5f, 0.5f); GL.Color3(Color.Lime); GL.Vertex2(-0.5f, -0.5f); GL.Color3(Color.Magenta); GL.Vertex2(0.5f, -0.5f); GL.Color3(Color.Cyan); GL.Vertex2(0.5f, 0.5f);
}
GL.End();
163
Capítulo 7 - OpenGL con otros Lenguajes
glControl1.SwapBuffers(); }
private void SetupViewport() {
int w = glControl1.Width; int h = glControl1.Height; oat aspectRatio = (oat)w / (oat)h; GL.Viewport(0, 0, w, h); GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); GL.Ortho(-aspectRatio, aspectRatio, -1, 1, -1, 1); GL.MatrixMode(MatrixMode.Modelview); GL.LoadIdentity();
}
private void glControl1_Resize(object sender, EventArgs e) {
SetupViewport(); glControl1.Invalidate(); }
private void button1_Click(object sender, EventArgs e) {
GL.ClearColor(Color.Red); glControl1.Invalidate(); }
private void button2_Click(object sender, EventArgs e) {
GL.ClearColor(Color.Beige); glControl1.Invalidate(); } }
}
7.2
Implementación con Java
Para trabajar con OpenGL en Java utilizando NetBeans, se requiere instalar un complemento, The NetBeans OpenGL Pack, que se descarga de la dirección: http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=3260. El archivo descargado esta comprimido y contiene un conjunto de archivos
con extensión .nmb. La última actualización de este paquete fue para NetBeans 6.7, pero puede ser ejecutado en NetBeans 7.01 y en cualquier plataforma.
164
Capítulo 7 - OpenGL con otros Lenguajes
7.2.1 Instalación de los complementos Para la instalación del paquete debemos, una vez abierto el NetBeans, seleccionar la opción Complementos que está disponible en el menú Herramientas como se muestra en la Figura 9.
Figura 9. Instalar Complementos Se mostrara la ventana Complementos (Figura 10) en la cual seleccionamos la pestaña Descargado, y el botón Agregar Plugins. Luego buscamos la ubicación donde descomprimimos el paquete de OpenGL y seleccionamos todo su contenido, como se muestra en la Figura 11.
Figura 10. Ventana de Complementos
165
Capítulo 7 - OpenGL con otros Lenguajes
Figura 11. Selección de elementos Luego en la ventana de Complementos debemos deseleccionar el complemento GSL editor, el cual no es compatible con la última versión del entorno que se está utilizando(Figura 12). Una vez terminada la instalación el ide se reiniciara y al iniciar nuevamente podremos utilizar el paquete que se instalo.
Figura 12. Complementos que se instalaran 166
Capítulo 7 - OpenGL con otros Lenguajes
7.2.2 Una aplicación JOGL JOGL es el nombre de la librería que se utiliza para acceder a OpenGL, la cual se instalo en el procedimiento anterior. Para este ejemplo crearemos un nuevo proyecto y seleccionaremos la opción
JOGL Application (Form Designes, GLJPanel) como se muestra en la Figura 13, al cual le asignamos un nombre y una ubicación.
Figura 13 Nuevo Proyecto en NetBeans Este proyecto se puede ejecutar y desplegara un triangulo con un cuadrado como se muestra en la Figura 14. Para este ejemplo se cambiara el cuadrado por la
tetera. Para realizar esto debemos abrir en el árbol de proyecto la clase GLRenderer como se muestra en la Figura 15, la cual es la encargada de realizar el dibujo.
167
Capítulo 7 - OpenGL con otros Lenguajes
Figura 14. Ejecución del Proyecto Original
Figura 15. Árbol de Proyecto En el método display de esta clase eliminaremos el código que se encarga del dibujo del cuadrado, cual está se ubica entre
gl.glBegin(GL.GL_QUADS); ………
gl.glEnd();
168
Capítulo 7 - OpenGL con otros Lenguajes
Después escribiremos el siguiente código:
GLUT tetera = new GLUT(); tetera.glutWireTeapot(1); para una correcta ejecución debemos agregar también
import com.sun.opengl.util.GLUT; y al ejecutar mostrara el siguiente resultado(Figura 16).
Figura 16. Resultado de la Ejecución Referencias Mena, C. (22 de Septiembre de 2011). Widget-Pc. Recuperado el 20 de Noviembre de 2011, de http://widget-pc.com/primera-aplicacion-graca-en-opentk-glcontrolwindows-forms/ OpenTK. (s.f.). OpenTK. Recuperado el 19 de Noviembre de 2011, de Home of the Open Toolkit library: http://www.opentk.com/
Loaiza, C. A. (29 de Junio de 2009). Aprendiendo JOGL. Recuperado el 2 de Septiembre de 2011, de OpenGL Mediante Programación en Java: http://aprendiendo jogl.blogspot.com/2009/07/instalar-jogl-con-netbeans.html
169