Programación OpenGL

73
Programación OpenGL: Escenas 3D por Miguel Angel Sepúlveda Después de un largo camino por otros temas, finalmente ha lle momento de hablar de gráficos en 3D bajo OpenGL. No voy a men diciendo que es un tema fácil porque no lo es. Cualquier buen programador de aplicaciones 3D con OpenGL, y en particular de animaciones, debe tener suficientes conocimientos de álgebra geometría analítica, física (mecánica) y por supuesto dominar numérico. Intentaré hacer el resto de esta serie lo mas accesible posib mundo. Desafortunadamente, no hay forma de evitar la necesida conocimientos sobre matrices, cómo los planos y líneas se rep matemáticamente en el espacio 3D, vectores, aproximaciones polinomiales a curvas, por mencionar solo unos pocos. Durante la última semana he estado pensando como presentar es material más complejo a una audiencia amplia. Los libros clás una metodología incremental paso a paso, más o menos el métod seguido en los dos artículos anteriores. He decidido no segui metodología pues se necesitaría demasiado tiempo (meses) para llevar al lector al punto de poder escribir su propio código. voy a aventurarme a utilizar otro método, que he decidido lla "tratamiento de choque". Esta vez voy a incluir una demostrac de mis simulaciones 3D y luego explicare bit por bit qué hace Finalmente, intentaré explicar con más detalle todas las cues normalmente se tratan en los libros estándar de OpenGL. Creo saltando directamente al final y dando al lector un ejemplo d algunas cosas interesantes incitará a los lectores a experime cosas, incluso aunque yo no haya dicho aun como funcionan tod cosas exactamente. Espero que este método funcione y la gente encuentre rápido y más directo. Así que pongamos manos a la obra. Durante los 6 meses anterio estado trabajado en la universidad de Pittsburgh en una herra (Object Oriented) para el desarrollo de simulaciones de polím El proyecto está bastante avanzado, la física es muy interesa para informáticos, porque un gel es básicamente una red neuro polímeros y muchas de las técnicas desarrolladas para redes n

Transcript of Programación OpenGL

Programacin OpenGL: Escenas 3Dpor Miguel Angel SeplvedaDespus de un largo camino por otros temas, finalmente ha llegado el momento de hablar de grficos en 3D bajo OpenGL. No voy a mentir diciendo que es un tema fcil porque no lo es. Cualquier buen programador de aplicaciones 3D con OpenGL, y en particular de animaciones, debe tener suficientes conocimientos de lgebra lineal, geometra analtica, fsica (mecnica) y por supuesto dominar el anlisis numrico. Intentar hacer el resto de esta serie lo mas accesible posible para todo el mundo. Desafortunadamente, no hay forma de evitar la necesidad de tener conocimientos sobre matrices, cmo los planos y lneas se representan matemticamente en el espacio 3D, vectores, aproximaciones polinomiales a curvas, por mencionar solo unos pocos. Durante la ltima semana he estado pensando como presentar este material ms complejo a una audiencia amplia. Los libros clsicos utilizan una metodologa incremental paso a paso, ms o menos el mtodo que he seguido en los dos artculos anteriores. He decidido no seguir con esta metodologa pues se necesitara demasiado tiempo (meses) para conseguir llevar al lector al punto de poder escribir su propio cdigo. En su lugar voy a aventurarme a utilizar otro mtodo, que he decidido llamarlo "tratamiento de choque". Esta vez voy a incluir una demostracin de una de mis simulaciones 3D y luego explicare bit por bit qu hace el cdigo. Finalmente, intentar explicar con ms detalle todas las cuestiones que normalmente se tratan en los libros estndar de OpenGL. Creo que saltando directamente al final y dando al lector un ejemplo de cdigo con algunas cosas interesantes incitar a los lectores a experimentar y a probar cosas, incluso aunque yo no haya dicho aun como funcionan todas las cosas exactamente. Espero que este mtodo funcione y la gente lo encuentre rpido y ms directo. As que pongamos manos a la obra. Durante los 6 meses anteriores he estado trabajado en la universidad de Pittsburgh en una herramienta OO (Object Oriented) para el desarrollo de simulaciones de polmeros y geles. El proyecto est bastante avanzado, la fsica es muy interesante, incluso para informticos, porque un gel es bsicamente una red neuronal de polmeros y muchas de las tcnicas desarrolladas para redes neuronales se

Programacin OpenGL: Escenas 3Dpor Miguel Angel Seplveda

pueden aplicar a la construcciones del gel. He elegido unos cuantos objetos de esta herramienta y los he empaquetado en esta sencilla demo: ../../common/May1998/example2.tar.gz. Se puede compilar bajo Linux, cualquier UNIX o sobre Windows 95/NT (suponiendo que ya tienes instalado GLUT). La demo muestra un polmero simple (una cadena lineal de monmeros enlazados) movindose en suspensin en una solucin a una determinada temperatura. La dinmica es tentadora, se asemeja a una serpiente excitada. La animacin es muy viva debido a las colisiones de las molculas del solvente. No se puede ver el solvente, pero influye en el movimiento del polmero a travs de las ecuaciones del movimiento. El modelo utilizado para dibujar el polmero es bastante sencillo; example2 controla las coordenadas (x, y, z) de cada nodo (monmero) a lo largo de la cadena polmero. En cada imagen (frame) de la animacin dibujamos una esfera en las coordenadas del monmero y luego los unimos utilizando cilindros que van de monmero a monmero. Por tanto tenemos dos primitivas elementales 3D: una esfera y un cilindro. Como en cualquier molcula, la distancia entre monmeros cambia en el tiempo, con lo que no podemos utilizar "un cilindro" para dibujar todos los enlaces, se ha de re-escalar de acuerdo a la distancia entre cada par de monmeros. Primera pregunta: Has dicho que tienes dos objetos en 3D, una esfera y un cilindro unidad. digamos que ambos objetos estn centrados en el origen de coordenadas. Si todo lo que sabemos sobre el polmero es la secuencia de (x, y, z) de los nodos, cmo podemos escalar, rotar y trasladar las replicas de los cilindros para crear los enlaces de los polmeros?

Por alguna razn que no logro comprender, los cientficos informticos han decidido cambiar el significado clsico de las coordenadas cartesianas: x es horizontal, y es vertical y z va en direccin al observador. Ten cuidado con esto porque si vienes de una formacin matemtica te puede confundir bastante. En la parte superior de la ventana de la animacin se muestra informacin sobre el estado de la animacin que te permitir saber en todo momento el tiempo, la temperatura del polmero, temperatura media del polmero, temperatura de la solucin, la friccin del solvente y el ngulo de rotacin de la cmara exterior. Para tener una visin ms amplia del polmero desde todos los lados, la cmara (tu punto de vista) gira lentamente al rededor del centro de gravedad del polmero. De echo la longitud del polmero que he elegido para la demo es tan corta que la rotacin de la cmara no es realmente necesaria, con un poco de tiempo el polmero llega a girar l solo. Sigue adelante y edita el fichero example2.cxx y modifica la definicin de POLYMERLENGTH a un valor entre 2 y 100. La cmara gira porque quiero que el lector se d cuenta de un aparente problema: cambia del sistema de coordenadas. El sistema de coordenadas de los nodos es utilizadas por las ecuaciones del movimiento y por tato estn expresadas en coordenadas del mundo, independientes del punto de vista concreto desde el que el usuario observa la escena. Estas coordenadas deben proyectarse a las coordenadas 2D x-y de la pantalla del ordenador. Cada vez que cambias el punto de vista, cambian las formulas que transforman las coordenadas internas del polmero en coordenadas 2D de la ventana. Segunda pregunta. Cmo solucionas este problema? cambiando las ecuaciones del movimiento del mundo real a coordenadas 2D del punto de vista no es una solucin, pues requiere demasiada lgebra, es muy complicado de implementar y es difcil no cometer errores. La respuesta a la segunda pregunta es sencilla. Slo hay una opcin: realizar toda la dinmica y la representacin del modelo 3D (polmero) en las coordenadas del mundo y luego cambiar las coordenadas del mundo a las coordenadas 2D del punto de vista de la cmara en el momento de dibujar (render) la imagen. OpenGL es bastante eficiente realizando estas transformaciones, incluso se pueden realizar por hardware (para aquellos que posean una tarjeta grfica con soporte OpenGL vern la diferencia). Pero antes de entrar a describir cmo OpenGL resuelve este problema, consideremos primero cuntas transformaciones de coordenadas hay desde el mundo real en 3D a las coordenadas finales 2D de la ventana.

Primero viene la transformacin de coordenadas del modelo (Modelview), para proyectar las coordenadas originales del mundo a las coordenadas de la vista (eye coordinates), estas son las coordenadas 3D relativas a la posicin del ojo del que mira la escena (o sea las coordenadas de la cmara). Se llama transformacin Modelview porque ----------------- It is called Modelview transformation because it really involves many similar though distinct operations. ----------------- Modelando y viendo proyecciones, lo ltimo es anlogo a posicionar una cmara de fotos en un estudio enfocando hacia la escena que se ha de fotografiar; el modelado de la proyeccin es entonces como posicionar el objeto a fotografiar en frente de la cmara.

Siguiendo la secuencia de transformaciones, las coordenadas de la vista se pasan a las coordenadas de transformacin de la proyeccin. El propsito de estas transformaciones puede parecer un poco esotrico a estas alturas. Despus de posicionar la cmara en la direccin correcta y de posicionar los objetos en el campo de la escena, OpenGL quiere saber qu cantidad (volumen) de campo debe ser proyectado sobre la ventana 2D de la pantalla. Por ejemplo, la cmara puede estar dirigida hacia una montaa muy distante, el campo que vemos define un volumen de espacio muy grande. Los ordenadores slo pueden trabajar con cosas finitas, por ello hay que especificar qu cantidad, de toda la escena, ha de ser recortada. Esta transformacin tambin se encarga de eliminar las superficies que no se pueden ver. Las coordenadas finales obtenidas son las Clip coordinates, recuerda siempre que no es suficientes que tus objetos 3D estn en frente de la cmara, sino que deben estar situados dentro de los planos de recorte definidos por la transformacin de proyeccin. Las distintas perspectivas 3D (como cnica u ortogonal) se definen en este nivel. Por el momento no entraremos en qu es una perspective division, ni cul es la diferencia entre las coordenadas de recorte y las coordenadas normalizadas de dispositivo. No es necesario saberlo aun. La ltima transformacin de coordenadas importante es la transformacin del Viewport. Aqu las coordenadas 3D que han pasado por todo tipo de transformaciones 3D son finalmente proyectadas en el rea 2D de la ventana de tu ordenador. Las transformaciones de coordenadas se representan por matrices (matrices de dos dimensiones). Para cada uno de los anteriores tipos de transformaciones hay una matriz asociada. stas pueden ser especificadas en cualquier momento del programa antes de dibujar la imagen. OpenGL mantiene una pila de matrices de transformacin que se han de aplicar sobre cada punto de la escena. Esta es una tcnica muy eficiente y til que exploraremos en futuros artculos. Por el momento vayamos al cdigo fuente, donde se definen algunas de estas transformaciones. En el fichero example2.cxx encontramos las ya familiares funciones reshape:void mainReshape(int w, int h){ // VIEWPORT TRANSFORMATION glViewport(0, 0, w, h); // PROJECTION TRANSFORMATION glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(wnLEFT, wnRIGHT, wnBOT, wnTOP, wnNEAR, wnFAR); // MODELVIEW TRANSFORMATION glMatrixMode(GL_MODELVIEW); ....

La directiva glViewport(x, y, width, height) especifica la transformacin del Viewport: x, y son las coordenadas de la esquina inferior izquierda del rectngulo de la ventana de dibujo y width y height las dimensiones del viewport. Todos los nmeros se expresan en pixels. Entonces la funcin glMatrixMode(), utilizado para seleccionar la matriz actual, es invocada con los parmetros GL_PROJECTION para comenzar la especificacin de la transformacin de proyeccin. Antes de especificar cualquier transformacin de matrices es recomendable cargar la matriz unidad (que no hace nada sobre los vrtices de coordenadas), esto se hace con glLoadIdentity(), asigna la matriz unidad a la matriz actual. Luego viene la declaracin de la perspectiva 3D; la sentencia es glFrustum(left, right, bottom, top, near, far) declara los planos de recorte en las posiciones izquierda, derecha, abajo, arriba, cerca y lejos. Estos nmeros estn especificados en coordenadas del punto de vista (eye) y su magnitud determina la forma (la perspectiva) del volumen del espacio que se va a proyectar en el viewport (pantalla del ordenador). Quizs parezca complicado, a m me llevo un tiempo acostumbrarme. La mejor forma de entenderlo es experimentando con varios nmeros, recuerda siempre que has de elegir nmeros de forma que el objeto modelado-visto caiga dentro de los planos de recorte o no vers nada en la pantalla. Hay otras formas de especificar la transformada de proyeccin. Con el tiempo llegaremos a verlas. Finalmente cambiamos la matriz actual a la matriz del modelview, otra vez con la funcin glMatrixMode() y utilizando GL_MODELVIEW como parmetro. La funcin mainReshape() continua con otras cosas que no tienen nada que ver y acaba. Lo que importa es que despus de que la ventana principal ha sido re-dimensionada, esta funcin ha especificado el viewport y la transformada de proyeccin y finalmente establece como matriz actual, la matriz modelview. Lo que sucede luego es que la funcin mainDisplay() termina la especificacin del modelview y finalmente dibuja el polmero con scene():void mainDisplay(){ glutSetWindow(winIdMain); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Limpiar los buffers de color y profundidad // Esto es como limpiar la pizarra. // Continuar con la transformacin MODELVIEW: // posicionar y orientar la cmara. glLoadIdentity(); // Cargar matriz unidad glTranslatef(0.0, 0.0, -4.0); // Mover la cmara 4 unidades atrs // dejamos la cmara apuntando en la direccin "-z". Realmente // esto funciona moviendo la siguiente escena 4 pasos en el eje "z". // Solo los elementos de la escena que queden dentro de el volumen // de representacin (ver transformacin de proyeccin ms adelante) // se vern en la pantalla.

// Dibujar el polmero glScalef(0.5, 0.5, 0.5); glRotatef(Angle, 0, 1, 0); scene(); }; glutSwapBuffers();

Espero no haber confundido mucho al lector por haber utilizado dos sub-ventanas. No estoy explicando cuestiones relativas a las sub-ventanas porque ya las expliqu en el artculo anterior ( Gestin de ventanas). Si tienes alguna duda, puedes ir a este artculo para refrescar la memoria. Esta funcin es muy simple. Primero glClear borra los buffers de color y profundidad. El buffer de profundidad es importante ahora en 3D porque la coordenada z de cada vrtice ha de ser comparada para determinar las superficies ocultas y eliminarlas. Despus cargamos la matriz unidad en la matriz actual modelview e invocamos las tres transformaciones de modelado: glTranslatef(xt, yt, zt) , esto traslada el sistema de coordenadas actuales por el vector (xt, yt, zt). En nuestro caso, tiene el efecto de mover la cmara 4 unidades hacia atrs a lo largo de z, esto es, alejarse del modelo. Si no hacemos esto,

la cmara se quedara en el origen, en medio de la escena, con lo que difcilmente podramos ver nada. glScalef(xs, ys, zs) , como su nombre indica, su misin es la de escalar el sistema de coordenadas por los factores xs, ys, zs a lo largo de los ejes x, y, z respectivamente. Este escalado es necesario para que la escena expresada en coordenadas del mundo (polmero) quepa en las coordenadas del volumen visible. glRotatef(angle, vx, vy, vz) , gira el sistema actual de coordenadas a lo largo del vector normalizado (vx, vy, vz) el ngulo angle. Este es el truco que utilizamos para producir la ilusin de que la cmara gira al rededor de la escena. De hecho es la escena la que est girando. Hay muchas otras formas de mover la cmara, pero por el momento est es la ms sencilla.

Unas palabras de advertencia: el orden en el que se aplican las transformaciones de modelado es muy importante. Es necesario comprender qu es lo que sucede con la matriz de Modelview cada vez que invocas a una transformacin de coordenadas. Cada transformacin Ti se representa matemticamente por una matriz Mi. La superposicin de una secuencia de transformadas Tn Tn-1... T1 (por ejemplo: translacin + escalado + rotacin ) es representado matemticamente por una nica matriz M = Mn Mn-1 .... M1. El orden es crucial porque cuando la transformacin compuesta M acta sobre un vrtice v, las transformaciones son realmente aplicadas en el orden inverso: M v = Mn Mn-1 .... M1 v Primero M1, luego M2, etc.. y finalmente Mn. En nuestro cdigo ejemplo, he declarado la transformacin en el siguiente orden: translacin -> escalado -> rotacin. Por tanto, cada

punto del modelo en las coordenadas del mundo va a ser rotado -> escalado -> trasladado antes de ser proyectado sobre la pantalla grfica. Siempre has de tener este orden inverso de transformaciones en la cabeza cuando escribas cdigo, en caso contrario puedes obtener resultados no deseados muy sorprendentes. La funcin scene() sencillamente ejecuta el dibujado 3D (render) del objeto polmero. Para entender como se construye el modelo 3D, tenemos que ir al fichero Gd_opengl.cxx y echar un vistazo a la funcin miembro draw(GdPolymer &p). Hay un bucle principal que pasa por cada monmero de la cadena del polmero, obtiene sus coordenadas x,y,z dibuja una esfera en esa posicin, y luego dibuja los cilindros a lo largo de los enlaces que conectan cada monmero Recuerdas la primera pregunta? Aqu tenemos una posible solucin... Si encuentras otra ms rpida dmelo. Hay un cosa ms que el lector debe saber para entender completamente la rutina de dibujado del polmero Para qu sirven lasfunciones: glPushMatrix() y glPopMatrix()? Hay slo dos primitivas geomtricas en el modelo del polmero, una esfera de radio 0.40 centrada en el origen y un cilindro superior derecho de altura 1.0 y radio 0.4. El polmero se construye utilizando dos primitivas y una serie de transformaciones para situar las esferas y cilindros en las posicies correctas. Cada vez que se ejecutan las sentencias glCallList(MONOMER) o glCallList(CYLINDER) se dibuja una nueva esfera y cilindro en el origen. Para mover las esferas a las coordenadas x,y,z necesitamos una translacin (ver glTranslatef(x, y, z)); para dibujar y posicionar un cilindro es ms complicado porque tenemos que orientarlo en la direccin adecuada (en mi algoritmo utilizo una transformacin de escalado->rotacin). Pero cualquiera que sea el mtodo que utilices para construir modelos complejos 3D, no hay duda que necesitars varias transformaciones de translacin, rotacin y escalado. Cuando se invoca la funcin scene(), la matriz actual de la mquina de estados OpenGL es la matriz MODELVIEW, como he mencionado anteriormente, sta es la matriz que representa la proyeccin del modelo de coordenadas del mundo a coordenadas de recorte. ste es un problema serio, mientras la matriz MODELVIEW sea todava la matriz activa, cualquier nueva transformacin aplicada para construir el modelo 3D se aadir a la matriz actual, con la consecuencia indeseable de destruir la transformacin MODELVIEW. De forma similar, algunas veces queremos aplicar determinadas transformaciones 3D a una parte del modelo pero no a otras (por ejemplo, escalar un cilindro pero no la esfera). OpenGL resuelve este problema utilizando una pila interna de matrices. Hay dos operaciones bsicas sobre esta pila implementadas mediante glPushMatrix() (meter en pila) y glPopMatrix() (sacar de pila). Examina una vez ms el cdigo fuente de scene() y observars que antes de dibujar la esfera de cada nommero llamamos una vez a "push", para mover la matriz MODELVIEW a la pila, y al final del bucle llamamos a "pop" para restaurar la matriz MODELVIEW. El bucle interno que dibuja los enlaces del polmero tiene sus propios "push" y "pop" para aislar las transformaciones de escalado y rotacin de las translaciones que afectan a ambos, esfera y cilindro.

Hay mucho ms que decir sobre transformaciones 3D y pilas de matrices. En este artculo slo hemos araado la superficie de estas cuestiones. Por el momento lo dejaremos as y dejaremos que el lector interesado explore el cdigo fuente de la demo e intente construir sus propios modelos 3D. El cdigo example2 tambin utiliza unas cuantas caracterstica aun no estudiadas: materiales e iluminacin. Dejamos la presentacin de estos temas para artculos futuros. La prxima vez, continuaremos explorando con mayor profundidad las transformaciones 3D y las pilas de matrices, tambin mostraremos como utilizar ambas caractersticas de OpenGL para implementar un robot mvil. Hasta entonces, pasatelo bien con OpenGL.

Primeros pasos en OpenGLEste tutorial cubre los primeros conceptos previos a la creacin de aplicaciones con OpenGL y en general a la creacin de contenido 3d. Es necesario aclarar que el tutorial, por simplicidad y extensin se enfoca sobre la especificacin 1.1 de OpenGL, es decir, solo se menciona la funcionalidad de la llamada Fixed Pipeline (ahora con la entrada de OpenGL 2.0 y la introduccin de los shader al estndar, la estructura cambio). En el tutorial se mencionan algunas palabras en ingles, acompaadas de su traduccin al espaol, solo para conservar el trmino original (en ingles) y facilitar la bsqueda posterior del trmino, tanto en espaol, como en ingls. Qu es OpenGL? : OpenGL (Open Graphics Library) es un API (de Aplication Programming Interface, Interfaz de Programacin de Aplicaciones) libre, multiplataforma, orientado a la creacin de contenido 3d. A un nivel ms simple se puede decir que es una librera que permite hacer software con grficos 3d sin preocuparse por el hardware en que se va a ejecutar y que tiene un gran soporte en diferentes sistemas operativos como Windows, OS/2, UNIX, FreeBSD , Linux, etc. Hay que hacer una diferencia clara, OpenGL no es un lenguaje de programacin, pero se puede trabajar con l desde diferentes lenguajes como c+ +, c#, java y Visual Basic. Para que puedo usar OpenGL? : OpenGL puede ser usado para todo tipo de aplicaciones que necesiten visualizacin 3d en tiempo real de alto rendimiento y calidad, en esto estn incluido los videojuegos, CAD, aplicaciones cientficas, mdicas, militares, simuladores, etc. Qu necesito para utilizar OpenGL en mis programas? Es buena idea utilizar un IDE como Visual Studio, Eclipse o DevCpp para realizar los programas, ya que facilita mucho el trabajo, adicionalmente, en los archivos fuente donde se utilicen funciones de OpenGL es necesario incluir las bibliotecas de prototipos gl.h y glu.h, que generalmente se encuentran preinstaladas no solo en Visual Studio, sino en otros entornos donde se soporta el uso de OpenGL. Tambin es necesario hacer un link con las libreras binarias, en Visual Studio las dos cosas se veran como:PLAIN TEXTC++:

1. 2. 3. 4. 5. 6. 7. 8. 9.

//Inclusin de las libreras prototipo #include #include //Link con las libreras binarias #pragma comment(lib, opengl32.lib) #pragma comment(lib, glu32.lib)

Es importante notar 2 cosas, las libreras binarias que estamos usando corresponden a la implementacin de software de Microsoft (el 32 al final lo indica), que finalmente utilizan las libreras dinmicas opengl32.dll y glu.dll localizados en el directorio de Windows y por otra parte, no todos los IDE y sistemas operativos obedecen a la misma forma de inclusin de OpenGL, por lo que el desarrollo variar ligeramente en este punto, para mayor informacin al respecto ver http://nehe.gamedev.net/. Con estas pequeas aclaraciones, es necesario pasar a algunos conceptos fundamentales del 3d. SISTEMAS DE COORDENADAS Para trabajar grficos bien sea 2d o 3d es necesario tener una forma de describir la posicin de un objeto cualquiera en el espacio. Para esto es necesario establecer un patrn de referencia, lo cual se hace generalmente a travs de un sistema de coordenadas y el sistema al que mas estamos acostumbrados es el de coordenadas cartesianas, en el cual un punto puede ser expresado como una distancia a travs uno (x), dos (x,y) o tres ejes (x,y,z) mutuamente perpendiculares que se intersecan en el punto (0,0) en el caso de dos dimensiones y (0,0,0) en el caso de tres.

OpenGL maneja los sistemas 2d y 3d, aunque el sistema de 2d sobre pxeles en pantalla es bastante ineficiente, por lo que en la mayora de los casos mejor utilizar 3d y simular el 2d con una proyeccin ortogrfica de la escena.

Primeros pasos en OpenGLSi bien la forma en que se representan las coordenadas cartesianas en matemticas es bastante estndar (x positivo a la derecha y y positivo arriba), en los sistemas de dibujo en el computador hay variaciones dependiendo del sistema de dibujo sobre el cual se est trabajando y el caso del 3d es totalmente dependiente de desde donde, hacia donde y que es arriba. Esto quiere decir que las coordenadas del sistema abstracto no tienen que ser concordantes con el sistema de coordenadas sobre la pantalla, por lo que se deber realizar un proceso llamado mapeo de coordenadas. En este caso el mapeo debe hacerse del sistema abstracto de coordenadas de OpenGL al sistema de coordenadas en ventana del sistema operativo (window, UNIX, linux, mac, etc). El siguiente esquema muestra tres posibles formas de realizar el mapeo de coordenadas:

El grafico muestra tres de las posibles formas de realizar el mapeo las coordenadas. En el Modo 1, el punto (0,0) en coordenadas de dibujo es el correspondiente al extremo inferior izquierdo de la ventana y el punto (200,200) estar en el extremo superior derecho. Tal vez es uno de los modos que parece ms natural En el Modo 2, el punto (0,0) en coordenadas de dibujo es el centro de la ventana y los puntos extremos estarn situados en los cuatro cuadrantes, en (100,100) superior derecha, (-100,100) superior izquierda, (-100.-100) inferior izquierda y (100,-100) inferior derecha. Este modo es similar a la forma en que lo muestra la cmara por defecto de OpenGL, con el agregado del eje z positivo saliendo de la pantalla. En el Modo 3, el punto (0,0) en coordenadas de dibujo se encuentra en el extremo superior izquierdo de la ventana y el punto (200,200) corresponde al extremo inferior derecho. Hay que notar, que en este modo el eje y positivo se encuentra cabeza abajo, es decir, cuando un punto aumenta su coordenada y va hacia abajo, no hacia arriba. Este modo es usado generalmente por los dispositivos de hardware y es la forma por defecto de GDI. Estas son solo algunas formas de mapeo de coordenadas y en cualquier caso y con un poco de matemticas (matrices de transformacin) se puede pasar de cualquier modo de mapeo a otro. PROYECCION Los monitores actuales de PC, los televisores, las pantallas de PDA, de celulares y consolas porttiles son todos dispositivos bidimensionales, la percepcin 3d sobre estos dispositivos se debe a un conjunto de trucos para engaar al ojo humano y hacerle ver objetos tridimensionales sobre un dispositivo bidimensional, el primero de estos trucos es la proyeccin. La proyeccin consiste en generar una imagen bidimensional de una escena tridimensional, algo as como sacarle una foto, o pintar un cuadro de la escena. Tal vez las

dos mas conocidas y las que permite trabajar OpenGL directamente son la ortogrfica y la perspectiva. Proyeccin Ortogrfica: En este tipo de proyeccin se trazan rayos paralelos al plano de proyeccin (son paralelos porque se considera la fuente de luzo centro de proyeccin en el infinito) y la imagen se forma con aquellos rayos que intersequen al objeto. Esto se ve mas claro en el diagrama.

Las imgenes producidas por este tipo de proyeccin se ven como si el objeto se hubiera aplanado sobre el plano de proyeccin (que puede ser tomado como la pantalla), es decir, no existe sensacin de profundidad, ya que variando la distancia del objeto al plano de proyeccin, no variar el tamao de la imagen producida por este. Este tipo de proyeccin es usada en aplicaciones CAD porque permite ver el modelo desde diferentes partes (bien sea rotando el objeto o la cmara) sin que se deformen las dimensiones en la proyeccin. Una forma de dibujo 2d basada en esta proyeccin es utilizada en los videojuegos, se trata de los juegos con perspectiva isomtrica donde se conservan parte de las medidas, al igual que las lneas paralelas. Tambin es posible realizar juegos 2d utilizando esta perspectiva, ya que los grficos se ven planos sobre la pantalla porque su dimensin es independiente de su profundidad con respecto al plano de proyeccin.

Primeros pasos en OpenGLProyeccin en Perspectiva: La fuente de rayos en este caso no se encuentra en el infinito, sino que es un punto localizado llamado punto de fuga. Los rayos que parten del punto de fuga e intersecan al objeto son entonces los que formaran la imagen sobre el plano de proyeccin.

En la proyeccin en perspectiva los objetos sufren una deformacin por la distancia, a medida que los objetos se alejan del plano de proyeccin disminuyen su tamao justo de la forma en que ocurre cuando un objetos se aleja de nuestros ojos ( en la figura se muestra como los dos objetos a pesar de ser de diferentes tamaos producen una imagen casi del mismo tamao sobre el plano de proyeccin, debido a la diferencia de distancias), es por eso, que esta perspectiva es la mas utilizada para dar una sensacin de realismo, como la que se necesitan en los juegos, simulaciones y animaciones. En el caso de OpenGL, tanto en el modo de perspectiva como en el ortogrfico se limita la regin del espacio sobre la que se realizan los clculos, a esta regin se le llama volumen de vista o volumen de recorte (clipping volume) y en el caso de la perspectiva tambin se la llama frustrum por la forma que tiene. Dicha regin se especifica, ya que los objetos por fuera de este campo a derecha o izquierda no aparecern en pantalla y aquellos muy lejanos generarn pocos rasgos, por lo que de calcularse consumiran recursos innecesariamente (la consideracin de lejano depende del programador).

En el caso de la proyeccin ortogrfica el volumen de vista tiene forma de caja rectangular, por lo que se determina fcilmente mediante 6 medidas: near, far, top, bottom, left, right (cerca, lejos, arriba, abajo, izquierda, derecha) y en el caso de proyeccin, tiene forma de pirmide truncada de base rectangular, que puede ser determinada por el field of view (campo de visin), el aspect ratio ( el alto del plano mas cercano dividido el ancho), near y far.

Hay que anotar que ambos volmenes se calculan a partir de la posicin del observador, que en el caso de OpenGL es la cmara. Tambin hay que observar que las dimensiones del plano ms cercano a la cmara pueden ser mayores o menores a las de la ventana, por lo el mapeo de las condenadas no ser con relacin uno a uno, adicionalmente OpenGL permite definir el

viewport (vista), es decir la regin sobre la ventana en la que se va a realizar el dibujado, que puede ser menor al tamao de la ventana. Hasta este punto el tutorial ha mostrado algunos conceptos bsicos relacionados con la forma en que OpenGL trabaja los grficos tridimensionales, conceptos que posteriormente se vern reflejados en las primeras aplicaciones que se realicen con OpenGL. Es importante tomar en cuenta que un buen manejo del lgebra lineal, los TDA como las pilas y conocimientos en un lenguaje de programacin como c++ permitirn avanzar ms rpidamente en el aprendizaje del API OpenGL

Hola mundo 3d en OpenGLEste tutorial aborda la creacin una aplicacin simple en OpenGL de dos formas diferentes, a travs de las libreras aux y glut. Como ejemplos estilo Hola Mundo estn orientadas a mostrar en pantalla aplicaciones simples que introduzcan al uso de una tecnologa nueva para alguien, en este caso OpenGL, por esto mismo no se explican en profundidad, extensin o detalle todos los conceptos relacionados con el cdigo fuente. Los dos programas fueron probados en el Visual Studio .net 2003, pero es de esperar que funcionen en versiones anteriores (2002, 6) y en entornos diferentes (devcpp). En otros lenguajes como Java o c#, el cdigo variar dependiendo de la sintaxis del lenguaje, la forma en que se realice el binding (ligadura) con el API (OpenGL esta escrito orientado al lenguaje c) y el sistema operativo. Primera Aplicacin 3d Usando AUX En los comienzos de OpenGL aux (de auxiliar) se creo como una librera para ayudar a los programadores a entender el uso del API, hacer ejemplos y prototipos de manera rpida sin tener que preocuparse por las particularidades del sistema operativo. Actualmente aux esta descontinuada, no es mantenida y en la pgina oficial de OpenGL no se recomienda utilizarla, pero est en este tutorial de manera ilustrativa.PLAIN TEXTC++: 1. #include 2. #include 3. #include 4. #include 5. #include 6. 7. #pragma comment(lib, "opengl32.lib") 8. #pragma comment(lib, "GlAux.Lib") 9. #pragma comment(lib, "glu32.lib") 10. 11. void main(void) 12. { 13. auxInitDisplayMode(AUX_SINGLE | AUX_RGBA);

14. 15. 16. 17. 18. 19. 20. 21. 22. }

auxInitPosition(100,100,640,480); auxInitWindow("Hola Mundo 3d"); glViewport(0,0,640,480); gluPerspective(45.0f,640.0f /480.0f, 1.0 ,150.0f); glTranslatef(0,0,-15.0f); auxWireTeapot(4.0f); glFlush(); getchar();

Con estas 9 lneas de cdigo (sin contar las inclusiones y la declaracin del main) se muestra una consola y una ventana con una tetera dibujada en alambres, para cerrar la ventana es necesario introducir una enter en la consola.

Las primeras 5 lneas de cdigo son las inclusiones de las liberis que necesita el programa, son windows.h , requeridas por OpenGL, stdio.h para la funcin getchar() y las de OpenGL gl.h, glut.h y glaux.h. Todas estas libreras vienen en la distribucin de Visual C++, por lo que no hay que preocuparse de su ubicacin en el disco duro. Las siguientes 3 lneas son las directivas #pragma comment(lib, "...") sirven para ligar las libreras binarias de OpenGL, ya que las .h solo contienen los prototipos de las funciones que se utilizarn. Al igual que las cabeceras .h, estas vienen en la distribucin de Visual c++.

La siguiente lnea es la declaracin de la funcin main(), que identifica al programa como de tipo consola. Es importante elegir este tipo de plantilla al crear el proyecto, ya que de otra manera la configuracin del compilador no ser la adecuada para que el programa se compile y ejecute. Finalmente llegamos a las lneas que constituyen propiamente el programa

auxInitDisplayMode(AUX_SINGLE | AUX_RGBA) : Esta funcin realiza dos inicializaciones el rea de dibujo de la ventana, la primera AUX_SINGLE, indica un buffer sencillo, la segunda AUX_RGBA indica el modo de colores deseado, es decir los canales, Red (Rojo) Green (Verde) Blue (Azul) Alpha (Transparencia). auxInitPosition(100,100,640,480): los dos primeros valores indican la posicin de la ventana cuando se muestre y los dos ltimos indican el tamao de la ventana. Asi que esta linea configura una pantalla que se muestra en (100,100) contados desde la esquina superior izquierda de la pantalla (x + derecha, y + abajo) y de tamao 640x480. auxInitWindow("Hola Mundo 3d): inicializa el ttulo de la ventana, que es el que aparece en la barra superior de esta, en este caso es Hola Mundo 3d. glViewport(0,0,640,480): Inicializa el rectngulo sobre el que se va a dibujar en la ventana, los parmetros son posicin (x,y) contados a partir de la esquina inferior izquierda (x + derecha, y + arriba) y las dimensiones ancho alto. En este caso el recuadro de dibujo empieza en (0,0) y tiene dimensiones 640x480 (el tamao completo de la ventana) gluPerspective(45.0f,640.0f /480.0f, 1.0f ,150.0f) Define el frustrum. Los parmetros son el ngulo de visin (45.0), el aspecto que es el ancho de la ventana dividido el alto (640.0f/480.0) y la distancia mas cercana (1.0) y lejana (150.0) dentro de la cual pueden estar los objetos antes de ser recortados. Si parte de un objeto est recortado, es parte no se dibuja. glTranslatef(0,0,-15.0f): Sirve para trasladar el objeto los objetos (la tetera) una distancia (x,y,z) a partir de donde estn, en este caso (0,0,15.0f) a partir del origen. auxWireTeapot(4.0f): Dibuja una tetera de tamao 4.0 en la posicin actual (0,0,-15.0) glFlush(): Obliga a los comandos pendientes de OpenGL a ejecutarse, en este caso, mueve y dibuja la tetera. getchar(): Esta lnea est por facilidad. De no estar incluida, la ventana aparecera y desaparecera (cuando se terminen de ejecutar todas las instrucciones) o se tendra que agregar unas cuantas lneas de cdigo para que el programa funcionara mas como una aplicacin convencional.

A cambio de tener pocas lneas, el Hola Mundo 3d con aux tiene pocas prestaciones y aunque se podra mejorar, es mejor seguir con glut.

Hola mundo 3d en OpenGLPrimera Aplicacin 3d Usando GLUT

GLUT es el GL Utility Toolkit (herramientas utilitarias GL), desarrollada originalmente por Mark J. Kilgard como un reemplazo para la librera aux, con funcionalidades adicionales, mas estable y con un rango mas amplio de sistemas operativos soportados. Posteriormente la librera fue tomada por otros como Nate Robins quienes realizaron modificaciones y mejoras a la librera inicial.PLAIN TEXTC++: 1. #include 2. #include 3. #include 4. #include "glut.h" 5. 6. 7. #pragma comment(lib, "opengl32.lib") 8. #pragma comment(lib, "glut32.lib") 9. #pragma comment(lib, "glu32.lib") 10. 11. void render(void) 12. { 13. glClear(GL_COLOR_BUFFER_BIT); 14. glLoadIdentity(); 15. glTranslatef(0.0f,0.0f,-15.0f); 16. glutWireTeapot(4.0f); 17. glutSwapBuffers(); 18. } 19. 20. void Redimensionar(GLsizei ancho, GLsizei alto) 21. { 22. if(alto == 0) 23. { 24. alto = 1; 25. } 26. 27. glViewport(0, 0, ancho, alto); 28. glMatrixMode(GL_PROJECTION); 29. glLoadIdentity(); 30. if(ancho>alto) 31. { 32. gluPerspective(45.0f,ancho/alto,1,150.0f); 33. } 34. else 35. { 36. gluPerspective(45.0f,alto/ancho,1,150.0f); 37. } 38. 39. glMatrixMode(GL_MODELVIEW); 40. glLoadIdentity(); 41. }

42. void main(void)43.

44. 45. 46. 47. 48. 49. }

{ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("Hola Mundo 3d"); glutDisplayFunc(render); glutReshapeFunc(Redimensionar); glutMainLoop();

Ahora son 21 lneas de cdigo (sin contar de nuevo las inclusiones ni las declaraciones de funciones), pero ahora la ventana es capaz de responder a los comandos ms simples del sistema operativo como cambiar de tamao, moverse y cerrarse. En la pantalla se vera algo como

Las nuevas libreras utilizadas son las de glut.h y glut32.lib, que no vienen incluidas en la distribucin del Visual Studio, por lo que es necesario incluirlas manualmente bien sea en el compilador y/o en el disco duro (basta colocarlas en la carpeta del proyecto) y en Windows adicionalmente hay que proporcionar las libreras dinmicas glut32.dll si se usa opengl32.lib, la distribucin de Microsoft o glut.dll si se usa opengl.lib, la distribucin de SGI. Para proporcionar las libreras dinmicas se pueden colocar en la carpeta donde se ejecute el programa o copiarlas a la carpetas WINDOWS/system32/, esta ltima es mejor si se van a desarrollar varias aplicaciones dependientes de esta librera. Las lneas de cdigo nuevas son: En la funcin render() que se encarga de dibujar los elementos.

glClear(GL_COLOR_BUFFER_BIT): Indica que se limpie un buffer con el color actual de limpiado (el color por defecto es negro) glLoadIdentity(): Carga la matriz identidad sobre la matriz actual (modelview), es necesario hacerlo ya que la funcion render() se ejecuta muchas veces, lo que hara que el glTranslate fuera acumulativo si no se cargara la matriz identidad. glutSwapBuffers(): Cambia el buffer actual sobre el que se est dibujando, por defecto el buffer sobre el que se dibuja es el buffer de atrs y el que se muestra es el del frente. En la funcin Redimensionar() que se encarga de cambiar el viewport y el aspecto de la escena cuando el usuario cambia de tamao la ventana: if(alto == 0){ alto = 1;}: Previene que el alto sea 0, para evitar posteriormente un error de divisin entre 0. glMatrixMode(GL_PROJECTION); glLoadIdentity(): Cambia el modo de matriz a proyeccin y luego carga la identidad sobre esta matrz. if(ancho>alto){ gluPerspective(45.0f,ancho/alto,1,150.0f);}: Define el frustrum, en este caso el alto es mayor que el ancho, as que el aspecto es ancho/alto. else{gluPerspective(45.0f,alto/ancho,1,150.0f);} En este caso el aspecto es alto/ancho, ya que la el alto es mayor que el ancho. glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Se elige la matriz MODEL_VIEW y se carga la identidad sobre ella.

Por ultimo este programa tambin parte del modo consola (como lo muestra la consola de comandos que aparece cuando se ejecuta), las lneas de cdigo en el main() son:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB): Inicializa la ventana con modo doble buffer (uno sobre el que se pinta y otro que se muestra en pantalla) y solicita un modo RGB de colores. glutCreateWindow("Hola Mundo 3d"): El titulo de la ventana, en este caso Hola Mundo 3d. glutDisplayFunc(render); Indica a la librera glut cual ser la funcin que realizar el pintado sobre OpenGL, en este caso es render(), que ya se haba definido anteriormente. glutReshapeFunc(Redimensionar): Indica a glut la funcin que ser llamada cuando el usuario cambie el tamao de la ventana. En este caso la funcin es Redimensionar() que se haba definido anteriormente. glutMainLoop(): Finalmente esta funcin es el ciclo de glut, donde se realizan la recepcin, procesamiento de mensajes del sistema operativo y el dibujado sobre el rea OpenGL.

Hola Complicado Mundo OpenGL-Win32Este tutorial aborda la creacin de una ventana en Windows con un contexto grfico OpenGL, pero a diferencia de los tutoriales basados en GLUT o AUX, esta aplicacin se desarrollar a partir de las libreras de Windows, haciendo todo manualmente. Surge la inquietud de por qu hacer este tutorial, si podra hacerse ms fcilmente con GLUT, AUX o cualquier otra librera?, la respuesta es porque este tutorial permite conocer mejor la estructura de un programa de Windows, que es til si se necesita algo mas de control (y

problemas) sobre la aplicacin. Adems, es divertido ensuciarse un poco las manos con el API de Windows de bajo nivel. PROGRAMANDO ORIENTADO A EVENTOS Windows y en general los sistemas operativos GUI utilizan una arquitectura orientada a eventos para manejar la interaccin usuario sistema aplicacin de manera organizada y eficiente. El modelo es bastante simple, cada vez que el usuario realiza una accin, el sistema determina sobre que aplicacin se realiz y le enva un mensaje describiendo la accin, el programa lee y procesa el mensaje, si es que este le interesa (un clic sobre el men por ejemplo) y realiza los cambios pertinentes. Un ejemplo con un clic podra ser como este:

En este caso la aplicacin, por ejemplo un juego de estrategia, averiguara la posicin en la que en la que se encontraba el puntero cuando se hizo el clic y movera una unidad a esta posicin. Es importante anotar que este modelo fue creado para ser eficiente en uso de recursos cuando varias aplicaciones corren simultneamente, un videojuego por el contrario es una aplicacin destinada a consumir recursos por su naturaleza de aplicacin en tiempo real, la razn de esto es que aunque el usuario se tome una siesta, el videojuego est realizando clculos, reproduciendo sonidos, dibujando la pantalla, la IA esta intentando conquistar el mundo, etc. LA APLICACION Las siguientes estructuras y tipos de datos sern usados en el desarrollo de la aplicacin:

HDC: Handle to Device context. Es el identificador de un Device Context. Un Device Context es una aplicacin a travs de la cual tienen que pasar las operaciones de dibujo, para que estas puedan ser mostradas en un dispositivo fsico, en este caso particular un monitor. PFD: Pxel Format Descriptor. Estructura que describe las propiedades de los pxeles en una superficie de dibujado. HWND: Handle to Window. Es el identificador de una ventana. WNDCLASS: Estructura que contiene los datos necesarios para el registro de una clase ventana, como son su nombre, estilo, funcin de paso de mensajes, icono, cursor, entre otros. HGLRC: Handle to GL Render Context. Es el identificador de un Render Context, similar al HDC, solo que este no es usado por GDI sino por OpenGL para realizar el dibujado sobre la pantalla.

Es posible dividir esta aplicacin en 4 tareas principales:

Crear la ventana win32. Preparar la ventana y ligarla a OpenGL. Inicializar OpenGL. Hacer el ciclo de mensajes y dibujado.

Las macros y variables del programa son:PLAIN TEXTC++: 1. #define VENTANA_ANCHO 640 2. #define VENTANA_ALTO 480 3. 4. HDC hdc=NULL; 5. HGLRC hglrc=NULL; 6. HWND hWnd=NULL; 7. HINSTANCE hInstance;

Hola Complicado Mundo OpenGL-Win32CREAR LA VENTANA WIN32 Para crear la ventana es necesario llenar el WNDCLASS, registrarlo y finalmente crear la ventana. El WNDCLASSPLAIN TEXTC++: 1. WNDCLASS 2. 3. hInstance Cwnd; = GetModuleHandle(NULL);

4. Cwnd.style = CS_OWNDC; 5. Cwnd.lpfnWndProc = (WNDPROC) WndProc; 6. Cwnd.cbClsExtra = 0; 7. Cwnd.cbWndExtra = 0; 8. Cwnd.hInstance = hInstance; 9. Cwnd.hIcon = NULL; 10. Cwnd.hCursor = LoadCursor(NULL, IDC_ARROW); 11. Cwnd.hbrBackground = NULL; 12. Cwnd.lpszMenuName = NULL; 13. Cwnd.lpszClassName = "OpenGL";14. 16.

15. RegisterClass(&Cwnd); 17. hWnd=CreateWindow( 18. "OpenGL", 19. "Hola Mundo",20.

21. 24. 25. 27.

22. 23.

26.

WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ,100, 100, VENTANA_ANCHO, VENTANA_ALTO, NULL, NULL, hInstance, NULL);

La funcin GetModuleHandle() obtiene un identificador para la aplicacin actual. Los datos de la estructura WNDCLASS son los siguientes: WNDCLASSS { UINT style : Estilo de la aplicacin, en este caso se quiere un DC propio (CS_OWNDC) WNDPROC lpfnWndProc : Manejador de mensajes int cbClsExtra : Bytes extra para la estructura int cbWndExtra : Bytes extra para la clase HINSTANCE hInstance : Instancia de la aplicacin que crea la ventana HICON hIcon : Icono de la ventana, al ser NULL, windows provee el icono por defecto. HCURSOR hCursor : Cursor usado al pasar sobre la ventana, LoadCursor(NULL,IDI_ARROW) es el icono por defecto HBRUSH hbrBackground : Color del fondo de la ventana,debido a que todo el espacio de la ventana va a estar ocupado por la ventana, este valor se provee como NULL LPCTSTR lpszMenuName : Nombre del recurso que identifica el men de la aplicacin, es NULL ya que no se utiliza men. LPCTSTR lpszClassName : Nombre de la clase que se usara al registrarla. } El manejador de mensajes al que hace referencia es en este caso uno muy simple:

PLAIN TEXTC++:

1. LRESULT CALLBACK WndProc(HWND

hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) 2. { 3. switch (uMsg) 4. { 5. case WM_CLOSE: 6. { 7. PostQuitMessage(0); 8. return 0; 9. } 10. } 11. return DefWindowProc(hWnd,uMsg,wParam,lParam); 12. }

Las entradas de esta funcin son: HWND hWnd : Identificador de la ventana que recibe el mensaje UINT uMsg : El mensaje WPARAM wParam : Informacin adicional sobre el mensaje LPARAM lParam : Informacin adicional sobre el mensaje Esta funcin solo intercepta un mensaje, aquel que es enviado por el sistema para indicar a la aplicacin que debe cerrarse (WM_CLOSE) y si es cualquier otro mensaje lo enva al DefWindowProc(). RegisterClass() registra una clase ventana, con los parmetros dados por un WNDCLASS, en este caso CWnd. Es hora de crear una ventana a partir de la clase creada con el RegisterClass(), para esto se utiliza la funcin CreateWindow() cuyos parmetros son los siguientes: HWND CreateWindow ( LPCTSTR lpClassName : Nombre de la clase a partir de la cual se crea la ventana LPCTSTR lpWindowName : Titulo de la ventana. DWORD dwStyle : Estilo de la ventana, en este caso con titulo y borde (WS_OVERLAPED) int x, : Posicin x de la ventana int y : Posicin y de la ventana int nWidth : Ancho de la ventana int nHeight : Alto de la ventana HWND hWndParent : Identificador de la ventana padre, en este caso NULL, ya que no tiene HMENU men : Identificador del men de la ventana, en este caso NULL, ya que no tiene

HINSTANCE hInstance : Identificador de la aplicacin poseedora de la ventana, en NT/2000/XP este valor es ignorado LPVOID lpParam : Cadena con el parmetro a pasar al llamar el mensaje WM_CREATE. En este NULL, ya que no hay ningun parmetro a pasar )

Hola Complicado Mundo OpenGL-Win32PREPARAR LA VENTANA Y LIGARLA A OPENGL Ahora es necesario:PLAIN TEXTC++: 1. GLuint PixelFormat; 2. 3. static PIXELFORMATDESCRIPTOR pfd= 4. { 5. sizeof(PIXELFORMATDESCRIPTOR), 6. 1, 7. PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL |PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 8. 32, 9. 0, 0, 0, 0, 0, 0, 10. 0, 11. 0, 12. 0, 13. 0, 0, 0, 0, 14. 32, 15. 0, 16. 0, 17. 0, 18. 0, 19. 0, 0, 0 20. }; 21. 22. hdc=GetDC(hWnd); 23. PixelFormat=ChoosePixelFormat(hdc,&pfd); 24. SetPixelFormat(hdc,PixelFormat,&pfd); 25. hglrc=wglCreateContext(hdc); 26. wglMakeCurrent(hdc,hglrc);

El PIXELFORMATDESCRIPTOR tiene los siguientes datos: PIXELFORMATDESCRIPTOR { WORD nSize : Tamao de la estructura WORD nVersion : Versin de la estructura, siempre es 1

DWORD dwFlags : Propiedades del buffer de pxeles, en este caso dibujar sobre una ventana (PFD_DRAW_TO_WINDOW), soporte a OpenGL (PFD_SUPPORT_OPENGL) y doble buffer (PFD_DOUBLEBUFFER) BYTE iPixelType : La forma de describir los pxeles, en este caso como RGBA (PFD_TYPE_RGBA) BYTE cColorBits : Tamao de un pxel individual en bits, en este caso 32 que es el mas comn BYTE cRedBits : Ignorado BYTE cRedShift : Ignorado BYTE cGreenBits : Ignorado BYTE cGreenShift : Ignorado BYTE cBlueBits : Ignorado BYTE cBlueShift : Ignorado BYTE cAlphaBits : Ignorado BYTE cAlphaShift : Ignorado BYTE cAccumBits : Ignorado BYTE cAccumRedBits : Ignorado BYTE cAccumGreenBits : Ignorado BYTE cAccumBlueBits : Ignorado BYTE cAccumAlphaBits : Ignorado BYTE cDepthBits : Bits para el buffer de profundidad, pueden ser 16 o 32 como en este caso. BYTE cStencilBits : Ignorado BYTE cAuxBuffers : Ignorado BYTE iLayerType : Ignorado BYTE bReserved : Ignorado DWORD dwLayerMask : Ignorado DWORD dwVisibleMask : Ignorado DWORD dwDamageMask : Ignorado } GetDC() obtiene el Device Context asociado a la ventana identificada por hWnd. ChoosePixelFormat() utiliza dos parmetros, el hdc sobre el cual se buscara un formato de pxeles compatible y el pfd que especifica el formato deseado por la aplicacin. Esta funcin devuelve el formato de pxeles mas cercano encontrado, con respecto al pfd. SetPixelFormat() utilizar tres parmetros, el hdc sobre el cual se va a establecer el formato de pxeles, un entero, el PixelFormat, donde esta guardado el ndice a dicho formato de pxeles y el pfd de referencia que se uso para encontrar el formato, el ultimo valor no afecta el funcionamiento de esta funcin, ya que se utiliza solamente como registro. wglCreateContext() crea un contexto de dibujo para OpenGL, a partir de un contexto de dibujo de GDI.

wglMakeCurrent() elige un HGLRC sobre el cual se va a dibujar los OpenGL, esto es debido a que una aplicacin puede tener varios contextos de dibujo, pero solo puede operar un proceso sobre un contexto a la vez. INICIALIZAR OPENGL La inicializacin de OpenGL es en este caso bastante simple y ms bien utilitaria, es realizada por las siguientes lneas de cdigo:PLAIN TEXTC++:

1. 2. 3. 4. 5. 6. 7.

glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glMatrixMode (GL_PROJECTION); glViewport (0, 0, VENTANA_ANCHO , VENTANA_ALTO); gluPerspective(45.0f,VENTANA_ANCHO/VENTANA_ALTO,0.1f,100.0f); gluLookAt( 0,0,16, 0,0,0, 0,1,0); glMatrixMode (GL_MODELVIEW); glLoadIdentity();

glClearColor() establece el color de fondo glMatrixMode() escoge una matriz para operar sobre ella. Primero se elige la de proyeccin (GL_PROJECTION) glViewport() establece el tamao del marco de dibujo de OpenGL gluPerspective() establece el frustrum, en este caso apertura de 45, aspecto de 640/480, plano mas visible a 0.1 de distancia y mas lejano a 100. gluLookAt() posiciona la cmara (en realidad hace transformaciones sobre la matriz proyeccin. Los parmetros estn agrupado de a 3 (x, y, z) y representan la posicin de la camara, el punto al que mira y que vector es considerado hacia arriba Finalmente se vuelve al modo de matriz GL_MODELVIEW que es el utilizado para dibujar las primitivas. HACER EL CICLO DE MENSAJES Y DIBUJADO El ciclo de mensajes se encarga de revisar constantemente los mensajes, en busca de alguno de inters para la aplicacin, de no haber mensajes, se dibuja la escena de OpenGL. El cdigo es as:PLAIN TEXTC++: 1. MSG mensaje; 2. BOOL continuar=TRUE; 3. 4. while(continuar) 5. {

6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23.

if (PeekMessage(&mensaje,NULL,0,0,PM_REMOVE)) { if (mensaje.message==WM_QUIT) { continuar=FALSE; } else { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } } else { render(); SwapBuffers(hdc); } }

La variable continuar indica cuando el ciclo debe detenerse, cuando el usuario o el sistema decidan cerrar la aplicacin, bien sea con la X sobre la barra de la ventana, con el mtodo abreviado, mediante el administrador de aplicaciones, etc. En algunos ejemplos se obvia esta variable al hacer un ciclo while(1) y utilizando un break; en caso de recibir el mensaje. PeekMessage() busca y almacena un mensaje de la pila de mensajes de la aplicacin. Si tal mensaje existe lo almacena en el primer parmetro y devuelve TRUE, de lo contrario devuelve FALSE. El ultimo parmetro (PM_REMOVE) le indica a la funcin al leer un mensaje debe borrarlo de la pila de mensajes. En este caso solo estamos observando el mensaje WM_QUIT, que indica que el WndProc llamo la funcin PostQuitMessage(), es decir que intercepto algn mensaje de salida de la aplicacin. Si no es este mensaje, se vuelve a colocar en la pila de mensajes mediante las funciones TranslateMessage() y DispatchMessage, para que este pueda ser ledo por el wndProc() creado anteriormente o por el manejador de mensajes por defecto (DefWindowProc()). Finalmente si no hay ningn mensaje por leer en la pila de mensajes, se hace el dibujado(render()) y se cambia de buffer (SwapBuffers()). El cdigo del render() es bastante simple y pinta un trianguloPLAIN TEXTC++:

1. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);2.

3. glBegin(GL_TRIANGLES);

4. 5. 6. 7. 8.

glColor3f(0.0f,0.0f,1.0f); glVertex3f(3.0f,-2.0f,0.0f); glVertex3f(0.0f,1.0f,0.0f); glVertex3f(-3.0f,-2.0f,0.0f); glEnd();

glClear() limpia los buffers pasados como parmetro de acuerdo al color de limpiado (negro) y entre las funciones glBegin() y glEnd() esta la especificacin de un triangulo de color azul.

Hola Complicado Mundo OpenGL-Win32El cdigo completo del programa,de 148 lneas de cdigo es:PLAIN TEXTC++: 1. #include 2. #include 3. #include 4. 5. #pragma comment(lib,"opengl32.lib") 6. #pragma comment(lib,"glu32.lib") 7. 8. #define VENTANA_ANCHO 640 9. #define VENTANA_ALTO 480 10. 11. HDC hdc=NULL; 12. HGLRC hglrc=NULL; 13. HWND hWnd=NULL; 14. HINSTANCE hInstance; 15. 16. void inicializarGL(void) 17. { 18. glClearColor(0.0f, 0.0f, 0.0f, 0.5f); 19. glMatrixMode (GL_PROJECTION); 20. glViewport (0, 0, VENTANA_ANCHO , VENTANA_ALTO); 21. gluPerspective(45.0f,VENTANA_ANCHO/VENTANA_ALTO,0.1f,100.0f); 22. gluLookAt( 0,0,16, 0,0,0, 0,1,0); 23. glMatrixMode (GL_MODELVIEW); 24. glLoadIdentity(); 25. } 26. 27. void render(void) 28. { 29. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 30. 31. glBegin(GL_TRIANGLES); 32. glColor3f(0.0f,0.0f,1.0f); 33. glVertex3f(3.0f,-2.0f,0.0f); 34. glVertex3f(0.0f,1.0f,0.0f);

35. 36.37. 38. 40.

glVertex3f(-3.0f,-2.0f,0.0f); glEnd(); } {

39. void deInicializar(void) 41. 42. 43. 44. 45.wglMakeCurrent(NULL,NULL); wglDeleteContext(hglrc); ReleaseDC(hWnd,hdc); DestroyWindow(hWnd); UnregisterClass("OpenGL",hInstance); } HWND hWnd,UINT uMsg,WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: { PostQuitMessage(0); return 0; } } return DefWindowProc(hWnd,uMsg,wParam,lParam); }

46. 47. 49.

48. LRESULT CALLBACK WndProc( 50. 51. 52. 53. 54. 55. 56. 57. 58.

59. 60. 62. 63.

61. int WINAPI WinMain(HINSTANCE hinst,HINSTANCE hinstAnterior,LPSTRcadenaDeComandos,int parametroVentana) { MSG mensaje; 64. BOOL continuar=TRUE; 65. GLuint PixelFormat; 66. WNDCLASS Cwnd; 67. 68. hInstance = GetModuleHandle(NULL); 69. Cwnd.style = CS_OWNDC; 70. Cwnd.lpfnWndProc = (WNDPROC) WndProc; 71. Cwnd.cbClsExtra = 0; 72. Cwnd.cbWndExtra = 0; 73. Cwnd.hInstance = hInstance; 74. Cwnd.hIcon = NULL; 75. Cwnd.hCursor = LoadCursor(NULL, IDC_ARROW); 76. Cwnd.hbrBackground = NULL; 77. Cwnd.lpszMenuName = NULL; 78. Cwnd.lpszClassName = "OpenGL"; 79. 80. RegisterClass(&Cwnd); 81. 82. hWnd=CreateWindow( "OpenGL", 83. "Hola Mundo",

84.

85. 88. 89. 91. 93. 94. 95. 96.

86. 87.

90. 92.

WS_OVERLAPPEDWINDOW ,100, 100, VENTANA_ANCHO, VENTANA_ALTO, NULL, NULL, hInstance, NULL);

static PIXELFORMATDESCRIPTOR pfd= { sizeof(PIXELFORMATDESCRIPTOR), 1, 97. PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, 98. PFD_TYPE_RGBA, 99. 32, 100. 0, 0, 0, 0, 0, 0, 101. 0, 102. 0, 103. 0, 104. 0, 0, 0, 0, 105. 32, 106. 0, 107. 0, 108. 0, 109. 0, 110. 0, 0, 0 111. }; 112. 113. hdc=GetDC(hWnd); 114. PixelFormat=ChoosePixelFormat(hdc,&pfd); 115. SetPixelFormat(hdc,PixelFormat,&pfd); 116. hglrc=wglCreateContext(hdc); 117. wglMakeCurrent(hdc,hglrc); 118. 119. ShowWindow(hWnd,SW_SHOW); 120. SetForegroundWindow(hWnd); 121. SetFocus(hWnd); 122. 123. inicializarGL(); 124. 125. while(continuar) 126. { 127. if (PeekMessage(&mensaje,NULL,0,0,PM_REMOVE)) 128. { 129. if (mensaje.message==WM_QUIT) 130. { 131. continuar=FALSE; 132. }

133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144.145.

else { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } } else { render(); SwapBuffers(hdc); } } deInicializar(); return (mensaje.wParam); }

146. 147. 148.

La aplicacin luce as:

Aun este programa tiene que abarcar bastantes prestaciones no contempladas, por dar simpleza (de ser posible eso) al Hola Mundo. Entre estas prestaciones estn:

Solicitar modo pantalla completa, que es muy comn entre los videojuegos. Atender a los errores en todo el proceso de creacin de la ventana y asociacin a OpenGL. Muchas de las funciones utilizadas en la aplicacin tienen un retorno que indica si la funcin pudo llevarse a cabo o no. Cambiar de tamao la escena de OpenGL al cambiar el tamao de la ventana. Esto se hace aadiendo los estilos CS_VREDRAW y CS_HREDRAW al WNDCLASS e interceptando el mensaje WM_SYSCOMMAND, Wparam SC_SIZE. Pausar la aplicacin cuando la ventana es puesta detrs de otra o minimizada.

Tambin es importante aclarar que este ejemplo utiliza el driver de software de OpenGL creado por Microsoft en la dcada del 90 y que actualmente dicho driver no es mantenido y es muy ineficiente. Para utilizar el driver de OpenGL que proporciona la tarjeta grfica, que tiene la ventaja de ser acelerado por hardware y mantenido constantemente (dependiendo de la tarjeta) se pueden usar las funciones WGL-ARB aprobadas en el ao 2000 y que hacen actualmente parte del estndar, aunque siempre que se quieran usar, se debe comprobar su disponibilidad, ya que dependen de la implementacin del estndar. Finalmente es necesario sealar que esta es una de las maneras mas complicadas de hacer una aplicacin con OpenGL para Windows, ya que se trabaja el API de win32 a muy bajo nivel y las funciones para ligar OpenGL con GDI no han sido actualizada en muchos aos, de hecho

el articulo relevante mas reciente que se puede encontrar en MSDN acerca de OpenGL data del ao 1995.

Tipos de Datos, Convenciones y Estados en OpenGLEste tutorial hace un breve repaso de tres conceptos importantes en la realizacin de aplicaciones con OpenGL, las convenciones del API, los tipos de datos manejados por este y los estados, con los cuales se controla gran parte del proceso de render. TIPOS DE DATOS Al igual que c, c++ y todos los lenguajes de programacin definen unos tipos de datos bsicos para representar valores de verdad, enteros, flotantes, bits y caracteres, OpenGL define sus propios tipos de datos que permiten trabajar de manera mas uniforme sobre el API en diferentes compiladores y sistemas operativos. Los tipos de datos en OpenGL son los siguientes:Tipo GL Prefij Tama Descripcin o o 1 8 8 8 16 16 32 32 32 ptrbits Valor de verdad Byte con signo, complemento a 2 Byte sin signo Caracter Entero corto Entero corto sin signo Entero con signo, complemento a 2 Entero sin signo Entero largo no-negativo Entero complemento de 2 , es el numero de bits necesarios para representar un puntero a GLint Entero no-negativo, es el numero de bits necesarios para representar un puntero a GLsizei

GLboolea n GLbyte b

GLubyte ub GLchar -

GLshort s GLushort us GLint GLuint GLsizei i ui -

GLintptr GLsizeipt r

ptrbits

GLbitfield GLfloat f

32 32 64 64

Campo de bits Numero de punto flotante Punto flotante de precisin doble. Doble convertido al intervalo [0,1]

GLdouble d GLclamp d

Las letras de la columna Prefijo se usan en las convenciones de funciones, para identificar el tipo de dato que la funcin recibe. Los bits en la columna de Tamao indican la mnima cantidad que debe tener el tipo de dato, ya que dependiendo de la implementacin del fabricante de hardware este nmero puede ser mayor. Las entrada de las funciones de OpenGL pueden ser cualquier tipo de dato que cumpla las especificaciones de arriba, es decir, el API no solamente funciona con los tipos de datos propios, sino que tambin puede funcionar con los tipos de datos de c, c++, algn binding de java, etc. As es que por ejemplo se puede usar el float de c++ como entrada de una funcin con parmetro GLfloat de OpenGL sin problemas. Aun as es recomendable utilizar los tipos de datos de OpenGL para mantener una buena portabilidad de la aplicacin. CONVENCIONES Todas las funciones de OpenGL siguen unas simples convenciones que permiten identificar su funcionamiento de manera rpida para el programador, dichas convenciones fueron establecidas inicialmente por SGI y hasta hace poco lo eran por el ARB. Actualmente y con el traspaso del ARB al grupo Kronos, se espera que dichas normas sean dictadas desde all. Una diseccin de una funcin en OpenGL lucira algo as como:

Retorno: El retorno puede ser cualquiera de los tipos especificados anteriormente. Liberara: Indica la fuente de la funcin, las mas comunes son gl para OpenGL, glu para el OpenGL Utility Library y wgl para la librera de bindings OpenGL win32. Para el caso de las extensiones, aparecen de la

forma GL_EXT, GL_ARB, GL_NV (nvidia), GL_ATI y en general cualquier nombre de compaa que produzca extensiones de hardware para OpenGL. Nombre: El nombre de la funcin. # Parmetros: Cantidad de parmetros que recibe la funcin, pueden ser ninguno (se obvia), 1, 2, 3 o 4. Tipo parmetros: Indica el tipo de todos los parmetros que recibe la funcin. Pueden ser cualquiera de los tipos con prefijo indicados en la tabla de Tipos de Datos de OpenGL. Si se le agrega la letra v despus del prefijo de tipo de parmetro, indica que la funcin recibe un arreglo de tamao # Parmetros y tipo Tipo parmetros. Parmetros: Los parmetros de la funcin.

Las mismas reglas anteriores pueden ser representada al estilo ANSI C se vera como: (Tomado de la especificacin 2.1 de OpenGL) tipoR Nombre{e1234}{e b s i f d ub us ui}{e v} ( [args ,] T arg1 , . . . , T argN [, args] ); donde tipoR es el tipo de retorno, seguido por el nombre de la funcin (incluido el indicador de librera) , los {} indican que un valor debe ser escogido entre todos los posibles, e es el valor vaci y los argumentos [args,] pueden o no estar presentes. Uno de los ejemplos mas amplios para mostrar el funcionamiento de estas convenciones es de de glVertex(), todas las definiciones de estas funcin son:PLAIN TEXTC++:

1. void 2. void 3. void 4. void 5. void 6. void 7. void 8. void 9. void 10. void 11. void 12. void 13. void 14. void 15. void 16. void 17. void 18. void 19. void 20. void

glVertex2d (GLdouble x, GLdouble y); glVertex2dv (const GLdouble *v); glVertex2f (GLfloat x, GLfloat y); glVertex2fv (const GLfloat *v); glVertex2i (GLint x, GLint y); glVertex2iv (const GLint *v); glVertex2s (GLshort x, GLshort y); glVertex2sv (const GLshort *v); glVertex3d (GLdouble x, GLdouble y, GLdouble z); glVertex3dv (const GLdouble *v); glVertex3f (GLfloat x, GLfloat y, GLfloat z); glVertex3fv (const GLfloat *v); glVertex3i (GLint x, GLint y, GLint z); glVertex3iv (const GLint *v); glVertex3s (GLshort x, GLshort y, GLshort z); glVertex3sv (const GLshort *v); glVertex4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w); glVertex4dv (const GLdouble *v); glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w); glVertex4fv (const GLfloat *v);

21. void 22. void 23. void 24. void

glVertex4i (GLint x, GLint y, GLint z, GLint w); glVertex4iv (const GLint *v); glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w); glVertex4sv (const GLshort *v);

Como se evidencia, es posible adivinar el tipo de entrada que tendr la funcin, solamente con observar su nombre. No todas las funciones poseen numero de argumentos variable, as que en esos casos se omite el numero delante del nombre de la funcin, como por ejemplo en glTranslate(). Esto tambin puede ocurrir con el tipo de datos y si la funcin recibe como parmetros arreglos.

Tipos de Datos, Convenciones y Estados en OpenGLESTADOS Como se haba mencionado anteriormente OpenGL mantiene una considerable cantidad de variables de estado. Hay dos tipos diferentes de variables de estado, unas son las llamadas GL server state (estado en servidor GL) y otras las GL client state (estado en cliente GL).

La mayora de los estados que se manipulan a la hora de hacer un programa son del servidor GL. Los estados se pueden prender usando la funcin:

glEnable(GLenum state) que recibe como parmetro el enum correspondiente al estado que se desea activar o desactivar , se puede comprobar si un estado est activo o no mediante: isEnabled(GLenum state) y finalmelmente se puede desactivar el estado mediante: glDisable(GLenum state) Algunos de los estados de comn uso son:

GL_FOG : Estado para la muestra de niebla. GL_LIGHTING: Estado para el uso de luces. GL_ALPHA_TEST: Para hacer uso de las transparencias. GL_DEPTH_TEST: Habilita la prueba de profundidad sobre el buffer de profundidad. GL_LIGHT#: Habilita una luz, que es un nmero entre 0 y 7 (8 es un minimo de luces que debe soportar una implementacin de OpenGL). Para que esto funcione GL_LIGHTING debe estar habilitado. GL_COLOR_MATERIAL: Permite crear materiales de color que afectan el brillo y la difusin de las superficies. Para que esto funcione GL_LIGHTING debe estar habilitado. GL_NORMALIZE: Normaliza los vectores que se pasen a travs de la funcin glNormal(). GL_POLYGON_SMOOTH: Dibuja polgonos con suavizado. Para que esto funcione, se necesita el alpha buffer. GL_POINT_SMOOTH: Suaviza los puntos. GL_CULL_FACE: Si esta habilitado, elimina la parte de atrs de los polgonos (tringulos, rectngulos y polgonos). Se considera frente y atrs de un polgono dependiendo de el orden en que se suministran los puntos que conforman el polgono (sentido reloj o contra-reloj). GL_TEXTURE_2D: Permite el uso de texturas 2d sobre las primitivas.

Bien esto es todo por este tutorial. A pesar de que en este tutorial no se desarrollaron ejemplos prcticos, existes bastantes elementos de aplicacin posterior a la hora de realizar cualquier aplicacin para OpenGL.

Primitivas en OpenGLEste tutorial cubre el manejo de primitivas en OpenGL, fundamental a la hora de realizar cualquier tipo de aplicacin 3d, ya que con estas (especialmente los tringulos) es que se representan los objetos 3d en los videojuegos. Al igual que en los anteriores tutoriales vale la pena aclarar que la documentacin sobre la que se basa este tutorial es la de la

implementacin 1.1 de OpenGL, que an sigue vigente en la implementacin actual, pero con variaciones gracias a la introduccin de nuevas tecnologas en las tarjetas grficas. Este tutorial, a diferencia de los anteriores, permite ver en accin las capacidades de OpenGL al mismo tiempo que su sencillez, posteriormente, con la introduccin de las transformaciones, texturas, iluminacin, extensiones y shaders se mostrara la potencia que la actual versin de OpenGL permite. PRIMITIVAS En el mundo fsico los objetos poseen formas variadas que no necesariamente guardan relacin con los objetos en la geometra bsica. En los videojuegos y dems software 3d en tiempo real, representar esas formas de manera exacta sera muy costoso computacionalmente hablando (hardware), al punto de que sera casi imposible con la tecnologa actual, es por eso que se usan aproximaciones para hacer que las cosas se vean lo mas cercanas posibles a la realidad y al mismo tiempo, lo mas ajustado posible a las capacidades del hardware actual. Al fin y al cabo hay un dicho en computacin grfica si luce bien, esta bien.

Un modelo hecho de tringulos a la izquierda, a la derecha con superficie e iluminacin. OpenGL hace uso del lo que sus creadores llaman el paradigma Begin/End, que simplemente es la forma en que se pasan las instrucciones para indicar al API como se deben armar las primitivas, a travs de dos funciones: void glBegin( enum mode ); void glEnd( void ); La funcin glBegin() indica a OpenGL que los siguientes llamados a la funcion glVertex(), entre esta y glEnd() debern ser interpretados como vrtices para ensamblar la primitiva especificada en (enum mode), el parmetro de la funcin glBegin(). Adicionalmente a especificar vrtices es posible especificar colores, normales, materiales y texturas entre los llamados de glBegin() y glEnd(). Los vrtices sumistrados entre los llamados del glBegin() glEnd() pueden ser cualquiera de la forma:

void Vertex{234}{sifd}v( T coords ); que significa que pueden tener dos, tres o cuatro parmetros y ser entero corto, entero, flotante o doble, al mismo tiempo que pueden o no estar contenidos en un vector. Es posible especificar diez tipos de primitivas diferentes al llamar la funcin glBegin(), estas son: 1. Puntos - glBegin(GL_POINTS); Se dibuja un punto en las coordenadas especificadas y con el color actual por cada llamado a glVertex. Esta primitiva se ve afectada entre otras por las siguientes funciones: void glPointSize( float size ); : Cambia el tamao de los puntos en pxeles por size, el tamao por defecto es 1.0. El tamao de un punto varia con la distancia de a la cmara por lo que a mayor distancia se vera mas pequeo para dar un efecto de profundidad Esta primitiva se ve afectada entre otros por este estado: GL_POINT_SMOOTH : Indica si el punto debe se suavizado o no. Ejemplo:PLAIN TEXTC++:

1. glPointSize(3.0f);

2. 3. glBegin(GL_POINTS); 4. glVertex3f(1.0f,1.0,1.0); 5. glVertex2f(3.5f,1.0f); 6. glEnd(); 7.

Este cdigo dibuja dos puntos, uno en (1,1,1) y (3.5,1,0), de tamao 3 pxeles y con sus respectivas atenuaciones de tamao, dependientes de la distancia a la cmara. A pesar de que el llamado de glBegin() no genera un bloque de cdigo como los corchetes, es recomendable usar un espacio tabulado para indicar que esas lneas de cdigo se encuentran entre el llamado a un glBegin() y un glEnd(). Debido a que hacer un ejemplo mostrando un punto en pantalla es bastante seco y aburrido, la aplicacin que muestra el conjunto de puntos en forma de cilindro, utilizando las funciones seno y coseno para trazar la circunferencia e incrementando una variable de profundidad.

Primitivas en OpenGLLINEAS OpenGL tiene tres primitivas para pintar lneas, estas son individuales, conectadas y en ciclo. Todas estas formas de dibujar lneas varan en la manera en que se interpretan una serie de vrtices. El dibujo de lneas se ve afectadas por las siguientes funciones: glLineWidth(GLfloat width); : Cambia el tamao de representacin de las lneas por width ( el tamao por defecto es 1), el tamao debe ser mayor que 0. glLineStipple(GLint factor, GLushort pattern) : Genera un patrn segn el cual sern pintadas las lneas. Pattern es un valor de 16 bits, donde cada bit indica si un segmento del tamao de un pxel debe estar apagado o prendido. Factor es una modificacin a la cantidad de pxeles que representa un bit en pattern, as si factor es 5 cada bit en pattern ser dibujado como 5 pxels, bien sean estos prendidos o apagados. En general las 3 primitivas de lneas se ven afectadas por los estados:

GL_LINE_SMOOTH : Indica si las lneas deben ser suavizadas o no. GL_LINE_STIPPLE : Si este estado esta activo se aplica el patrn definido por glLineStipple(). 2. Lneas Individuales glBegin(GL_LINES); Con esta primitiva es posible dibujar lneas separadas. Cada para de vrtices especificados se dibuja una lnea y si se especifica un numero impar de vrtices, el ltimo es ignorado. Ejemplo:PLAIN TEXTC++:

1. glEnable(GL_LINE_SMOOTH);

2. 3. glBegin(GL_LINES); 4. glVertex3f(0.0f,0.0f,0.0f); 5. glVertex3f(1.0f,0.0f,0.0f); //eje x 6. glVertex3f(0.0f,0.0f,0.0f); 7. glVertex3f(0.0f,1.0f,0.0f); //eje y 8. glVertex3f(0.0f,0.0f,0.0f); 9. glVertex3f(0.0f,0.0f,1.0f); //eje z 10. glEnd(); 11.

Estas lneas de cdigo dibuja un 3 segmentos de lneas de tamao 1, a lo largo de cada uno de los 3 ejes (x,y,z), partiendo del origen (0,0,0). 3. Lneas Conectadas glBegin(GL_LINE_STRIPS); Permite dibujar un conjunto de lneas conectadas, donde los dos primeros vrtices forman una lnea y cada vrtice adicional genera una lnea que une dicho a vrtice con ltimo suministrado antes de este. Ejemplo:PLAIN TEXTC++: 1. 2. glBegin(GL_LINE_STRIPS); 3. glVertex3f(0.0f,0.0f,0.0f); 4. glVertex3f(1.0f,0.0f,0.0f); //Primera linea 5. glVertex3f(1.0f,1.0f,0.0f); //Segunda linea 6. glVertex3f(0.0f,1.0f,0.0f); //Tercera linea

7. glVertex3f(0.0f,0.0f,0.0f); //Cuarta linea 8. glEnd();9.

Este cdigo dibuja un cuadrado de lado 1 sobre el plano XY. 4. Lneas en Ciclo glBegin(GL_LINE_LOOP); Similar a LINE_STRIPS, con la diferencia de que la ltimo vrtice en ser suministrado se une con el primero para formar una ltima lnea. Ejemplo:PLAIN TEXTC++: 1. 2. glBegin(GL_LINE_ LOOP); 3. glVertex3f(0.0f,0.0f,0.0f); 4. glVertex3f(1.0f,0.0f,0.0f); 5. glVertex3f(1.0f,1.0f,0.0f); 6. glVertex3f(0.0f,1.0f,0.0f); 7. glEnd(); 8.

Este ejemplo dibuja lo mismo que el anterior, observando claro est que en este caso no se suministra el punto (0,0,0) al final, ya que esta lnea se genera al conectar el punto (1,1,1) con el primer vrtice.

Primitivas en OpenGLPOLGONOS OpenGL permite el manejo de tres tipos de primitivas poligonales, tringulos, rectngulos y polgonos en general. Las siguientes funciones afectan la manera en que son mostrados los polgonos: void glFrontFace( enum dir ); : Establece el sentido de winding de los polgonos, dir puede ser CCW (Counter-ClockWise), que indica en sentido anti-manecillas o CW (ClockWise) en sentido manecillas. Se puede entender mas fcilmente si se piensa en la primitiva como si esta fuera a ser dibujada en una hoja, con el plano que forman los vrtices, si los puntos de la figura se proveen en sentido anti-manecillas, la cara frontal del polgono estar apuntando hacia fuera de la hoja, de lo contrario (en sentido manecillas) estar apuntando hacia adentro. Es importante tener esto en cuenta debido a que algunas funciones de OpenGL dependen de este comportamiento o lo modifican. void glShadeModel( enum mode ); : Indica de que manera se deben rellenar de color los polgonos, SMOOTH indica que se debe hacer un degradado de color dependiendo del color de cada vrtice y FLAT que no se realizar degradado. void CullFace( enum mode ); : Indica cual de las caras del polgono no debe ser dibujada en caso de que el estado CULL_FACE est activo, las opciones son FRONT, BACK y FRONT_AND_BACK, para las caras frontal, posterior y frontal-posterior simultneamente. void PolygonMode( enum face, enum mode ); : Modifica la forma en que son dibujados los polgonos, face indica la cara a la que se le cambiaran las propiedades, al igual que CullFace las opciones son FRONT, BACK Y FRONT_AND_BACK, mode indica como se desea presentar el polgono, las opciones son POINT, que muestra solo los vrtices, LINE, que muestra las lneas que lo conforman y FILL que muestra la superficie del mismo. El modo por defecto es FRONT_AND_BACK y FILL. Los siguientes estados estn asociados al manejo de las primitivas poligonales: CULL_FACE : Indica si sobre los polgonos se debe realizar la eliminacin de caras, por defecto est deshabilitada. GL_DEPTH_TEST : Indica si se debe realizar un chequeo de profundidad para eliminar los segmentos de objetos ocultos tras otros objetos. Es sin duda esencial realizar este chequeo para dar sentido de profundidad a la escena. Este estado esta por defecto desactivado. TRIANGULOS

Sin duda esta es una de las primitivas mas utilizadas, debido a que posee ciertas ventajas sobre los rectngulos y polgonos, por ejemplo, no es posible suministrar tres vrtices que no pertenezcan a un mismo plano, mientras que esto si es posible con las otras dos primitivas. Existen tres tipos posibles de primitivas triangulo en OpenGL, independientes, conectados y en abanico. 5. Tringulos independientes glBegin(GL_TRIANGLES); Simple, cada tres vrtices se genera un nuevo triangulo con la cara frontal determinada por el orden que este activo, bien sea CCW o CW. Evidentemente la cantidad de vrtices debe ser 0 o mltiplo de tres, los ltimos vrtices que no correspondan a ninguna tripleta son despreciados. EjemploPLAIN TEXTC++: 1. 2. glBegin(GL_TRIANGLES); 3. glVertex3f(0.0f,0.0f,0.0f); 4. glVertex3f(1.0f,0.0f,0.0f); 5. glVertex3f(0.0f,1.0f,0.0f); 6. glEnd(); 7.

Este ejemplo genera un triangulo rectngulo sobre el plano XY con la cara frontal apuntando hacia Z+ en CCW. 6. Tringulos conectados glBegin(GL_TRIANGLE_STRIP); Similar a LINE_STRIPS, los primeros tres vrtices generan un triangulo y luego cada vrtice adicional genera otro que comparte un lado del triangulo anterior, es decir si se suministran los vrtices a,b,c,d,e se formarn los tringulos abc , cbd y cde. La razn por la que se invierte el orden de los vrtices en algunos tringulos, cbd por ejemplo, es para preservar el winding de la primitiva. Ejemplo:PLAIN TEXTC++: 1. 2. glBegin(GL_TRIAGLE_STRIP); 3. glVertex3f(0.0f,0.0f,0.0f);

4. glVertex3f(1.0f,0.0f,0.0f); 5. glVertex3f(0.0f,1.0f,0.0f); 6. glVertex3f(1.0f,1.0f,0.0f); 7. glEnd();8.

Este fragmento de cdigo dibuja un cuadrado de lado 1 sobre el plano XY, hecho de dos tringulos y con la cara frontal apuntando hacia Z+. 7. Tringulos en abanico glBegin(GL_TRIANGLE_FAN); Esta primitiva genera un conjunto de tringulos alrededor de un punto comn, al igual que TRIANGLE_STRIPS, estos estn conectados por un lado. En este caso el proporcionar los vrtices a,b,c,d,e generarn los tringulos abc, acd y ade. Ejemplo:PLAIN TEXTC++: 1. 2. #define PI 3.1415926535897932384626433832795f 3. ... 4. int n= 2*PI/50; 5. glBegin(GL_TRIANGLE_FAN); 6. glVertex3f(0.0f,0.0f,0.0f); 7. for(int seg=0, seg