Source: http://docplayer.es/1649948-Introduccion-a-la-programacion-grafica-con-opengl.html
Timestamp: 2018-02-21 10:15:17+00:00

Document:
Introducción a la Programación Gráfica con OpenGL - PDF
Download "Introducción a la Programación Gráfica con OpenGL"
Alfredo San Segundo Olivera
1 Introducción a la Programación Gráfica con OpenGL Oscar García Alex Guevara Escola Tècnica Superior d Enginyeria Electrònica i Informàtica La Salle Enero 2004 Oscar García - Alex Guevara La Salle
2 Índice Índice ÍNDICE 1 INTRODUCCIÓN 5 1. CONCEPTOS PREVIOS SISTEMAS GRÁFICOS. DISPOSITIVOS Y ELEMENTOS EL MODELO "CÁMARA SINTÉTICA" ARQUITECTURAS GRÁFICAS INTERFÍCIE OPENGL. PRIMITIVAS Y ATRIBUTOS TRANSFORMACIONES COORDENADAS HOMOGÉNEAS ESCALAR TRASLADAR ROTAR DEFORMAR CONCATENACIÓN DE TRANSFORMACIONES PREMULTIPLICACIÓN Y POSTMULTIPLICACIÓN IMPLEMENTACIÓN CONCEPTO DE "PILA" O "STACK" CREAR MATRICES "A MEDIDA" PROYECCIONES TIPOS DE PROYECCIÓN PROYECCIÓN ORTOGRÁFICA PROYECCIÓN PERSPECTIVA LA CÁMARA LA LIBRERÍA GLUT FUNCIÓN MAIN INICIALIZACIÓN DEL SISTEMA RENDER DEL SISTEMA SISTEMA DE VENTANAS CONCEPTO DE ASPECT RATIO VIEWPORTS EVENTOS Y MENÚS DE USUARIO. 46 Oscar García - Alex Guevara La Salle
3 Índice 6.1. EL RATÓN EL TECLADO CAMBIO DE TAMAÑO MENÚS ILUMINACIÓN VECTORES NORMALES A UNA SUPERFÍCIE TIPOS DE ILUMINACIÓN ESPECIFICACIÓN DE MATERIALES LUCES CARACTERÍSTICA AMBIENTAL CARACTERÍSTICA DIFUSA CARACTERÍSTICA ESPECULAR COLOCANDO LAS LUCES MÁS PARÁMETROS TEXTURIZACIÓN CARGANDO TEXTURAS EN MEMORIA PASANDO LAS TEXTURAS A OPENGL PARÁMETROS DE LAS TEXTURAS RENDERIZANDO CON TEXTURAS COLORES, LUCES Y TEXTURAS BUFFERS DE OPENGL EL BUFFER DE COLOR DOBLE BUFFER INTERCAMBIO DE BUFFERS EL BUFFER DE PROFUNDIDAD COMPARACIONES DE PROFUNDIDAD VALORES DE PROFUNDIDAD EL STENCIL BUFFER FUNCIONES DEL STENCIL BUFFER DIBUJANDO CON EL STENCIL BUFFER EL BUFFER DE ACUMULACIÓN EFECTOS ESPECIALES NIEBLA TRANSPARENCIAS ANTIALIASING MOTION BLUR OPTIMIZACIONES DEL RENDER 79 Oscar García - Alex Guevara La Salle
4 Índice 11.1 VERTEX ARRAYS COMO TRABAJAR CON VERTEX ARRAYS DIBUJANDO CON VERTEX ARRAYS OPTIMIZACIONES INDEPENDIENTES DE OPENGL QUAD-TREES BSP TREES PORTALES PVS ORDENACIÓN DE LAS TEXTURAS 81 Oscar García - Alex Guevara La Salle
5 Introducción Introducción OpenGL es una librería gráfica escrita originalmente en C que permite la manipulación de gráficos 3D a todos los niveles. Esta librería se concibió para programar en maquinas nativas Silicon Graphics bajo el nombre de GL (Graphics Library). Posteriormente se considero la posibilidad de extenderla a cualquier tipo de plataforma y asegurar así su portabilidad y extensibilidad de uso con lo que se llego al termino Open Graphics Library, es decir, OpenGL. La librería se ejecuta a la par con nuestro programa independientemente de la capacidad gráfica de la maquina que usamos. Esto significa que la ejecución se dará por software a no ser que contemos con hardware gráfico especifico en nuestra máquina. Si contamos con tarjetas aceleradoras de vídeo, tecnología MMX, aceleradoras 3D, pipelines gráficos implementados en placa, etc. por supuesto gozaremos de una ejecución muchísimo mas rápida en tiempo real. Así esta librería puede usarse bajo todo tipo de sistemas operativos e incluso usando una gran variedad de lenguajes de programación. Podemos encontrar variantes de OpenGL para Windows 95/NT, Unix, Linux, Iris, Solaris, Delphi, Java e incluso Visual Basic. No obstante, su uso mas extenso suele ser el lenguaje C o C++. Por supuesto no podemos desligar el mundo de los gráficos de OpenGL y por tanto se intentará que este sea un curso de "gráficos usando OpenGL", mas que una larga mención de funciones y constantes integradas en esta librería. Trabajaremos con C y por tanto nos referiremos siempre a ejemplos codificados según este lenguaje. Simplemente necesitaremos las librerias adecuadas y un compilador cualquiera de Ansi C, es decir, el estándar de este lenguaje. Algo de álgebra lineal también hará falta para entender que es lo que ocurre internamente y como podemos operar con nuestra geometría para lograr los efectos deseados. Oscar García - Alex Guevara La Salle
6 Conceptos previos 1. Conceptos previos Sistemas gráficos. Dispositivos y elementos. Tal como comentamos en el capítulo de introducción, es inviable hablar de cómo programar con OpenGL sin, a la par, mencionar determinados conceptos. Por tanto, primero debemos entender que es un "pipeline" gráfico, que elementos lo configuran y cuales son sus entradas y salidas. Un sistema gráfico típico se compone de los siguientes elementos físicos: Estas son las características generales de cada uno de los elementos: Entradas : todo aquello que nuestro programa ha calculado y desea dibujar. En definitiva es el "nuevo estado" de nuestro mundo tras algún evento que lo ha hecho cambiar como por ejemplo que la cámara se haya movido o alejado de la escena. Procesador (CPU): máximo administrador del sistema, se encargará de gestionar la comunicación entre todos los módulos. Realizara operaciones según se le pida con ayuda de una/s ALU/s (Unidades aritméticas) y consultara la memoria cuando le sea necesario. En sistemas dedicados, y por tanto especializados en gráficos, podemos tener diversas CPU's trabajando en paralelo para asegurar un buen rendimiento en tiempo real (Calcular y dibujar a la vez). Memoria : elemento indispensable y bastante obvio como el anterior. En nuestro caso nos interesara una cierta franja de memoria, el "frame buffer". Frame Buffer : Zona de memoria destinada a almacenar todo aquello que debe ser dibujado. Antes de presentar la información por pantalla, esta se recibe en el frame buffer. Por tanto, nuestro programa OpenGL escribe en esta área de memoria y automáticamente envía su contenido a la pantalla después. Look Up Table (LUT): esta "tabla" contiene todos los colores que tenemos disponibles en nuestro sistema. A algunos os parecerá quizá más familiar el termino "paleta" para referiros a la LUT. En sistemas "indexados" cada color tiene un identificador en la tabla y puedes referirte a él usándolo en tu programa. Oscar García - Alex Guevara La Salle
7 Conceptos previos Así si deseamos dibujar un polígono de color rojo, modificaremos su atributo de color dándole a este el valor del identificador que tiene el color rojo en la LUT. Generalmente no se utiliza ya que no se trabaja en color indexado, sino con color real (RGB) Conversor D/A: la información contenida en el frame buffer a nivel de bit es digital y por tanto debe convertirse a su homónimo analógico para poder ser procesada por un CRT (Tubo de rayos catódicos) y proyectada en la pantalla. No profundizaremos mas en este tema pues no es el objetivo analizar el funcionamiento de un monitor. Salidas : tras el conversor ya disponemos de información analógica para ser visualizada en nuestra pantalla. Antes de continuar aclarar el termino píxel (picture element). Un píxel es la unidad mínima de pantalla y los encontramos dispuestos en filas en cualquier monitor o televisor de manera que el conglomerado de pixeles con sus colores asociados da lugar a la imagen. El frame buffer se caracteriza por su resolución y por su profundidad. La resolución viene dada por el producto ancho x alto, es decir, el número de filas multiplicado por el número de columnas análogamente a las resoluciones que nuestro monitor puede tener (640 x 480, 800 x ). La profundidad es el número de bits que utilizamos para guardar la información de cada píxel. Este número dependerá de la cantidad de colores que deseemos mostrar en nuestra aplicación. Típicamente si queremos "color real" necesitaremos ser capaces de mostrar 16,7 millones de colores simultáneamente que es la capacidad aproximada de nuestro sistema visual. En este caso y suponiendo una resolución de 800 x 600 pixeles en pantalla necesitaremos: 800 píxeles/fila x 600 filas x 24 bits/píxel = 1.37 Megabytes de memoria para el frame buffer Dado que color real implica 256 posibles valores de rojo, 256 de verde y 256 de azul por píxel y esto implica un byte/píxel para cada una de estas componentes, es decir, 3 bytes por píxel. La librería OpenGL, por si sola, se encargará de reservar este espacio de memoria, sin que nosotros tengamos que ocuparnos de ello. Nuestra librería o API (Application Programming Interface), en este caso OpenGL, contactara directamente con los elementos de la figura anterior a medida que lo crea necesario. Por tanto, esto nos será totalmente transparente y no deberá preocuparnos. Oscar García - Alex Guevara La Salle
8 Conceptos previos 1.3. El modelo "cámara sintética". OpenGL utiliza este modelo semántico para interpretar una escena que debe ser dibujada. Básicamente se trata de imaginar un objeto situado en un determinado lugar y filmado por una cámara, tan sencillo como esto. Veamos el siguiente diagrama: Contamos con un "mundo 3D" que estamos observando desde una determinada posición. Podéis pensar en el observador como vosotros mismos mirando hacia vuestro mundo virtual o bien como una cámara que lo esta filmando. Ese punto es el centro de proyección tal y como se observa en la figura. Evidentemente el mundo es tridimensional pero su proyección en un plano (plano de proyección) es bidimensional. Este plano es nuestro frame buffer antes de dibujar o bien la pantalla del monitor después de haberlo hecho. Por tanto, queda claro que pasamos de coordenadas del mundo en 3D a coordenadas de pantalla en 2D y por lo tanto necesitamos proyectar. El modelo "cámara sintética" se compone pues de los siguientes elementos: Necesitamos luces que iluminen nuestro mundo 3D. Para ello será necesario que especifiquemos sus localizaciones, sus intensidades y sus colores. Necesitamos una cámara que "filme" nuestro mundo virtual y lo muestre por pantalla. Esta cámara es nuestro "punto de vista" del mundo a cada momento. Se caracteriza por su posición en el mundo, su orientación y su apertura o "campo visual". El campo visual es la "cantidad" de mundo que la cámara alcanza a ver. Mirad la figura anterior e imaginad que acercamos el plano de Oscar García - Alex Guevara La Salle
9 Conceptos previos proyección a nuestro mundo 3D. En este caso estaremos disminuyendo el campo visual dado que será menos "porción" del mundo la que se proyectará. Por ultimo necesitamos objetos que formen parte de nuestro mundo y que precisamente serán los "filmados" por nuestra cámara. Se caracterizaran por sus atributos de color, material, grado de transparencia, etc. Es muy importante que notéis la independencia que todos estos elementos tienen entre sí. La cámara es independiente de los objetos puesto que estos están en una posición y ella en otra. Manejaremos los objetos (Geometría) por un lado y la cámara por otro de manera que los primeros "actuaran" en nuestro mundo y la segunda filmará desde una determinada posición con un determinado ángulo. Oscar García - Alex Guevara La Salle
10 Conceptos previos 1.4. Arquitecturas gráficas Hablemos ahora del pipeline gráfico, elemento que marcara la pauta de actuación para OpenGL e incluso para vuestras manos en el momento de programar. La geometría que deseáis dibujar será la entrada de vuestro pipeline gráfico y como salida tendréis una imagen en pantalla. Pero lo que ocurre con todos esos puntos, vectores y polígonos desde que entran hasta que salen lo vemos en la siguiente figura: El punto de entrada de nuestra geometría es el superior izquierdo y a partir de ahí solo tenemos que seguir las líneas que conectan los diferentes módulos. Analicemos cada uno de los módulos: Objeto geométrico: nuestro mundo se compone de puntos, líneas, polígonos, etc. en definitiva, primitivas. Inicialmente estos objetos tienen unos atributos que nosotros fijamos pero pueden ser movibles o fijos, deformables o rígidos, y, por tanto, debemos ser capaces de trasladarlos, rotarlos y escalarlos antes de dibujarlos en pantalla. Transformación del modelo: este módulo es el encargado de trasladar, rotar, escalar e incluso torcer cualquier objeto para que sea dibujado en pantalla tal y como debe estar dispuesto en el mundo. OpenGL realiza estas funciones multiplicando a nuestra geometría (vértices) por varias matrices, cada una de las cuales implementa un proceso (rotar, trasladar...) Nosotros usaremos las funciones de OpenGL para crear estas matrices y "operarlas" con nuestra geometría. Oscar García - Alex Guevara La Salle
11 Conceptos previos Coordenadas del mundo: tras haber transformado nuestros vértices, ya sabemos las posiciones de todos los objetos en nuestro mundo. No son relativas a la cámara, recordad que precisamente he incidido en la independencia cámara/mundo. Son posiciones referidas a un sistema de coordenadas que definiremos única y exclusivamente para el mundo que estamos creando. Transformación del visionado: ahora es cuando necesitamos saber "como" se ven esos objetos, ya posicionados correctamente en el mundo, desde nuestra cámara. Por tanto, los "iluminamos" para que sean visibles y tomamos sus posiciones tal y como se ven desde la cámara. Coordenadas de cámara: tras aplicar luces ya sabemos cuales son las coordenadas de todos los objetos respecto de nuestra cámara, es decir, como los vemos nosotros desde nuestra posición en el mundo. Clipping: el clipping consiste en recortar (ocultar) todo aquello que "está" pero "no se ve" desde la cámara. Es decir, si todo aquello que la camara no puede ver, por que no entra en su ángulo de visión, se elimina, a ese proceso se denomina Clipping. Proyección : Pasamos de coordenadas 3D del mundo a coordenadas 2D de nuestro plano de proyección. D.I.S.C. (Device Independent Screen Coordinates): tras proyectar tenemos lo que se llaman "coordenadas de pantalla independientes de dispositivo". Las coordenadas que tenemos calculadas en este momento todavía no se han asociado a ningún tipo de pantalla o monitor. En este punto del pipeline no sabemos si nuestro monitor es de 15 pulgadas y de resolución 800 x 600 o si es de 19 pulgadas y de resolución 1024 x De hecho esto no tenemos porque controlarlo nosotros, nos será transparente. Se trata de asociar la imagen recortada 2D que se encuentra en el frame buffer con los píxeles de la pantalla. Según la resolución de pantalla sea mayor o menor, un punto de nuestro mundo ocupara mas o menos píxeles. Rasterización : este proceso se conoce también como "scan conversion". Finalmente asociamos todos nuestros puntos a píxeles en pantalla. Tras esto solo falta iluminar los fósforos de nuestra pantalla con energía suficiente para que veamos lo que esperamos. Evidentemente esto es un proceso totalmente físico llevado a cabo en el tubo de rayos catódicos del monitor. No actuaremos pues sobre él. Imagen de pantalla: Aquí termina nuestro proceso. Ya tenemos la imagen de lo que nuestra cámara ve en el monitor. El pipeline gráfico puede implementarse vía software o hardware. En maquinas dedicadas, por ejemplo Silicon Graphics, todos los módulos están construidos en la placa madre de manera que el sistema es muy rápido. En sistemas mas convencionales como PC o Mac, todo se realiza vía software y por tanto es mas lento, siempre y cuando no tengamos instalada una tarjeta acceleradora gráfica. De todas formas lo interesante de OpenGL es que funcionará independientemente de la implementación del pipeline. No tendréis que cambiar el código si cambiáis de plataforma, funcionara igual. Lo único es que según el sistema conseguiréis más o menos velocidad. Oscar García - Alex Guevara La Salle
12 Interficie OpenGL. Primitivas y atributos 2. Interfície OpenGL. Primitivas y atributos. Empecemos con algunos comandos básicos de OpenGL. OpenGL tiene sus propios tipos en cuanto a variables se refiere. Así aunque podemos usar los típicos (int, float, double), nos acostumbraremos a los definidos por esta librería (GLint, GLfloat, GLdouble) Como veis son los mismos pero con el prefijo "GL" delante. Se declaran exactamente igual que cualquier variable en C y tienen casi las mismas propiedades. Usémoslos porque el funcionamiento general del sistema será más óptimo. Las funciones OpenGL empiezan con el prefijo "gl", en minúsculas. Veamos un ejemplo. Supongamos que queremos crear un vértice, es decir, un punto: Usaremos: o: glvertex3f( 0.0, 0.0, 0.0 ); GLfloat vértice[3] = { 0.0, 0.0, 0.0 }; glvertexfv( vértice ); Ambas funciones crean un vértice situado en el origen de coordenadas del mundo, es decir, x = y = z = 0.0. En el primer caso el nombre de la función termina en "3f" (3 floats). Esto significa que vamos a especificar el vértice con 3 valores o variables de tipo real, o sea float. En cambio en el segundo caso tenemos "fv" (float vector). Estamos indicando a OpenGL que el vértice lo daremos mediante un array/vector de floats. Precisamente este es el array que defino justo antes de llamar a la función. Trabajamos en 3D y especificamos las coordenadas del vértice en este orden: X, Y, Z. Si deseamos trabajar en 2D solo tenemos que hacer una coordenada igual a 0.0, normalmente la Z. Ya que estamos puestos vamos a definir nuestro primer polígono, un triángulo. OpenGL tiene varios tipos definidos de manera que nos facilita la creación de polígonos simples. Vamos allá: glbegin(gl_triangles); glvertex3f( -1.0, 0.0, 0.0 ); glvertex3f( 1.0, 0.0, 0.0 ); glvertex3f( 0.0, 1.0, 0.0 ); glend( ); Este código crea un triángulo situado en el plano XY ya que observareis que los valores de Z son todos 0.0 para los tres vértices que lo forman. Sus tres vértices se encuentran en las posiciones ( -1.0, 0.0 ), ( 1.0, 0.0 ) y (0.0, 1.0 ) según la forma ( X, Y ). Oscar García - Alex Guevara La Salle
13 Interficie OpenGL. Primitivas y atributos Un polígono se encapsula entre las funciones glbegin y glend. El parámetro que recibe la primera sirve para decirle a OpenGL que tipo de polígono deseamos crear, en nuestro caso un triángulo. GL_TRIANGLES es una constante ya definida en la librería. Por claridad es conveniente tabular (indentar) el código entre glbegin y glend tal y como veis en el ejemplo. Cualquier programa OpenGL que examinéis seguirá esta convención si esta bien estructurado. Vamos a definir alguno de los atributos de nuestro triángulo, por ejemplo su color. Usamos: glcolor3f( 0.5, 0.5, 0.5 ); donde los tres valores (floats) que se le pasan a la función glcolor son por orden, la cantidad de rojo (Red) que deseamos, la cantidad de verde (Green) y la cantidad de azul (Blue). Es el llamado sistema RGB que muchos conoceréis sobradamente. Aplicando una cantidad de cada color conseguimos el tono deseado (Teoría aditiva del color). Los valores de cada color deben estar entre 0.0 (No aplicar ese color) y 1.0 (Aplicar ese color en su máxima intensidad). Por tanto: glcolor3f( 0.0, 0.0, 0.0 ); //se corresponde con el color NEGRO mientras que... glcolor3f( 1.0, 1.0, 1.0 ); //se corresponde con el BLANCO y de esta manera si queremos definir un triángulo blanco obraremos así: glcolor3f( 1.0, 1.0, 1.0 ); glbegin( GL_TRIANGLES ); glvertex3f( -1.0, 0.0, 0.0 ); glvertex3f( 1.0, 0.0, 0.0 ); glvertex3f( 0.0, 1.0, 0.0 ); glend( );...de manera que primero especificamos el color y TODO lo que dibujemos a partir de este momento será de ese color, en este caso el triángulo. Al ejecutar cada función glvertex, el vértice en cuestión "entra" en el pipeline y se traslada a la posición que hemos especificado para él. Entonces se "mapea" en el frame buffer (representación en memoria del plano de proyección 2D) pasando posteriormente a la pantalla de nuestro monitor. Así en este caso tenemos 3 vértices que sucesivamente entran en el pipeline uno detrás de otro. Algo muy importante que debéis tener en cuenta. Cuando defináis un polígono a base de sus vértices deberéis seguir un orden concreto. Si no lo hacéis, OpenGL no asegura que la representación en pantalla sea la correcta. La convención es crear los vértices siguiendo el polígono según el sentido antihorario de las manecillas del reloj. OpenGL supone la cara "a dibujar" del polígono como la que se define de esta manera. Oscar García - Alex Guevara La Salle
14 Interficie OpenGL. Primitivas y atributos Respecto a las constantes que podemos usar en la función glbegin tenemos entre otras: GL_POINTS : para que todos los vértices indicados entre ambas funciones se dibujen por separado a modo de puntos "libres". GL_LINES : cada dos vértices definidos, se traza automáticamente una línea que los une. GL_POLYGON : se unen todos los vértices formando un polígono. GL_QUADS : cada 4 vértices se unen para formar un cuadrilátero. GL_TRIANGLES : cada 3 vértices se unen para formar un triángulo. GL_TRIANGLE_STRIP : crea un triángulo con los 3 primeros vértices. entonces sucesivamente crea un nuevo triángulo unido al anterior usando los dos últimos vértices que se han definido y el actual. GL_QUAD_STRIP : igual que el anterior pero con cuadriláteros. De hecho los tipos mas usados son los tres primeros mientras que el resto pueden sernos de ayuda en casos determinados. Veamos la figura: En la figura se observa como usando diferentes tipos ( GL_POINTS, GL_LINES, etc.) conseguimos diferentes objetos en pantalla dados unos vértices Oscar García - Alex Guevara La Salle
15 Interficie OpenGL. Primitivas y atributos creados según el orden que veis en la figura ( primero p0, luego p1, etc.) para los 6 rectángulos de la primera fila. Es decir: glbegin( TIPO ); glvertex3f( p0x, p0y, p0z ); glvertex3f( p1x, p1y, p1z ); glvertex3f( p2x, p2y, p2z ); glvertex3f( p7x, p7y, p7z ); glend(); Lo que OpenGL dibujará según el caso es lo que se encuentra en color negro en la figura, no el trazado gris que solo lo he puesto como referencia. En la segunda fila de la figura vemos como crear sucesivos "polígonos de cuatro lados" (no tienen porque ser cuadrados o rectángulos, eso depende de en qué posiciones situemos los vértices) con un lado en común de dos a dos. Hay mas variantes que podréis encontrar en las especificaciones de OpenGL aunque no suelen usarse mas que para aplicaciones muy concretas. Los polígonos especificados por una serie de puntos deben ser convexos para su correcto trazado, y coloreado, por parte de OpenGL. Que quiere decir esto?, pues bien se define a un polígono como convexo si cogiendo dos puntos cualesquiera de su interior y trazando la línea que los une, todos los puntos que pertenecen a la línea se encuentran dentro del polígono. En la anterior figura tenéis un ejemplo de esto. Por tanto asegurad siempre que definís polígonos convexos, de lo contrario los resultados son simplemente impredecibles y pocas veces acertados. Entonces, como dibujamos polígonos que no sean convexos? Lo que normalmente se hace es dibujar un polígono complejo, convexo o no, a base de muchos triángulos. Es lo que se denomina "Tesselation". Todo polígono puede descomponerse en triángulos y, por tanto, a partir de estos somos capaces de dibujar cualquier cosa. También lo tenéis en la figura explicitado gráficamente. Usando GLU o GLUT podemos crear con una sola llamada objetos mas complejos como es el caso de una esfera: Usando GLU con: void glusphere( GLUquadricObj *qobj, GLdouble radius, GLint slices, GLint stacks ); Usando GLUT con: void glutsolidsphere(gldouble radius, GLint slices, GLint stacks); En cuanto programemos lo veréis mas claro pero de hecho no dejan de ser funciones en C de las de siempre. Con radius definimos el radio que queremos para la esfera, con slices y stacks la "partimos" en porciones como si de un globo terráqueo se tratara ( paralelos y meridianos) de manera que a mas particiones, mas calidad tendrá ya que OpenGL la aproximara por mas polígonos. En cuanto a *qobj en la primera función, se trata de definir primero un objeto de tipo quadric con otra función de GLU ( glunewquadric ) para después asociar la esfera al susodicho objeto. No os preocupéis Oscar García - Alex Guevara La Salle
16 Interficie OpenGL. Primitivas y atributos porque no usaremos demasiado esta filosofía. De momento quedaros con la idea que es lo que me interesa. A alguien se le ocurrirá probablemente pensar que en estas funciones no se define la posición de la esfera en el mundo. Es cierto y por lo tanto previamente a crearla, y por tanto dibujarla, deberemos especificar donde queremos que OpenGL la dibuje. Lo podemos especificar con: gltranslatef( posx, posy, posz ): función que nos traslada posx unidades en el eje X, posy en el eje Y... y si tras esto llamamos a glutsolidsphere, ya tendremos a nuestra esfera dibujada en el punto que deseamos. Bueno hablemos un poco de los atributos. Una cosa es el tipo de la primitiva a dibujar y otra es como se dibuja, es decir, con que color de borde, con que color de relleno, con que ancho de borde, con que ancho por punto, etc. Estos son algunos de los atributos que pueden especificarse. Algo importante, en OpenGL los atributos no se pueden definir explícitamente para cada objeto sino que lo usual es definir unos ciertos atributos generales de manera que todo lo que se dibuje a partir de ese momento seguirá esas especificaciones. Si deseamos cambiar los atributos deberemos hacerlo en otra parte del programa de manera que la forma de dibujar será diferente a partir de esa línea. Veamos algunas funciones de ejemplo referidas a atributos: glclearcolor( 0.0, 0.0, 0.0, 0.0 ): esta es algo genérica y se refiere al color con el cual debe de "resetearse" el frame buffer cada vez que redibujemos toda la escena de nuevo. En este caso el "fondo" de nuestra ventana será como el fijado por esta función en el frame buffer, de color negro. El cuarto parámetro de la función se refiere al valor de "alpha" en cuanto al color. Veremos mas adelante que el valor de alpha permite variar el grado de transparencia de un objeto. glcolor3f( 1.0, 0.0, 0.0 ): En este caso definimos que todo lo que se dibuje desde este momento será de color rojo. Recordad que el orden de parámetros es Red, Green, Blue ( RGB ). glpointsize( 2.0 ): con esta llamada definimos que cada uno de nuestros puntos deberá tener un grosor de dos pixeles en el momento de ser trasladado a pantalla. glnormal3f( 1.0, 0.0, 0.0 ); cuando operemos con luces veremos que para cada cara de un polígono hay que asociar un vector o normal. Esta función define como normal a partir de este momento a un vector definido desde el origen con dirección positiva de las X. El orden de los parámetros es X, Y, Z. glmaterialfv(gl_front, GL_DIFFUSE, blanco); por ultimo y también referido al tema de las luces. Cada objeto será de un material diferente de manera que los reflejos que en el se produzcan debidos a las luces de nuestra escena variaran según su rugosidad, transparencia, capacidad de reflexión... en este caso definimos que todas las caras principales ( FRONT, son las caras "que se ven" del polígono ) de los objetos dibujados a partir de ahora tendrán una componente difusa de color blanco ( asumiendo que el parámetro "blanco" es un vector de reales que define este color ). La componente difusa de un material define que color tiene la luz que este propaga en todas las direcciones cuando sobre el incide un rayo luminoso. En este caso se vería luz blanca emanando del objeto/s dibujados a partir de ahora. Por supuesto antes hay que definir luces en Oscar García - Alex Guevara La Salle
17 Interficie OpenGL. Primitivas y atributos nuestra escena y activarlas. Lo veremos mas adelante en el apartado de iluminación. En cuanto a los colores, trabajaremos con la convención RGBA, es decir, grado de rojo, verde, azul y transparencia. Los valores para cada componente se encontraran siempre dentro del intervalo [ 0, 1 ]. Si nos pasamos o nos quedamos cortos numéricamente hablando, OpenGL adoptara como valor 1 o 0 según sea el caso. Es decir, que redondea automáticamente aunque hay que evitarle cálculos innecesarios y prever valores correctos. En el caso del valor para alpha, 0 significa transparencia total y de aquí podemos usar cualquier valor hasta 1, objeto totalmente opaco. Que decir del texto...no nos es de mucho interés ahora mismo que lo que estamos deseando es empezar a dibujar polígonos 3D como locos pero comentare un par de cosas. OpenGL permite dos modos de texto: Stroke Text y Raster Text. En el primer caso cada letra del alfabeto es una nuevo polígono literalmente construido a partir de primitivas de manera que puede tratarse tal y como si de un objeto cualquiera se tratara. Es pesado pues tenemos que dibujar literalmente cada letra a base de primitivas pero interesante en cuanto a posibilidades pues podremos escalar, rotar, trasladar...en fin todo lo que nos es posible aplicar a un polígono. En cuanto al segundo caso tenemos un ejemplo de simplicidad y rapidez. Es el típico alfabeto creado a partir de bloques de bits ( BitMaps ), de manera que tendremos una rejilla sobre la que un 1 significara lleno y un 0 vacío. De esta forma:...se corresponde con la letra H Así podremos crearnos fácilmente un alfabeto y posicionar directamente en el frame buffer sendas letras. Para ello es necesario conocer como acceder directamente, al nivel de bit, al frame buffer y esto aun nos tomara algo de tiempo. Oscar García - Alex Guevara La Salle
18 Transformaciones 3. Transformaciones Coordenadas Homogéneas Todos estamos acostumbrados a utilizar coordenadas cartesianas para representar los vértices que definen a nuestra geometría. Es decir un punto es algo así: P = ( x, y, z) y representa una determinada localización en un espacio 3D. Pero cuando programamos Gráficos hablamos de puntos y de vectores y pueden confundirse en cuanto a representación. Si entendemos que un vector es una resta entre dos puntos: Vector v = Punto1 - Punto2 = (x1, y1, z1) - (x2, y2, z2) = (a, b, c) Obtenemos el mismo aspecto que un punto. Por otra parte trabajaremos modelando geometría para luego transformarla: trasladándola a otra posición, rotándola respecto de un eje, escalándola para cambiar su tamaño, etc. Estas son las llamadas transformaciones afines/rígidas/lineales. Dado que operamos usando matrices para efectuar estas transformaciones necesitamos modificarlas ligeramente por dos motivos: Para que no alteren de igual forma a un vector y a un punto, lo cual sería incorrecto. Para poder efectuar algunas transformaciones afines como la traslación, imposibles de efectuar multiplicando matrices si no se usan coordenadas homogéneas. Es muy sencillo convertir un vector o un punto cartesiano a su representación homogénea. De hecho lo que se hace es añadir una nueva coordenada a las típicas XYZ. Añadimos la componente W de esta forma: Punto P1 = (x1, y1, z1) en cartesianas es P1 = (x1, y1, z1, w1) en homogéneas. Vector v = (a, b, c) en cartesianas es v = (a, b, c, w) en homogéneas. Los valores típicos para la nueva componente son: W = 1, cuando tratemos con puntos. W = 0, cuando sean vectores. Por tanto, el caso anterior queda modificado de la siguiente manera: Punto P1 = (x1, y1, z1, 1) en homogéneas. Vector v = (a, b, c, 0) en homogéneas. Oscar García - Alex Guevara La Salle
19 Transformaciones Veremos más adelante en este capítulo como este convenio nos permite operar transformando un punto en otro punto, y un vector en otro vector, sin tener que efectuar una operación diferente en cada caso. En el caso que W sea diferente que 1 ó 0, tendremos que efectuar una sencilla operación para transformar un punto homogéneo en uno cartesiano. Si tenemos el punto: P1 = (x1, y1, z1, w1) en homogéneas, entonces en cartesianas el punto es P1 = (x1/w1, y1/w1, z1/w1). Es decir, que normalizamos cada una de las componentes XYZ del punto por su componente W. En el caso de W = 1 no hay que hacer nada pues la división es obvia, pero puede pasar que nos interese variar W y entonces no podremos usar las XYZ hasta haberlas normalizado según os acabo de explicar. Por lo tanto, podemos decir que: P = (1, 2, 3, 1) = (2, 4, 6, 2) = (5, 10, 15, 5) Una observación importante: podemos transformar de dos maneras distintas pero totalmente equivalentes. Es exactamente lo mismo transformar un vértice respecto de un sistema de referencia que transformar, en orden inverso, el sistema de referencia dibujando después el vértice en éste. Las transformaciones afines se llaman así porque conservan las lineas, como podemos ver en la figura: Figura 1. Las transformaciones afines conservan las lineas. Se observa que tan sólo transformando los vértices y uniéndolos de nuevo obtendremos como resultado final la línea que los une transformada. De esta forma queda claro que sólo tendremos que aplicar transformaciones a los puntos, vértices, de nuestra geometría, uniéndolos después con segmentos rectos. Oscar García - Alex Guevara La Salle
20 Transformaciones 3.2. Escalar Gracias a la función de escalado podemos aumentar/disminuir un objeto en cuanto a tamaño. Tan sólo tendremos que multiplicar a cada uno de sus vértices por la matriz de escalado, uniéndolos después con líneas tal y como estaban al inicio: Figura 2. Escalar un cubo. En el ejemplo se observa el efecto claramente. El cubo original es el de color rojo y como veis está centrado en el origen. El cubo escalado es el de color verde. Es 2 veces mayor que el original al haber efectuado un escalado de 2.0 sobre todas sus componentes. La matriz que se ha aplicado a cada uno de los vértices del cubo la tenéis en la figura Trasladar Esta es precisamente una transformación afín imposible de realizar en cartesianas si no se incluye una suma de matrices. Pero nosotros no queremos sumar, tan sólo multiplicar. Y es que la mayoría de los "pipeline's" gráficos implementados vía hard en aceleradoras 3D o tarjetas de video esperan recibir matrices para concatenarlas y multiplicarlas. Si intentamos aplicar la transformación que vemos sin usar coordenadas homogéneas, es decir, con un vector y una matriz de 3 x 3, veremos como es imposible hacerlo. Necesitamos sumar algo al resultado para lograrlo. Oscar García - Alex Guevara La Salle
Transformaciones en OpenGL Aquí se explican las transformaciones en OpenGL. Se incluyen algunas nociones básicas con la única intención de entender la práctica y de qué estamos hablando. En otro documento
1. INTRODUCCIÓN A OPENGL: DIBUJANDO UNA TORTUGA CON OPENGL
1. INTRODUCCIÓN A OPENGL: DIBUJANDO UNA TORTUGA CON OPENGL 1.1 QUÉ ES OPENGL? Qué es OpenGL? OpenGL es una interfaz software de harware gráfico, es decir define las funciones que se pueden utilizar en
Gràfics per computador Departament de Sistemas Informàtics i Computació Escola Politècnica Superior d Alcoi Enginyeria Tècnica en Informàtica de Gestió PRÀCTICA 3 Jordi Linares i Pellicer jlinares@dsic.upv.es
Es un SW (en forma de librería C) que permite la comunicación entre el programador y el HW de la máquina para el diseño de gráficos.
Qué es Open GL? Es un SW (en forma de librería C) que permite la comunicación entre el programador y el HW de la máquina para el diseño de gráficos. Es portable. Consta de unos 150 comandos muy básicos.
El color es una longitud de onda de luz, visible para el ojo humano
Color Teoría del color El color es una longitud de onda de luz, visible para el ojo humano 390nm 720 nm El color que vemos en los objetos es resultado de la luz reflejada por su superficie El negro es
INTRODUCCIÓN A OpenGL 1. Introducción...2 2. Abriendo una ventana gráfica para dibujar...2 3. Dibujo de primitivas gráficas...3 4. Tipo de datos de OpenGL...4 5. Estado de OpenGL...5 6. Sistema de Coordenadas...6
Mini Manual de OpenGL Por Daniel Barrero (dbarrero@cable.net.co) - 11/6/2002
Mini Manual de OpenGL Por Daniel Barrero (dbarrero@cable.net.co) - 11/6/2002 Introducción OpenGL es una interface de software para el hardware grafico, esta interface consiste de una larga serie de comandos
Capítulo VI: Java 3D
Capítulo VI: Java 3D 6.1 Definición Java 3D es un API de gráficos 3D desarrollada por Sun como una extensión del JDK 2 del lenguaje de programación Java. Es una colección de clases que tienen como objetivo
Curso de introducción a OpenGL (v1.0)
Por Jorge García (Bardok) Este manual ha sido realizado para el e-ghost, por Jorge García, está sujeto a la licencia FDL (GNU Free Document License), y confiere los derechos y obligaciones pertinentes.

References: resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución