63640386-opengl-delphi

87
 Programación con Delphi y OpenGL Carlos García Trujillo [email protected] http://glscene.tripod.com Prohibida la reproducción o modificación sin autorización  expresa del autor. (Cedida la publicación a el Rinconcito de Delphi)  http://www.elrinconcito.com/delphi/

Upload: fernando-arias

Post on 21-Jul-2015

67 views

Category:

Documents


0 download

TRANSCRIPT

Programacin con Delphi y OpenGL

Carlos Garca [email protected] http://glscene.tripod.com

(Cedida la publicacin a el Rinconcito de Delphi) http://www.elrinconcito.com/delphi/

Prohibida la reproduccin o modificacin sin autorizacin expresa del autor.

Delphi en tres dimensionesUn vistazo a las APIs de grficos 3DQuiero hablar un poco acerca de las opciones que tenemos para realizar aplicaciones que involucren grficos 3D en Delphi, ya sean salvapantallas, juegos, demos multimedia, interfaces 3D, e incluso simulaciones y aplicaciones de realidad virtual. As que mencionaremos las caractersticas mas relevantes de las dos APIs grficas de mayor importancia en el mundo de las computadoras personales: Direct3D y OpenGL. Que por qu usar una de estas APIs? Los motivos son varios: ahorrarnos tiempo de trabajo, permitir un amplio soporte de hardware y lograr cdigo fcilmente portable.

gratuita y es una muy sencilla y prctica interfaz entre Delphi y la gran mayora de funcionalidades de DirectX.

OpenGLOpenGL es una librera grfica escrita originalmente en C que permite la manipulacin de grficos 3D a todos los niveles. Esta librera se concibi para programar en mquinas nativas Silicon Graphics bajo el nombre de GL (Graphics Library). Posteriormente se consider la posibilidad de extenderla a cualquier tipo de plataforma y asegurar as su portabilidad y extensibilidad de uso con lo que se lleg al trmino Open Graphics Library, es decir, OpenGL. La librera se ejecuta a la par con nuestro programa independientemente de la capacidad grfica de la mquina que usamos. Esto significa que la ejecucin se dar por software a no ser que contemos con hardware grfico especfico en nuestra mquina. Si contamos con tarjetas aceleradoras de v deo, tecnologa MMX, aceleradoras 3D, pipelines grficos implementados en placa, etc ... gozaremos por supuesto de una ejecucin muchsimo ms rpida en tiempo real. As esta librera puede usarse bajo todo tipo de sistemas operativos e incluso usando una gran variedad de lenguajes de programacin. Podemos encontrar variantes de OpenGL para Windows 95/NT, Unix, Linux, Iris, Solaris, Java e incluso lenguajes de programacin visuales como Visual Basic, Borland C++ Builder y por supuesto Delphi. En contraste con la antigua IRIS GL-library de SGI, OpenGL es por diseo independiente de plataformas y sistemas operativos como ya lo mencionamos, y esto es un punto que podemos tomar en cuenta los programadores de Delphi, pensando en que prximamente saldr una versin de Delphi para Linux, en la que obviamente no podremos contar con DirectX. Adems es perceptiva a la red, de manera que es posible separar nuestra aplicacin OpenGL en un servidor y un cliente que verdaderamente produzca los grficos. Existe un protocolo para mover por la red los comandos OpenGL entre el servidor y el cliente. Gracias a su independencia del sistema operativo, el servidor y el cliente no tiene porque ejecutarse en el mismo tipo de plataforma, muy a menudo el servidor ser una supercomputadora ejecutando una compleja simulacin y el cliente una simple estacin de trabajo mayormente dedicada a la visualizacin grfica. OpenGL permite al desarrollador escribir aplicaciones que se puedan desplegar en varias plataformas fcilmente. Por encima de todo, OpenGL es una biblioteca estilizada de trazado de grficos de alto rendimiento, y hay varias tarjetas grficas aceleradoras y especializadas en 3D que implementan primitivas OpenGL a nivel del hardware. Hasta hace poco, estas avanzadas bibliotecas grficas solan ser muy caras y slo estaban disponibles para estaciones SGI u otras estaciones de trabajo UNIX. Las cosas estn cambiando muy deprisa y gracias a las generosas licencias y el kit de desarrollo de controladores de SGI, vamos a ver ms y ms hardware OpenGL para usuarios de PCs. Al contrario de Direct3D, OpenGL es un API altamente portable y sencilla. Lo de sencilla es ms bien en comparacin con Direct3D, ya que para poder comprender la mayor parte de las funciones de OpenGL es necesario tener un poco de conocimientos de Algebra Lineal, Geometra y un poco de 2

Direct3DDirect3D es el API 3D de Microsoft. Es un completo conjunto de servicios de grficos 3D tanto de transformaciones, iluminacin y renderizado de escenas, as como de acceso transparente a la aceleracin por hardware y una comprensible solucin 3D para la nueva generacin de PCs. Es la ltima adicin al altamente popular conjunto de APIs Microsoft DirectX de tecnologa multimedia. Este conjunto incluye las APIs DirectDraw, DirectSound, DirectInput y DirectPlay. Direct3D proporciona acceso a avanzadas capacidades grficas de aceleradores 3D por va hardware, tales como el z-buffering (que se usa para registrar la proximidad de un objeto al observador, y es tambin crucial para el eliminado de superficies ocultas), antializado de lneas (reduce los bordes escalonados en las lneas dibujadas sobre una pantalla), transparencias, efectos atmosfricos, y correcta perspectiva del mapeado de texturas. Entre las desventajas que podramos enumerar de Direct3D es que es una interfaz complicada y poco portable. Sin embargo, si queremos que nuestras aplicaciones grficas corran bajo Windows 9x soportando aceleracin de hardware en casi todas las tarjetas del mercado y al mismo tiempo funcionen sin tarjetas aceleradoras o saquen provecho del MMX y los microprocesadores que vendrn sin tener que programar las rutinas de rasterizacin por software aparte, la nica opcin es Direct3D. Aqu cabe hacer mencin que Direct3D soporta un juego de chips grficos mucho ms amplio que el soportado por OpenGL, y esta es una de las razones por las que este sea tan popular en el rea del desarrollo de juegos para PCs, y que muchas empresas de desarrollo de este tipo de aplicaciones basen sus programas en esta API. Direct3D es el API elegida para portar juegos de consolas como Playstation a PC. Los programadores de Delphi tenemos mucho de donde escoger en cuanto a Direct3D, ya que existen en Internet una gran cantidad de componentes y libreras freeware que funcionan como interfaz entre Delphi y DirectX. Entre los componentes ms relevantes que podemos mencionar respecto a DirectX con Delphi estn los famosos DelphiX de Hiroyuki Hori, y los agregados que se han escrito para esta librera, como el TCollisionTester3DX de Henrik Fabricius, entre otros. Y qu decir adems de la suite de componentes Delphi Games Creator, la cual tambin se distribuye de manera

Delphi en tres dimensionesFsica, aunque a final de cuentas no es tan difcil como puede parecer. OpenGL provee prcticamente las mismas funcionalidades en cuanto a capacidades grficas que Direct3D; incluso en algunos aspectos se comporta de una manera ms eficiente, y posee una serie de caractersticas que facilitan al programador la tarea de construir la escena, como tal es el caso de las Listas de Despliegue, que son una manera de almacenar comandos de dibujo en una lista para un trazado posterior. Los Programadores de Delphi tenemos un amplio panorama en frente nuestro respecto a OpenGL, ya que de por s las versiones de Delphi de 32 bits incluyen la DLL OpenGL32, que es la versin de OpenGL para Win32, adems incluye una unidad llamada OpenGL.Pas la cual es la interfaz entre la DLL y nuestras propias aplicaciones. Incluso algunas versiones de Delphi traen archivos de ayuda para esta API y sus mltiples funciones. Debemos mencionar que existen muchos programadores de Delphi que han hecho valiosas aportaciones al mundo de los grficos, tales como: Mitchell E. James con su componente GLPanel, Mike Lischke, el cual es un prominente miembro del grupo JEDI (Joint Endeavor of Delphi Innovators, Grupo de Esfuerzos de Innovadores de Delphi), y que tambin ha escrito varias libreras para OpenGL en Delphi. Esto, por mencionar solo a algunos, a fin de cuentas existen muchos programadores reconocidos en este mbito. permitindonos olvidarnos de las rutinas de rasterizacin por software. Pero tambin es claro que aparecern ms versiones de Direct3D, incorporando mejoras y que no saldr n nuevas versiones de OpenGL para Windows (al menos esa es la intencin de Microsoft). Por otra parte tenemos los obscuros planes de Microsoft de lanzar una consola basada en Direct3D y Windows CE en conjuncin con SEGA y de crear una nueva API trabajado conjuntamente con Silicon Graphics, que promete ser una fusin de ambas APIs. Por esto no debemos preocuparnos por un futuro lleno de conjeturas y ocuparnos por el presente. Nuestra recomendacin (si de algo sirve para aquellos que despus de leer esto quedaron aun ms confundidos) es determinar el mercado de la aplicacin que pretendemos realizar y el tiempo que se tiene para terminar el proyecto, de esta forma podremos decidir por una complicada API con mercado amplio en las PCs como Direct3D; o bien una API sencilla con un mercado ms restringido en las PCs que nos permite la posibilidad de portar cdigo a casi cualquier plataforma de una forma mas sencilla como tal es el caso de OpenGL. En posteriores nmeros estudiaremos ms a fondo cada una de estas APIs (OpenGL y Direct3D), y presentaremos algunos programas interesantes que podemos realizar con Delphi basndonos en estas tecnologas (como el mostrado en la figura 1), as como algunas cuestiones relacionadas con la representacin virtual de objetos. Figura 1. Un ejemplo de una Aplicacin 3D hecha en Delphi usando tecnologa OpenGL.

Otras consideraciones adicionalesEst claro que en un futuro cercano las tarjetas aceleradoras 3D de hardware reemplazarn por completo las actuales,

Figura 1. Un ejemplo de una Aplicacin 3D hecha en Delphi usando tecnologa OpenGL.

3

Introduccin a la Programacin de Grficos con OpenGLConstruccin de Aplicaciones Grficas. Matrices y Vectores. Inicializacin de Contextos y consideraciones adicionales.Bien, ahora nos dedicaremos a estudiar especficamente el API de grficos OpenGL. En el articulo del n mero pasado hablbamos de las comparaciones entre OpenGL y Direct3D, y de lo que es un API de grficos solo en teora, pero esta vez estudiaremos ms a detalle y con ejemplos de cdigo como se construye una aplicacin grfica basada en OpenGL. Siendo honestos, la programacin de grficos 3D no es un tema sencillo, ya que requiere de conocimientos previos de anlisis numrico, lgebra lineal, fsica y otros muchos temas extras, sin embargo aqu trataremos de hacer esto lo ms digerible posible para que todo el mundo podamos entenderlo sin tanto embrollo; aunque desafortunadamente, no hay forma de evitar la necesidad de tener conocimientos sobre matrices, vectores, y un poco de geometra, as que ms conviene dedicar algo de tiempo a estudiar estos temas si se quieren hacer este tipo de aplicaciones.

que esto ofrece independencia del sistema operativo, pues no es lo mismo crear una ventana basndose en las APIs de Windows que crear una ventana en algn ambiente grfico de Unix o Linux, por esto, si se usa GLUT como manejador de ventanas, no se tendra que reescribir el cdigo para migrar la aplicacin de plataforma, ya que solo habra que conseguir la versin de GLUT para el ambiente grfico deseado y volver a compilar nuestro programa en el nuevo ambiente. Esto debemos pensarlo los programadores de Delphi si deseamos usar OpenGL en la inminente nueva versin de Delphi para Linux. Las funciones contenidas en esta librera empiezan con las letras glut. Estas libreras se encuentran disponibles en Internet, y se distribuyen de manera gratuita en diferentes sitios, principalmente se pueden encontrar en el sitio oficial de OpenGL en http://www.opengl.org , donde seguramente encontrarn las de su sistema operativo en especfico. Otro componente es el llamado Frame Buffer, que no es otra cosa que el rea de memoria donde se construyen los grficos antes de mostrarlos al usuario, es decir, que nuestro programa de OpenGL escribe en esta rea de memoria, y automticamente enva su contenido a la pantalla una vez que la escena est completamente construida. La figura 1 muestra grficamente como esta constituida la estructura de abstraccin de OpenGL.

Como Funciona OpenGL?OpenGL funciona a travs de una serie de libreras DLL que suelen tener variados nombres, pero que a fin de cuentas cubren funciones muy especficas y son muy sencillas de identificar, ahora veremos cuales son estas: OpenGL.DLL (Open Graphics Library, Librera de Grficos Abierta).- Esta podemos encontrarla tambin con el nombre de OpenGL32.DLL (para el caso de los sistemas operativos de 32 bits) o bien simplemente como GL.DLL . Esta es la librera principal, que contiene la mayora de las funciones que aqu utilizaremos. Las funciones contenidas en esta librera inician con las letras gl. GLU.DLL (Graphics Utility Library, Librera de Utileras de Grficos).- Tambin la podemos encontrar como GLU32.DLL. Contiene funciones para objetos comunes a dibujar como esferas, donas, cilindros, cubos, en fin, varias figuras ya predefinidas que pueden llegar a ser tiles en ciertos casos, as como funciones para el manejo de la cmara entre muchas otras. Podremos identificar las funciones que pertenecen a esta librera porque llevan antepuestas en su nombre las siglas glu. GLUT.DLL (GL Utility Toolkit, Equipo de Herramientas de Utilera para el desarrollo de Grficos).- Esta tambin permite crear objetos complejos como GLU, aunque la principal funcin de esta librera es permitir que los programas se vuelvan interactivos, o sea que posibilita la libre creacin de ventanas, as como el acceso al ratn y al teclado. Nosotros podramos llegar a prescindir en ese aspecto de GLUT, ya que Delphi nos ofrece de manera natural poder crear ventanas y responder a los diferentes eventos del manejo del ratn y el teclado; sin embargo, muchos programadores (principalmente programadores de C y C++) piensan que programar aplicaciones basadas en GLUT tiene muchsimas ventajas, ya

Figura 1 Niveles de Abstraccin en OpenGL

Las Piedras angulares: las matrices y los vectoresAqu es donde empieza el trabajo sucio de todo este asunto. Toda la geometra que se despliega en las aplicaciones OpenGL est basada en los conceptos de Matrices y Vectores y las operaciones aritmticas aplicables a estas estructuras. En OpenGL existen bsicamente tres matrices principales: Una matriz de proyeccin llamada GL_PROJECTION, la cual nos permite determinar la perspectiva que usaremos para observar la escena generada, as como el tipo de proyeccin a usar (esto tiene que ver mucho con cuestiones de ptica y de geometra, y abordaremos este tema en otra ocasin ms especficamente, ya que es bastante extenso y complejo). Esta matriz tiene una gran relacin con otro concepto tambin muy interesante llamado clipping, que consiste en recortar u ocultar todo aquello que est pero no se ve, es decir lo que queda fuera del foco de nuestra cmara o nuestro campo visual activo, este es un proceso que se hace automticamente una vez, habiendo 4

Introduccin a la Programacin de Grficos con OpenGLinicializado pertinentemente esta matriz. Una matriz de Modelado llamada GL_MODELVIEW, donde sta es la matriz que usaremos para aplicar a nuestra escena operaciones de rotacin, traslacin o escalamiento, o bien para manipular la posicin y orientacin de la cmara, para obtener as las animaciones. La figura 2 muestra algunos ejemplos de matrices de transformacin lineal para el caso de sistemas de 3 de los vectores, y como se transforman las coordenadas hasta llegar a las coordenadas reales de la ventana.

Vectores de diversos tipos

Los vectores son un conjunto de valores que nos permiten definir dentro de nuestra escena, desde los vrtices de las figuras, hasta los colores, los materiales y las luces, entre otras muchas cosas. Existen bsicamente dos formas de trabajar con vectores en OpenGL, con sus elementos como variables independientes, o manejarlos como una estructura de datos. Cuando trabajamos sus elementos de forma independiente cada vector es descompuesto en 3 4 valores segn sea el caso. Y cuando se maneja como una estructura estos valores estn contenidos en una estructura de datos que bien puede ser un arreglo un registro. Decimos que los vectores pueden descomponerse en 3 o 4 valores, ya que en el caso de los colores estos estn compuestos por tres que determinan el color, codificados en RGB, y un elemento extra en algunos casos, que determina el nivel de transparencia para Figura 2. Matrices Genricas de Transformacin Lineal para Sistemas de 3 Dimensiones. dimensiones. Y una ltima matriz para el manejo de Texturas llamada GL_TEXTURE, sobre la cual tambin podemos aplicar las transformaciones lineales de rotacin, traslacin y escalamiento para manipular las texturas a utilizar en las figuras de nuestra escena, cuando estemos ms avanzados explicaremos mas a detalle el manejo de texturas en nuestros programas, pero debemos aprender a gatear antes de intentar correr. Podemos hacer uso de cada una de estas matrices mediante el procedimiento GLMatrixMode(), el cual nos permite seleccionar una de estas matrices para su configuracin. Para inicializar con valores cada matriz se invoca a un procedimiento llamado GLLoadIdentity(), el cual carga la matriz identidad, que es aquella que solo contiene valores de 1 en toda su diagonal (como se muestra en la figura 3), lo cual hace que multiplicar cualquier vector por esta matriz nos d como resultado al mismo vector sin que haya sufrido ninguna transformacin. Ahora tal vez Figura 4. Secuencia de Transformacin de Coordenadas.

Tipos en OpenGLFigura 3. La Matriz Identidadse preguntarn y de cual hierba hay que fumar para saber como multiplicar vectores por matrices?, pues basta con echar una mirada a cualquier libro de lgebra Lineal y ah se explica el oscuro procedimiento. En la figura 4 podemos observar el orden en como se aplican las matrices a cada uno Debemos recordar que las libreras de OpenGL fueron escritas originalmente en C, as que conservan muchas caractersticas de este lenguaje, entre ellas, la estructura de sus procedimientos, y los tipos que se utilizan. Aunque en los tipos de OpenGL se anteponen las siglas GL, estos guardan una marcada equivalencia con los tipos genricos de C, as GLFloat sera el equivalente al tipo float de C, y GLint, al tipo int. Y los rangos del dominio alcanzado por cada uno de estos tipos depende de su correspondiente equivalencia en C. Aunque OpenGL tambin provee de ciertos tipos de datos estructurados para el manejo tanto de matrices como de vectores, y generalmente estos tipos ya vienen en las libreras de OpenGL para Delphi con su respectiva equivalencia en tipos de Object Pascal.

5

Introduccin a la Programacin de Grficos con OpenGLel objeto, cara vrtice al cual corresponda dicho color, a esta caracterstica de transparencia se le conoce comnmente como Alpha Blending. Todos estos valores (en el caso especfico de los colores) tienen un dominio que flucta en el rango de 0 a 1. Los vectores estn compuestos por nmeros que pueden ser de tipo real, enteros, bytes, doubles, short, etc... Aqu cabe sealar que OpenGL provee de sus propios tipos, los cuales por convencionalismos similares al que usamos en Delphi, anteponiendo una T a las clases que usamos, en OpenGL se antepone GL a la definicin de Tipos que se utiliza, as por ejemplo GLFloat, es el equivalente del tipo Single en Delphi, y as existen muchas equivalencias entre ambas tipologias (Ver recuadro: Tipos en OpenGL). Para declarar un vector como un vrtice descomponiendo sus elementos usaramos la instruccin GLVertex3f(X,Y,Z), donde X, Y y Z son variables constantes de tipo GLFloat, Real, Single. La parte final de la instruccin que usamos: 3f , nos indica que el procedimiento recibe como parmetro tres valores de punto flotante. As la instruccin GLVertex3i() funcionar exactamente igual solo que con valores enteros. Cuando trabajamos los vectores como una estructura de datos lo que hacemos es pasar la direccin de memoria de esta estructura en la llamada del procedimiento, usando el operador @. Por ejemplo: Si suponemos una variable V de tipo Tvector, donde Tvector est definido como: Tvector = Array [0..2] of GLFloat; podramos usar la instruccin: GLVertex3fv(@V); para declarar el vrtice a partir de este dato estructurado. Observen como en estos casos las instrucciones para manejar estructuras terminan en: v.private { Private declarations } procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; public { Public declarations } end; var Form1: TForm1; RC : HGLRC; Angulo : GLInt; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin RC:=CreateRenderingContext(canvas.Handle,[opDoubleBuffered],32,0); //Primero Creamos un contexto... end; procedure TForm1.FormDestroy(Sender: TObject); begin DestroyRenderingContext(RC); //Se libera el Contexto... end; procedure TForm1.FormPaint(Sender: TObject); Var X,Y,Z:GLInt; begin ActivateRenderingContext(canvas.Handle,RC); // Se asocia el contexto con el manejador del Canvas... glClearColor(0,0.2,0,0); // Ponemos un color Verde Oscuro de Fondo... glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Algo as como borrar la Pizarra... glMatrixMode(GL_MODELVIEW); glLoadIdentity; gluLookAt(0,0,3,0,0,0,0,1,0); // Posicin y punto de vista de la cmara... glRotatef(30,1,0,0); //Primero hacemos una rotacin de 30 grados respecto a X para obtener perspectiva... glRotatef(Angulo,0,1,0); //Se Rota la figura en el eje Y a partir de la variable Angulo... GLPointSize(2.0); //Asignamos un tamao de 2 pixeles para cada punto... //Ahora con tres ciclos anidados dibujamos un cubo con puntos de colores variados... GLBegin(GL_POINTS); For x := -5 to 5 do for y := -5 to 5 do for z := -5 to 5 do begin GLColor3f(X,Y,Z); GLVertex3f(X/10,Y/10,Z/10); end; GLEnd; SwapBuffers(canvas.Handle); //Copiar el Back Buffer en el canvas del formulario... DeactivateRenderingContext; //Libera el contexto... end; procedure TForm1.FormResize(Sender: TObject); begin // Cuando se cambia de tamao hay que actualizar el puerto de visin... wglMakeCurrent(canvas.handle,RC); // Otra manera de hacer el contexto dibujable cuando este ya est creado... glViewport(0,0,Width,Height); // Especificar un puerto de visin.... glMatrixMode(GL_PROJECTION); // Activar matriz de proyeccin... glLoadIdentity; // Poner estado inicial en esta matriz... gluPerspective(35,Width/Height,1,100); // Especificar Perspectiva ... wglMakeCurrent(0,0); // Otra manera de liberar el contexto... Refresh; // Redibujar la escena ... end;

En Delphi!, En Delphi por favor!Bueno, ahora realizaremos nuestro primer programa OpenGL en Delphi, pero para esto, a fin de hacer las cosas mucho ms sencillas y que no nos cueste tanto trabajo empezar, utilizaremos una adecuacin a la librera OpenGL.Pas (versin 1.2) de Delphi hecha por Mike Lischke, un alem n con muchas aportaciones al mundo de los grficos en Delphi, y que provee en esta librera muchas funciones que facilitan el proceso de inicializacin de contextos, que nos permitirn entender este caso de una manera muy sencilla. Tanto el cdigo fuente que aqu veremos, como las libreras .pas que utilicemos podrn descargarlas desde el sitio web de esta revista sin ning n problema. Primero que nada echemos un vistazo al Listado 1, y ahora analizaremos bit por bit este cdigo fuente, al menos eso intentaremos.unit Unit1; interface uses Windows, Forms, OpenGL, Classes, ExtCtrls, Messages, Controls, StdCtrls,Graphics, sysUtils, Dialogs; type TForm1 = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormResize(Sender: TObject); procedure Timer1Timer(Sender: TObject);

6

Introduccin a la Programacin de Grficos con OpenGLinicializacin con GLLoadIdentity(), para poder aplicar las operaciones de rotacin con las operaciones GLRotate() a los vrtices que luego se definen. La operacin gluLookAt() sirve para determinar un punto de observacin ( cmara) para la escena, podramos obtener el mismo efecto de rotacin si en vez de transformar los vrtices de la escena solo movemos este punto de observacin, es algo similar a lo que se hace en los clsicos juegos 3D de estilo Doom. En posteriores artculos hablaremos concretamente de la cmara y su utilizacin en concreto. Esta animacin la construiremos utilizando solo puntos aislados, por lo que usamos la operacin GLPointSize() para determinar el nmero de pxeles reales que ocupar cada uno de nuestros puntos, en nuestro caso 2. Y luego entre las declaraciones GLBegin() y GLEnd() que sirven para determinar los vrtices de una figura, llamamos a GLColor3f() y GLVertex3f() dentro de tres ciclos anidados para dibujar todos los vrtices con su correspondiente color. Ntese que se deben de declarar primero los colores que los vrtices, porque como veremos ms adelante, OpenGL funciona como una mquina de estados finitos, donde se deben declarar los atributos antes de las figuras.

procedure TForm1.Timer1Timer(Sender: TObject); begin Inc(Angulo,4); //Rotamos el angulo de observacin de la escena... Angulo := Angulo mod 360; Refresh; //y la volvemos a dibujar ... end; procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin //Para borrar el fondo, y evitar el parpadeo ... Message.Result:=1; end; end.

Como podemos observar en el listado, tenemos un formulario y un componente Timer, el formulario nos servir como la ventana en donde se mostrarn los grficos; y el Timer ser quien coordine nuestra animacin, en esta ocasin a fin de hacer las cosas ms sencillas usaremos el Timer para esta finalidad, pero ya veremos ms adelante en artculos posteriores que es mucho mas eficiente utilizar hilos de ejecucin de alta prioridad para hacer esto, por ahora dejmoslo de ese tamao. Primeramente y como se deben de imaginar, necesitamos un lienzo en el cual plasmar nuestras obras de arte, por lo cual necesitamos de procesos que nos permitan acceder directamente a algn objeto grfico que nos sirva como lienzo. En este primer ejemplo usamos el Objeto Canvas de nuestro formulario, pero en teora podemos utilizar el Canvas de cualquier otra clase que contenga a ste objeto (un PaintBox por ejemplo). A este lienzo le llamaremos el contexto. Como pueden darse cuenta tenemos una variable global llamada RC de tipo HGLRC, esta variable ser la que represente nuestro contexto dibujable. En el evento OnCreate del formulario hemos escrito una lnea de cdigo que sirve para asociar nuestro contexto con el manejador (handle) del objeto Canvas del formulario, lo cual hace que nuestras animaciones se desplieguen sobre este Canvas. Los parmetros que se pasan a este procedimiento los estudiaremos a detalle en otra ocasin. Del mismo modo en el Evento OnDestroy del formulario debemos escribir una lnea de cdigo que libere nuestro contexto del Canvas, para evitar as apuntadores perdidos por ah. Ahora, las animaciones como han de suponer deben construirse escena por escena, como en las pelculas de dibujos animados, con ligeras diferencias entre ellas para obtener calidad en nuestra animacin, y a la vez debemos hacer uso de algn evento para mostrar estas escenas; as que podemos utilizar el evento OnPaint del formulario para irlas mostrando una por una. Como sabemos este evento se dispara cada vez que Windows tiene que dibujar el formulario as que podemos ocuparlo para que haga en l lo que nosotros deseamos que se vea. En este evento es donde escribimos el cdigo para generar las escenas que nos interesa mostrar, vemos como con cada frame o escena, hacemos el contexto dibujable y al finalizar lo liberamos de nuevo. La instruccin glclearcolor() recibe como parmetro un vector de 4 valores que determinarn el color con el que se inicializar nuestro frame buffer antes de escribir en l, dando como resultado un color de fondo. La instruccin GLClear() sirve para borrar de este frame buffer valores de escenas que hayan sido construidas previamente a la actual. Tambin podemos observar como hacemos uso de la matriz ModelView, y su

Y el resto?Hasta ahora ya utilizamos la matriz de modelado para hacer las rotaciones, pero como vemos en el evento OnResize hacemos uso de la matriz de proyeccin para definir nuestro puerto de visin y perspectiva. Entender como funciona realmente la matriz de proyeccin es un poco complicado y ya la estudiaremos a su tiempo, por ahora solo debemos entender que el evento OnResize se dispara cada vez que modificamos el tamao de nuestra ventana, por lo cual debemos ajustar la escala de lo que estamos observando para no perder las dimensiones, es por eso que debemos tenerlo presente. Observen como al final del cdigo para este evento usamos el mtodo Refresh del TForm, lo cual obliga al formulario a volver a dibujar la escena con la matriz de proyeccin ya ajustada. Tambin cuando Windows trata de dibujar el formulario despus de haberlo creado se dispara OnResize, lo que nos garantiza que, desde el principio, tendremos ajustada nuestra perspectiva sin la necesidad de modificar nosotros mismos el tamao de nuestra ventana. Una vez ejecutando este programa traten de modificar el tamao ustedes mismos para que vean como es que funciona esto. El procedimiento del Timer lo nico que hace es incrementar una variable global llamada Angulo y volver a dibujar la escena; la operacin mod que efectuamos a esta variable es para asegurarnos que su dominio solo fluctuar entre los valores 0 y 359, que son los 360 grados de una circunferencia. Nosotros en el evento OnPaint rotamos la escena conforme a esta variable, lo que ocasiona que escena con escena obtengamos nuestra figura en diferentes posiciones relativas, y con esto obtener la animacin. El numero de unidades que incrementemos a esta variable con cada escena, ser lo que determine la calidad de nuestra animacin a final de cuentas. Ahora como estamos utilizando el Canvas del formulario como lienzo y continuamente estamos mandando a redibujar la escena, forzamos a que Windows tenga que borrar el contenido del formulario anterior antes de mostrar el nuevo contenido, lo cual ocasiona un continuo parpadeo en nuestra animacin, cosa 7

Introduccin a la Programacin de Grficos con OpenGLque no es nada deseable. Por esto lo que tenemos que hacer es evitar que Windows se tome esta molestia, de cualquier modo nosotros mismos estamos dibujando sobre esta ventana lo que se nos va antojando, as que para que perder ese valioso tiempo. Para evitar que Windows borre el contenido del formulario debemos utilizar un manejador de mensajes que opere para el mensaje WM_ERASEBKGND, el cual es enviado por Windows cada que se necesita borrar el fondo de una ventana, para evitar que Windows tome alguna accin, slo debemos devolver como resultado un valor distinto de 0 para indicar que nosotros mismos haremos ese trabajo (en nuestro caso devolvemos un 1). Los manejadores de mensajes en este tipo de aplicaciones suelen ser bastante tiles, ya veremos despus como responder a cambios en la paleta de colores y en la resolucin de la pantalla por citar algunos casos. Y con esto es suficiente para poder compilar y observar nuestra primera animacin con OpenGL (Figura 5), hace por Software, as que no se quejen si en su equipo las animaciones se ven demasiado lentas, lo ms seguro es que su Hardware sea el culpable. Bueno, hasta aqu llegamos en esta ocasin, porque parece que tenemos suficiente con que entretenernos por ahora, y todava mucho por estudiar en el futuro... Hasta Pronto.

Figura 5. Nuestra Primera Aplicacin de OpenGL en Ejecucin. sorprendente verdad?, con muy pocas lneas de cdigo hemos conseguido grandes resultados, como ya es costumbre con los programas que hacemos con Delphi. Ahora algunas consideraciones extras: Por alguna extraa razn las aplicaciones que hacemos con Delphi usando OpenGL ocasionan un conflicto cuando las ejecutamos desde el IDE, por lo cual es recomendable solo compilarlas y ejecutarlas desde fuera del Ambiente de Desarrollo Integrado. Y una cosa ms, recordemos que OpenGL utiliza aceleracin por Hardware para optimizar el renderizado de las escenas, pero cuando el nuestro no provee esas caracter sticas de aceleracin, todo lo que debera de hacerse por Hardware se 8

Lneas con OpenGL en dos dimensionesProyeccin Ortogonal 2D. Construccin de grficos con Lneas. Antializado. Algoritmos recursivos de Fractales.OpenGL no se utiliza solamente para generar impresionantes grficos 3D, sino como veremos a continuacin tambin puede utilizarse para hacer grficas en 2 dimensiones. En esta ocasin trabajaremos con los diferentes tipos de lneas que nos ofrece OpenGL; y a fin de hacer este tema todava mas interesante veremos un extra bastante til e impresionante: Los Fractales, un concepto matemtico muy utilizado en la graficacin por computadora.

En este caso cualquier coordenada que definamos como (x,y,z), ser proyectada sobre el plano de visualizacin z=0 como (x,y,0), y si esta coordenada entra dentro de nuestro rectngulo ser mostrada en nuestro despliegue (ver figura 1). Si es nuestra intencin modificar las coordenadas de nuestro rectngulo de visualizacin debemos definirlas mediante la instruccin glOrtho2D(), con la cual declaramos los valores de 2 coordenadas que determinarn el rea del rectngulo, es decir, la esquina superior izquierda y la inferior derecha.

Qu son los Fractales?Para comprender lo que es un fractal, hagamos un pequeo ejercicio: tomemos una hoja de papel y dibujemos sobre ella un segmento rectilneo. La geometra Euclidiana nos dice que se trata de una recta y por tanto tiene una sola dimensin (su longitud). Ahora extendamos el segmento rectilneo haciendo trazos de un lado a otro sin que stos se crucen hasta llenar toda la hoja. La geometra Euclidiana nos dice que todava se trata de una lnea y que tiene una sola dimensin, pero nuestra intuicin nos dice que si la lnea llena completamente el plano debe tener ms de una dimensin, si bien no llegar a tener dos. Esto implica que nuestro dibujo debe tener una dimensin fraccionaria. Este concepto tan simple comenz toda una revolucin en las matemticas. Varios matemticos de fines del siglo XIX y principios del XX propusieron la existencia de una dimensin fraccionaria y no debiera sorprendernos que sus colegas los tildaran de locos, pues esa idea aparentemente tan aberrante atentaba contra la nocin de dimensiones enteras que todos conocemos. Hubieron de pasar cerca de 50 aos para que un matemtico se tomara en serio tan aventuradas teoras. En 1975 el Dr. Benot Mandelbrot, acu un nombre para estas figuras que tienen una dimensin fraccionaria. Las llam fractales, trmino que deriv del adjetivo latino fractus, que significa "irregular" o "interrumpido". Mandelbrot afirma que as como las figuras geomtricas convencionales son la forma natural de representar objetos hechos por el hombre (cuadrados, crculos, tringulos, etc.), los fractales son la forma de representar objetos que existen en la Naturaleza. De tal forma, los fractales tienen una doble importancia: como objetos artsticos (por poseer una singular belleza) y como medio para representar escenarios naturales. Es ms, los fractales estn presentes en las expresiones utilizadas para describir fenmenos tan variados como la prediccin del clima, el flujo turbulento de un lquido, el crecimiento o decrecimiento de una poblacin y, hasta para comprimir imgenes. La idea principal detrs de los fractales es que algunas imgenes pueden ser producidas repitiendo una fraccin de s mismas. Tomemos como ejemplo un rbol: si observamos una de sus ramas, caeremos en la cuenta de que asemeja un rbol en pequeo. Valindonos de esta curiosa propiedad (llamada auto-similitud o "self-similarity" en ingls) puede dibujarse una figura compleja repitiendo una imagen mucho ms simple. A esta repeticin se le llama recursividad. Llevando la recursin a niveles ms elevados llegaremos al concepto de Sistemas de Funciones Iteradas o IFS (por sus 9

Visualizacin 2DAunque aqu tratemos el tema de la visualizacin 2D en OpenGL, es importante recordar que este es un API grfico de 3 dimensiones; as que si queremos utilizarlo para hacer representaciones 2D tenemos que hacer un pequeo truco. Como ustedes han de suponer lo que hemos de hacer es graficar todo lo que deseemos en un plano, para obtener as la apariencia de que estamos trabajando con 2 dimensiones aunque realmente sigamos trabajando en 3. Entonces la visualizacin 2D se basa en tomar un rea rectangular de nuestro mundo 3D y transferir su contenido a nuestro despliegue. El rectngulo de visualizacin est en el plano z=0. Por default si no se especfica el volumen de visualizacin se construye un rectngulo de 2x2, donde las coordenadas de este rectngulo quedan como: ((-1.0,-1.0),(1.0,1.0),(1.0,-1.0),(1.0,1.0)), estas coordenadas, claro, en el plano z=0.

Figura 1

Lneas con OpenGL en dos dimensionessiglas en ingls): tomemos un punto y movmoslo por la pantalla, trasladmoslo, rotmoslo y ajustemos su escala aleatoriamente. Esto nos permitir obtener imgenes relativamente complejas a partir de patrones sumamente simples, si iteramos un nmero adecuado de veces. Todos estos conceptos aunque de entrada parezcan complejos, veremos que su aplicacin no lo es tanto y cmo podemos nosotros usar fractales para representar todo un paisaje, con objetos de la naturaleza de una manera muy sencilla y simple. Digital) entre otros, se limitan solo a encontrar aquellos pixeles que puedan representar a la lnea en cuestin, pero no se ocupan de la presentacin que esta tendr para el usuario. En OpenGL existe un concepto muy interesante al respecto llamado antialiazing o antializado. El antializado consiste precisamente en eliminar esos escalonamientos que se presentan tanto en las lneas como en los contornos de las figuras a representar para obtener as figuras ms realistas, que no se vean tan poligonales. En esta ocasin estudiaremos el antializado en cuanto a lneas.

Tipos de Lineas en OpenGLExisten bsicamente 3 tipos de lneas en OpenGL: Lneas sencillas, Lneas en ciclo y Lneas con patrones. Como habamos visto en el nmero anterior la definicin de figuras en OpenGL se hace con las instrucciones GLBegin() y GLEnd(), donde a GLBegin() se le pasa como parmetro el tipo de figura que nos interesa dibujar con los vrtices definidos entre estas instrucciones (el ejemplo pasado lo hicimos solo con puntos usando GL_POINTS), as que ahora estudiaremos como hacer lneas con ellas. Para hacer lneas sencillas usamos GL_LINES, con esta instruccin como parmetro para GLBegin() indicamos a OpenGL que dibuje una lnea que una cada dos vrtices que nosotros definamos. Algo muy similar a cuando trabajbamos con el Objeto Canvas y usbamos las instrucciones MoveTo(x,y) y LineTo(x,y), lo recuerdan?... ah... que tiempos aquellos! ... Las lneas en ciclo nos sirven para definir contornos. Para hacer este tipo de lneas usamos GL_LINE_LOOP, cuando utilizamos esta instruccin unimos todos los vrtices que definimos con una misma lnea en el orden en que hayan sido estos definidos, y al mismo tiempo se unen el ltimo vrtice definido con el primero, cerrando as la figura. Esto es muy til para dibujar contornos de polgonos (ya sean regulares o irregulares), por ejemplo. Recuerdan cuando trabajbamos con el Canvas que podamos cambiar el estilo de la pluma para dibujar lneas punteadas o con diversos patrones?. Pues en OpenGL tambin se pueden declarar varios patrones para dibujar lneas. Para ello usamos en nuestro ejemplo la instrucci n GL_LINE_STRIP como parmetro, ste permite escribir una secuencia de lneas unidas vrtice a vrtice, pero a diferencia de GL_LINE_LOOP el ltimo vrtice no se une con el primero. Ya veremos sobre la marcha como declaramos los patrones a utilizar.

Vamos al Cdigo!Bueno, vamos directamente al ejemplo que aqu presentamos. Echemos una mirada al Listado 1, y a ver que podemos aprender de esto. Por ahora pasemos por alto los procedimientos que hemos definido para dibujar los fractales y centrmonos en los eventos de los objetos. Como pueden darse cuenta la estructura de este programa es muy similar a la del programa que estudiamos en el nmero anterior, ya que seguimos usando la misma versi n de OpenGL.Pas, y el mtodo de inicializacin de contextos no cambia para nada. Las diferencias las empezamos a encontrar en el evento OnPaint(). Como vemos en la instruccin GLClear(), solo pasamos como parmetro el Buffer de Color (GL_COLOR_BUFFER_BIT) y ya no el buffer de profundidad (GL_DEPTH_BUFFER_BIT) como en el ejemplo pasado; la razn es que ahora slo trabajaremos en 2 dimensiones, as que no hay relacin de profundidad entre las figuras que dibujaremos, por lo que no necesitamos limpiar este buffer. Luego encontramos la instruccin gluOrtho2D (-1.0, 1.0, 0.0, 1.5); con la que definimos un rectngulo de visualizacin cuya esquina superior izquierda es (-1.0,1.5) y la esquina inferior derecha es (1.0,0.0). Ahora aqu vienen unas instrucciones que tal vez les resulten nuevas en este momento glPushMatrix() y glPopMatrix(). Suponemos que todos aqu hemos trabajado alguna vez con estructuras de datos de tipo Pila, y que entendemos los procedimientos de insercin y eliminacin de elementos de esta estructura. Bueno, pues estas instrucciones trabajan con una pila de matrices y sirven para hacer respaldos de la matriz de transformaciones que luego podemos recuperar. La finalidad de hacer estos respaldos es para poder hacer ciertas transformaciones sobre figuras especficas sin que stas afecten al resto de las figuras en nuestra escena. Esto es verdaderamente til como veremos ms adelante. Delimitemos ahora lo que pretendemos realizar con este cdigo. Bien, pues lo que dibujaremos es: un paisaje en el campo durante una noche de Eclipse de Luna , qu les parece?, no me negarn que es un ttulo bastante artstico para nuestra obra de arte; y todo usando solo lneas. Nuestro paisaje estar compuesto por rboles, estrellas, y la luna eclipsada, por supuesto. As que necesitamos procedimientos que dibujen cada una de estas figuras. Tanto los rboles como las estrellas las construiremos usando fractales con procedimientos recursivos. Los fractales que usaremos sern del tipo de los sistemas S>eS*, lo que significa que sern sistemas que contendrn 10

Calidad en el trazado de lneasTambin, como en el nmero anterior vimos la instruccin para hacer ms grande el tamao de los puntos que dibujamos, en el caso de las l neas podemos hacer que OpenGL las dibuje ms gruesas de cmo las presenta originalmente con la instruccin glLineWidth() , pasndole como parmetro un nmero entero que indique el nmero de pixeles que ocupar el ancho de las lneas a dibujar. Volviendo a los aejos recuerdos del Canvas... Recuerdan como cuando dibujbamos lneas con cierto ngulo diagonal, se dibujaban en forma de escalerita?; esto se debe en gran medida a que los algoritmos clsicos de trazado de lneas como el mtodo de Bresenham el del DDA (Anlisis DiferencialGLPointSize()

Lneas con OpenGL en dos dimensioneselementos y a la vez a alguno algunos subsistemas similares. En nuestro caso, los elementos sern Lneas y los subsistemas sern llamadas recursivas al mismo procedimiento. Basndonos en este tipo de sistemas podemos construir diversos tipos de figuras de la naturaleza, como rboles, estrellas, piedras, nubes, e incluso podr amos llegar a representar el sistema solar. Analicemos primeramente el procedimiento para construir rboles. La llamada a este procedimiento tiene los siguientes parmetros: Arbol(x,y,t,teta,w:real); la idea con este procedimiento es dibujar a partir del punto (x,y), un segmento de lnea de longitud t e inclinacin teta. Y despus volver a llamar recursivamente a este procedimiento, pasando como parmetros el extremo final del segmento de recta generado y los parmetros t y teta con valores modificados para hacer simtrica la figura. A fin de cuentas lo que hacemos es dibujar un arbolito ms pequeo al final de cada segmento de recta. Observen como ahora utilizamos glVertex2f() para declarar nuestros vrtices ya que trabajamos en dos dimensiones. El parmetro w nos servir para determinar el tipo de rbol que deseamos dibujar, pues como veremos, este simple procedimiento nos permite dibujar Cipreses, Jacarandas y Pinos. A poco no es sorprendente?. Algo similar pasa con el procedimiento para dibujar las estrellas, solo que aqu todos los segmentos de recta tienen un mismo origen, el centro de la estrella. As que lo que variamos es el ngulo de inclinacin de cada segmento para obtener as la figura final. Un detalle ms: hemos puesto el trazado de la lnea punteada entre dos sentencias de push y pop de atributos. Recuerdan cuando en el artculo del nmero anterior dijimos que OpenGL es una mquina de estados?, en futuros artculos veremos con ms detalle estas operaciones de push y pop para el caso de los atributos, pero brevemente lo que estamos haciendo con la primera sentencia glPushAttrib(GL_LINE_BIT) es guardar en una pila el valor actual de la variable de estado GL_LINE_BIT (esta variable decide el patrn de punteado), entonces podemos modificar GL_LINE_BIT con nuestra sentencia glLineStipple() y cuando hemos acabado llamamos a glPopAttrib() que devuelve el valor antiguo de la variable GL_LINE_BIT. Este mecanismo es una manera efectiva de modificar las variables de estado de OpenGL localmente. Si no lo hacemos as entonces todas las lneas dibujadas despus de glLineStipple() tendran el mismo patrn de punteado y estaramos forzados a declarar un patrn con glLineStipple() para cada lnea que trazsemos en nuestra aplicacin. Push y pop nos evitan este molesto trabajo.

Y la luna y el antializado?Bien, pues la luna la construiremos como si fuera un polgono con GL_LINE_LOOP, recuerden que a final de cuentas un circulo podemos definirlo como un polgono que tiene muchos lados, tantos que no se llegan a distinguir. En nuestro caso hacemos uno de 100 lados. Como lo que pretendemos es dibujar una

Las lneas punteadasSiguiendo con el anlisis sobre el procedimiento Star(), que dibuja las estrellas, vemos que aqu es donde usamos los patrones con las lneas. La funcin glLineStipple() especifica el patrn usado para el punteado, por ejemplo, si usramos el patrn $AAAA (este es un nmero en hexadecimal), en binario este nmero es 1000100010001000, OpenGL interpreta esto dibujando 3 bits apagados, 1 bit encendido, 3 bits apagados, 1 bit encendido, 3 bits apagados, 1 bit encendido y por ltimo 3 bits apagados y 1 encendido. El patrn se lee hacia atrs porque los bits de menor orden se usan primero. GlLineStipple() tiene dos parmetros, el patrn de punteado que debe ser un n mero hexadecimal y un factor entero que sirve para escalar este patrn; con un factor de 3 nuestra lnea punteada mostrara 9 bits apagados, 3 bits encendidos, 9 bits apagados, 3 bits encendidos, 9 bits apagados, 3 bits encendidos y por ltimo 9 bits apagados y 3 bits encendidos. Jugando con factores y patrones binarios, uno puede dibujar todo tipo de l neas punteadas complicadas. En nuestro ejemplo usamos el patrn $5555, con un factor de 1, lo que nos da un patrn uniforme de 1 pixel apagado por 1 encendido. Hagan cuentas!.

Figura 2 luna eclipsada, entonces solo debemos preocuparnos de dibujar el contorno de esta luna, y aprovechamos que el color con el que borramos la pizarra es el negro para evitar dibujar el resto. Ahora, como decamos, dibujar tantas lneas en tan diferentes ngulos ocasiona que nuestro circulo no luzca bien definido, por lo que aqu si es conveniente utilizar el antializado. El antializado para el caso de las lneas se habilita con la instruccin glEnable(GL_LINE_SMOOTH); y se inhibe con 11

Lneas con OpenGL en dos dimensionestglDisable(GL_LINE_SMOOTH); Lo inhabilitamos porque no nosinteresa dibujar toda nuestra escena con antializado, si no solo la luna. Pueden probar que sucede cuando ignoran estas lneas de cdigo, ya vern que as no parece luna. rboles pequeos, como es que se transforman las figuras fractales para generar los diferentes tipos de rboles que tenemos en nuestra escena, modificando el parmetro w que habamos mencionado. Estas animaciones estn controladas nuevamente por un componente Timer. Por ahora eso es todo, ya tenemos nuestra escena construida (Ver Figura 2); que se diviertan experimentando con las lneas y los fractales. Recuerden que pueden descargar el cdigo fuente de este programa y las unidades extras que utilizamos directamente desde el sitio web de la revista. Hasta Pronto...

Para terminar un poco de animacinPor ltimo, puesto que ya hemos utilizado los diferentes tipos de lneas disponibles en OpenGL, vamos a agregar un poco de animacin a nuestra escena. Si mal no recordamos las estrellas titilan, por lo que usamos una variable para simular este efecto, as como una variable adicional para mostrar con 2

unit Unit1; interface uses Windows, Forms, OpenGL, Classes, ExtCtrls, Messages, Controls, StdCtrls,Graphics, sysUtils, Dialogs; type TForm1 = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormResize(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; public { Public declarations } end; var Form1: TForm1; RC : HGLRC; Angulo : GLInt; Radio : GLFloat = 0; implementation {$R *.DFM}

procedure Arbol(x,y,t,teta,w:real); var x1,y1,t1:real; begin if t > 0.01 then {condicin de paro} begin glbegin(GL_LINES); glVertex2f(x,y); x1 := x -t * cos(teta); y1 := y -t * sin(teta); glVertex2f(x1,y1); glend; t1 := t /1.7; {Se llama recursivamente al sistema} Arbol(x1,y1,t1,teta-w,w); Arbol(x1,y1,t1,teta,w); Arbol(x1,y1,t1,teta+w,w); end; end;

12

Lneas con OpenGL en dos dimensiones

Procedure Star(X,Y,t,Teta:Real); var X1,Y1:real; begin if Teta < 10 then {Nuestra condicin de paro} begin glEnable (GL_LINE_STIPPLE); //Habilitamos el uso de los patrones... glPushAttrib (GL_LINE_BIT); //Salvamos el estado de las lineas... glLineStipple (1, $5555); //Declaramos el patrn a utilizar... glbegin(GL_LINE_STRIP); glVertex2f(x,y); //Todas las lineas tienen el mismo centro... x1 := x -t * cos(teta); y1 := y -t * sin(teta); glVertex2f(x1,y1); glend; glPopAttrib (); //Recuperamos el estado anterior... {Llamamos recusivamente al sistema} Star(X,Y,t,Teta+0.25); glDisable (GL_LINE_STIPPLE); //Inhibimos los patrones... end; end; Procedure Luna; var i:integer; Coseno,Seno:GLFloat; begin GLBegin(GL_LINE_LOOP); For i := 0 to 100 do begin Coseno := Cos(i*2*PI/100); Seno := Sin(i*2*PI/100); GLVertex2f(Coseno,Seno); end; GLEnd; end; procedure TForm1.FormCreate(Sender: TObject); begin RC:=CreateRenderingContext(canvas.Handle,[opDoubleBuffered],32,0); //Primero Creamos un contexto... end; procedure TForm1.FormDestroy(Sender: TObject); begin DestroyRenderingContext(RC); //Se libera el Contexto... end; procedure TForm1.FormPaint(Sender: TObject); begin ActivateRenderingContext(canvas.Handle,RC); // Se asocia el contexto con el manejador del Canvas... glClearColor(0,0,0,0); // Ponemos un color Verde Oscuro de Fondo... glClear(GL_COLOR_BUFFER_BIT); // Algo as como borrar la Pizarra... glMatrixMode(GL_MODELVIEW); glLoadIdentity; gluOrtho2D (-1.0, 1.0, 0.0, 1.5); //Para trabajar en 2 dimensiones... {Dibujamos algunos arbolitos felices...} glPushMatrix(); //Salvamos la matriz del ambiente... glLineWidth (1); glcolor3f(0,0,1); glrotatef(270,0,0,1); //Se incorporan los arboles... Arbol(0,0,0.3,0,0.5); Arbol(0,0.2,0.2,0,0.25); Arbol(0,-0.15,0.15,0,radio); Arbol(0,-0.65,0.25,0,2.1);

13

Lneas con OpenGL en dos dimensionesArbol(0,0.5,0.2,0,radio); Arbol(0,0.7,0.35,0,0.55); Arbol(0,0.85,0.18,0,0.25); glPopMatrix(); //Recuperamos el ambiente... {Ponemos algunas estrellitas Felices...} glpushmatrix(); glLineWidth (1); glscalef(0.5,0.5,0); GlColor3f(0.5,1,0); Star(0.4,2,0.2*sin(Angulo),0); GlColor3f(1,1,0); Star(0.8,2.25,0.2*sin(Angulo),0); GlColor3f(1,0,0); Star(-0.3,2.4,0.2*sin(Angulo),0); GlColor3f(1,1,1); Star(1.5,2.4,0.2*sin(Angulo),0); glpopmatrix(); GLPushMatrix; glEnable (GL_LINE_SMOOTH); //Habilitamos el Antializado para las Lineas glLineWidth (5); //Modificamos el ancho de las lineas... GLColor3f(1,1,1); GLScalef(0.15,0.15,0); GLTranslatef(-4,7,0); LUNA; glDisable (GL_LINE_SMOOTH); //inhibimos el antializado... GLPopMatrix; SwapBuffers(canvas.Handle); //Copiar el Back Buffer en el canvas del formulario... DeactivateRenderingContext; //Libera el contexto... radio := radio - 0.03; //Variamos la variable radio if radio 0.01 then {condicin de paro} begin {Se elije el color en que se deplegar la linea} if t < 0.05 then glcolor3f(0,1,0) else if t < 0.1 then glcolor3f(1,1,1) else glcolor3f(1,0,0);

31

Tipos de proyecciones y manejo de la cmara en OpenGL

glbegin(GL_LINES); glVertex3f(x,y,z); x1 := x -t * cos(teta); y1 := y -t * sin(teta); z1 := z -t * sin(teta2); glVertex3f(x1,y1,z1); glend; t1 := t /1.85; {Se llama recursivamente al sistema} S(x1,y1,z1,t1,teta-w,teta2-w,w); S(x1,y1,z1,t1,teta,teta2,w); s(x1,y1,z1,t1,teta+w,teta2+w,w); S(x1,y1,z1,t1,teta+w,teta2-w,w); S(x1,y1,z1,t1,teta-w,teta2+w,w); end; end;

procedure TForm1.FormCreate(Sender: TObject); begin RC:=CreateRenderingContext(Canvas.Handle,[opDoubleBuffered],32,0); end; procedure TForm1.FormDestroy(Sender: TObject); begin DestroyRenderingContext(RC); end; procedure TForm1.FormPaint(Sender: TObject); var p: PGLUquadricObj; begin ActivateRenderingContext(Canvas.Handle,RC); // Hacer el contexto dibujable glClearColor(0.2,0.3,0,1); // Color de Fondo... glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Borra el Fondo y Depth-Buffer glMatrixMode(GL_MODELVIEW); // Activamos la matriz de modelado glLoadIdentity; // la inicializamos gluLookAt(eyex,eyey,eyez,centerx,centery,centerz,upx,upy,upz); // Definimos un punto de visin... glEnable(GL_DEPTH_TEST); glShadeModel ( GL_SMOOTH) ; gltranslatef(0,0,-3); glrotatef(25,0,1,0); glcolor3f(0,0.5,0); glbegin(gl_quads); glcolor3f(0,0.5,0); glvertex3f(1.5,0,-1.5); //dibujamos un piso ficticio... glcolor3f(0,0.5,1);

32

Tipos de proyecciones y manejo de la cmara en OpenGLglvertex3f(1.5,0,1.5); glcolor3f(1,0.5,1); glvertex3f(-1.5,0,1.5); glcolor3f(1,1,1); glvertex3f(-1.5,0,-1.5); glend; glpushmatrix; glcolor3f(0.8,0.5,0.1); gltranslatef(0, 0.2, 0); glrotatef(90,1,0,0); P := GLUNewQuadric; gluQuadricTexture(p,1); gluCylinder(p,0.13,0.3,0.2,10,10); gluDeleteQuadric(p); gldisable(GL_TEXTURE_2D); glpopmatrix;

//Le ponemos una base feliz.

glpushmatrix; glscalef(5,5,5); glrotatef(270,0,0,1); //Se incorpora el arbol... s(0,0,0,0.15,0,0,(Angle/360)*3); glpopmatrix; SwapBuffers(Canvas.Handle); //Copiar el Back Buffer en el canvas del formulario... DeactivateRenderingContext; //Libera el contexto... end; procedure TForm1.FormResize(Sender: TObject); begin // Cuando se cambia de tamao hay que actualizar el puerto de visin... wglMakeCurrent(Canvas.handle,RC); // Otra manera de hacer el contexto dibujable glViewport(0,0,Width,Height); // Especificar un puerto de visin.... glMatrixMode(GL_PROJECTION); // Activar matriz de proyeccin... glLoadIdentity; // Poner estado inicial... gluPerspective(35,Width/Height,1,100); // Especificar Perspectiva ... wglMakeCurrent(0,0); // Otra manera de liberar el contexto... Refresh; // Redibujar la escena ... end; procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin //Para borrar el fondo, y evitar el parpadeo ... Message.Result:=1; end; procedure TForm1.Timer1Timer(Sender: TObject); begin Inc(Angle,2); Repaint; end; procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if (ssLeft in Shift) then begin dx:=(x-mStartX)/10; dy:=(y-mStartY)/10;

33

Tipos de proyecciones y manejo de la cmara en OpenGLCenterX := CenterX + dx/Width; CenterY := CenterY + dy/Height; end; end; procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin Case Key of 38: if eyez >= -1 then eyez := Eyez - 0.1; 40: if eyez = 360 then Angle:=0; Repaint; end; procedure TMainForm.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin //Para borrar el fondo, y evitar el parpadeo ... Message.Result:=1; end; end.

39

Iluminacin con OpenGL (I)Ahora bien, para construir la esfera usaremos un objeto de la librera glu. As que por esto vemos que declaramos una variable local en este evento de tipo PgluQuadric (esto ya lo habamos mencionado en un articulo anterior, si lo recuerdan). Primeramente hay que definir como se calcularn las normales para este objeto, y a fin de poder seleccionarlo pusimos en la segunda forma un RadioGroup que nos permite elegir entre la iluminacin plana y la iluminacin suave. Para el caso de objetos de la librera glu tambin podemos determinar el modo de iluminacin usando la funcin gluQuadricNormals(), pasando como parmetro el puntero al objeto a modificar (en este caso la variable p), y el tipo de normales que se han de calcular: GLU_FLAT para la iluminacin plana, GLU_SMOOTH para iluminacin suave o Gouraud, y GLU_NONE si no queremos que se calcule ninguna normal para esta figura. Despus elegimos el modo en como se ha de desplegar nuestra esfera, para esto se usa la funcin gluQuadricDrawStyle(), a la cual tambin se le pasa como parmetro el puntero a nuestro objeto, y como segundo parmetro: GLU_FILL si deseamos una esfera slida, GLU_LINE si solo deseamos que la dibuje a base de lneas, tambin puede usarse GLU_POINT GLU_SILHOUETTE para dibujarla como puntos o solo la silueta de la esfera respectivamente. Con gluSphere() construimos propiamente la esfera, indicando el radio que est tendr, as como el nmero de paralelos y meridianos. Cabe sealar que entre ms meridianos y paralelos definamos para nuestra esfera la calidad en la definicin ser mayor, pero tambin el tiempo que consumirn los clculos para realizarla, como ven siempre se sacrifica algo, calidad o velocidad. Y una vez construida podemos liberar nuestro puntero con gluDeleteQuadric(). Tambin al final construimos una esfera ms pequea que la anterior la cual modificamos con ciertas transformaciones para que gire alrededor de la primera a manera de satlite. Esto es un principio para los que planeen hacer una representacin del sistema solar por ejemplo, al final de cuentas solo son esferas girando unas alrededor de otras. Esta pequea esfera no se ve afectada por la luz de nuestra escena ya que la inhibimos antes de construirla, esto para poder establecer una diferencia entre un objeto iluminado y otro que no lo es. En el "listado 2" lo que tenemos son 4 eventos asociados a los TrackBars que controlan tanto la posicin en el eje Y de nuestra luz, as como los valores RGB del color de la misma. Jugando un poco con esto podemos ver como es que funcionan. Noten como a partir de las posiciones de estos TrackBars modificamos valores en los arreglos correspondientes. Bueno, hasta aqu llegamos por ahora, y en el siguiente articulo seguiremos estudiando ms sobre iluminacin y empezaremos a trabajar con materiales, porque esto tambin tiene su chiste. Hasta Pronto.

Listado 2 unit Unit2; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls; type TForm2 = class(TForm) TrackBar1: TTrackBar; Label1: TLabel; RadioGroup1: TRadioGroup; GroupBox1: TGroupBox; TrackBar2: TTrackBar; TrackBar3: TTrackBar; TrackBar4: TTrackBar; Label2: TLabel; Label3: TLabel; Label4: TLabel; RadioGroup2: TRadioGroup; CheckBox1: TCheckBox; procedure TrackBar1Change(Sender: procedure TrackBar2Change(Sender: procedure TrackBar3Change(Sender: procedure TrackBar4Change(Sender: private { Private declarations } public { Public declarations } end;

TObject); TObject); TObject); TObject);

40

Iluminacin con OpenGL (I)var Form2: TForm2; implementation uses Unit1; {$R *.DFM} procedure TForm2.TrackBar1Change(Sender: TObject); begin glfLightPosition[1] := -TrackBar1.Position /10; end; procedure TForm2.TrackBar2Change(Sender: TObject); begin glfLightDiffuse[0] := TrackBar2.Position /10 end; procedure TForm2.TrackBar3Change(Sender: TObject); begin glfLightDiffuse[1] := TrackBar3.Position /10 end; procedure TForm2.TrackBar4Change(Sender: TObject); begin glfLightDiffuse[2] := TrackBar4.Position /10 end; end.

41

Iluminacin con OpenGL (2)Ms sobre Luces, Definicin de Materiales, Tipos de Reflexiones.Bien, continuaremos con la serie sobre iluminacin que iniciamos en el nmero anterior, pero esta vez hablaremos un poco ms tcnicamente acerca de las luces, y de los modos en como sta es recibida por diferentes cuerpos.

nos interesa afectar, el segundo es el parmetro a modificar, y el tercero es el valor valores que tomar dicho parmetro. As pues para indicar estos tres parmetros para la luz nmero 3 de nuestra escena usaramos:glLightf(GL_LIGHT3,GL_CONSTANT_ATTENUATION,0.8); glLightf(GL_LIGHT3,GL_LINEAR_ATTENUATION,0.5); glLightf( GL_LIGHT3, GL_QUADRATIC_ATTENUATION, 0.1 ) ;

Ms parmetros para las lucesAparte de las caractersticas que ya habamos mencionado en el artculo pasado, existen otras mas que tambin tienen cierta relevancia en cuanto a los efectos de iluminacin de escenas. Vamos a ver estas caractersticas hablando un poco de Fsica para tratar de entenderlas. Primero hablemos de la atenuacin con la distancia. Con esto nos estamos refiriendo a la atenuacin que sufre la luz a medida que se desplaza. Est claro que a ms lejos est un objeto de una fuente luminosa, menos iluminado resultar. Pues bien, esa es la idea!. Veamos la formula que presentamos en la Figura 1. Esta funcin sirve para atenuar la luz con la distancia, y como podemos ver involucra 3 parmetros (a, b y c).

Otras caractersticas adicionales que se aplican de manera similar a estas que vimos, las encontramos en lo que sera la definicin del cono de luz que forma cada una de nuestras fuentes de iluminacin. Veamos la Figura 2... en ella encontramos el anglicismo

Figura 2 Cut-Off, que se refiere a la lnea que corta la regin que resultar iluminada por nuestra luz (Tan sencillo que sera decirlo en Espaol!!), sin embargo el ambiente de los grficos est plagado de anglicismos que dicen mucho en pocas letras, y no nos queda ms remedio que vivir con eso por ahora. En fin, para definir el cono de nuestra luz usamos los siguientes parmetros: GL_SPOT_CUTOFF para definir el cono. En este parmetro lo que hacemos es definir un ngulo de abertura para el cono, con un valor que puede ir de los 0.0 a los 90.0 grados. Y en caso de que no nos interese definir un ngulo, usando un valor de 180 estaremos desactivando esta opcin. GL_SPOT_DIRECTION, el cual nos sirve para restringir la direccin de la luz emitida. Es un vector de tres valores reales que corresponden al vector direccional que indica hacia adonde apunta nuestro foco. Por defecto esa direccin es la de las Z's negativas. Y por ltimo GL_SPOT_EXPONENT, que regula la prdida de intensidad de la luz a medida que nos alejamos del centro del cono, algo similar a lo que habamos mencionado sobre la atenuacin con la distancia. Los valores que este parmetro puede tomar fluctan entre 0.0 y 128.0. Intuimos como se le indican estos valores a cada luz en OpenGL?

Figura 1 El primero de estos (a), se refiere a la atenuacin constante que sufre sin importar la distancia. Es el desgaste natural de la energa luminosa. En OpenGL la llamamos GL_CONSTANT_ATTENUATION y por defecto tiene el valor de 1.0 si este no se especifica. El segundo (b), es la atenuacin lineal, y la llamamos as porque es el parmetro que se multiplica linealmente por la distancia en nuestra formula. Lo cual nos da un factor que se incrementa linealmente a medida que aumenta la distancia. En OpenGL lo llamamos GL_LINEAR_ATTENUATION y por defecto es igual a 0. El tercero (c), es la atenuacin cuadrtica, y a sta la llamamos as porque a este parmetro lo multiplicamos por el cuadrado de la distancia a aplicar. Con esto obtenemos un valor an mayor que con la atenuacin lineal, y por lo mismo una atenuacin ms severa. En OpenGL hacemos referencia a este parmetro con GL_QUADRATIC_ATTENUATION que por defecto es igual a 0. Y ahora, de qu nos sirve saber esto?... Bien, pues como pueden darse cuenta, la funcin en realidad representa una fraccin de 1 sobre algo... Pues OpenGL reduce la intensidad de la luz que llega a un determinado lugar con esta fraccin, evidentemente esto de manera inversamente proporcional a la distancia a la que se encuentre dicho lugar. Para indicar estos parmetros de las luces a OpenGL usamos la ya conocida funcin glLightf(); a la que, como han de recordar, le pasamos tres argumentos, el primero es la luz que

Los materiales...No es lo mismo iluminar un brillante que un pedazo de madera, como tampoco es lo mismo iluminar un pedazo de metal que un trozo de tela, o de plstico. Esto porque existen materiales en el mundo real que son ms opacos que otros, y

42

Iluminacin con OpenGL (2)otros que por si mismos (debido al color, o al propio aplicarse al lado visible (Front), al no visible (Back) o a material) generan cierta luminosidad, por ejemplo los colores ambos. Aqu debemos tomar en cuenta que puede no fluorescentes. Y OpenGL nos permite definir materiales con todas Tabla 1 estas caractersticas, tomando const GLfloat GLenum face GLenum pname * params propiamente de principios fsicos GL_FRONT GL_DIFFUSE ( R, G, B, 1.0 ) todo lo que hemos estado GL_BACK GL_AMBIENT ( R, G, B, 1.0 ) mencionando. GL_FRONT_AND_BACK GL_AMBIENT_AND_DIFFUSE ( R, G, B, 1.0 ) A cada pedazo de la geometra que GL_EMISSION ( R, G, B, 1.0 ) compone nuestra escena podemos GL_SPECULAR ( R, G, B, 1.0 ) asignarle un material distinto, y as GL_SHININESS [ 0, 128 ] tambin poder representar objetos complejos compuestos de diversos materiales, como por ejemplo un piano que tenga las teclas interesarnos el c mo se vea la parte no visible de una cara blancas de marfil y los bemoles de bano (Disculpen, soy un si esta nunca se va a presentar al usuario, por ejemplo en un gran aficionado a la msica); ambos materiales respondern cubo cerrado cuyas caras interiores nunca se ven. En cuanto a de un modo distinto a una misma luz, y esa diferencia debe pname se especifica aqu cu l es la caracter stica que ser notoria si deseamos hacer una escena lo suficientemente vamos a definir en concreto. Las posibles son las que hemos realista. comentado para un material. De hecho son bastante obvias si Para un material se definen cinco caracter sticas miramos las constantes que podemos usar. Por ltimo fundamentales. Estos componentes son: *params, donde damos los valores concretos de la Reflexi n difusa (diffuse) o color de base que caracter stica. Son tres valores, de hecho tres n meros reflejar a el objeto si incidiera sobre l una luz pura reales que especifican un color RGB. Ese color define blanca, la mayor a de las veces esta denota el color del exactamente c mo debe verse el objeto que se renderice material que estamos definiendo. despu s en cuanto a color ambiente, difusi n, Reflexi n especular (specular), que se refiere a los componente especular, etc. "puntitos brillantes" de los objetos iluminados. Hay una excepci n en el caso de GL_SHININESS. Si usamos Reflexi n ambiental (ambient) , define como un objeto esta constante como segundo par metro, el tercero tendr pol gono determinado refleja la luz que no viene que ser un n mero entre 0 y 128 que controlar la directamente de una fuente luminosa, sino de la escena en concentraci n del brillo. Por defecto este valor vale 0. s . La misma funci n tiene tambi n las formas glMaterialf, Coeficiente de brillo o "shininess". Define la cantidad de glMateriali y glMaterialiv. No suelen usarse, por eso las versiones puntos luminosos y su concentraci n. Digamos que llamadas escalares (enteras), ya que s lo son tiles para variando este par metro podemos conseguir un objeto definir GL_SHININESS. m s o menos cercano al metal, por ejemplo. Los Valores t picos, son los usados por defecto, son de 0.8 Coeficiente de emisi n (emission) o color de la luz que para las tres componentes en GL_DIFFUSE, de 0.2 para emite el mismo objeto. Lo que les mencionaba hace un GL_AMBIENT y de 0.0 en GL_EMISSION y GL_SPECULAR. Por momento de la fosforescencia. supuesto tendremos que retocar estos valores hasta conseguir Las componentes ambiental y difusa son t picamente el efecto deseado, ya que si los dejamos como est n no nos iguales o muy semejantes. La componente especular suele ser gustar lo que veremos. gris o blanca. El brillo nos determinar el tama o del Por cierto que el cuarto valor, es decir el 1.0, se refiere al punto de m xima reflexi n de luz y esto nos permite valor del canal alfa del color RGB. Ya llegar m s obtener efectos muy variados y llamativos. adelante el momento de estudiar esto cuando hablemos de Se pueden especificar diferentes par metros en cuanto a transparencias. material para cada pol gono. Es una tarea ardua, pero l gicamente a m s variedad de comportamientos m s Al Ejemplo! real ser la escena. El funcionamiento es el normal en Veamos lo que nos muestra esta vez el Listado 1. Como OpenGL. Cada vez que se llama a la correspondiente ver n, lo que pretendemos hacer en este programa es funci n se activan esos valores que no cambiar n hasta mostrar c mo podemos hacer diferentes combinaciones de llamarla de nuevo con otros. Por tanto todo lo que se las caracter sticas que hemos mencionado, para obtener "renderice" (por decir un palabro, como dijeran en Espa a) variados materiales a partir de pr cticamente los mismos a partir de una llamada heredar esas caracter sticas. La valores. funci n es: glMaterialfv ( GLenum face, GLenum pname, const GLfloat En realidad, mucho de lo que mostramos en el ejemplo ya lo*params ) ;

Ahora echemos un vistazo a la Tabla 1. En ella se observan los valores que pueden adoptar los par metros de la funci n. En el caso de face tenemos tres posibilidades dependiendo de si la caracter stica en cuesti n debe

hab amos mencionado en art culos anteriores, as que nos centraremos en la parte donde definimos las caracter sticas de la luz, y el material a usar. Como ven, la mayor parte de estas caracter sticas las definimos como arreglos que representan vectores. Algunos de estos vectores 43

Iluminacin con OpenGL (2)Listado 1unit Unit1; interface uses Windows, Forms, OpenGL, Classes, ExtCtrls, Messages, Controls, StdCtrls,Graphics ,sysUtils, glut; type TMainForm = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); procedure FormResize(Sender: TObject); procedure Timer1Timer(Sender: TObject); private RC : HGLRC; Angle : Integer; procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; end; var MainForm: TMainForm; implementation uses Dialogs; {$R *.DFM} procedure TMainForm.FormCreate(Sender: TObject); begin RC:=CreateRenderingContext(Canvas.Handle,[opDoubleBuffered],32,0); end; procedure TMainForm.FormDestroy(Sender: TObject); begin DestroyRenderingContext(RC); end; procedure TMainForm.FormPaint(Sender: TObject); const ambient:Array[0..3] of GLfloat =(0.0, 0.0, 0.0, 1.0 ); //Luz ambiental diffuse:Array[0..3] of GLfloat=( 1.0, 1.0, 1.0, 1.0 ); //Luz Difusa specular:Array[0..3] of GLfloat=( 1.0, 1.0, 1.0, 1.0 ); //Luz Especular position:Array[0..3] of GLfloat=(0.0, 3.0, 2.0, 0.0 ); //Posicin de la luz no_mat:Array[0..3] of GLfloat=( 0.0, 0.0, 0.0, 1.0 ); //Material negro, o sin color... mat_ambient:Array[0..3] of GLfloat=( 0.7, 0.7, 0.7, 1.0 ); // Nuestro color de material ambiental... mat_ambient_color:Array[0..3] of GLfloat=(0.8, 0.8, 0.2, 1.0 );// Un color de material combinado... mat_diffuse:Array[0..3] of GLfloat=(0.1, 0.5, 0.8, 1.0); //Reflexin difusa... mat_specular:Array[0..3] of GLfloat=( 1.0, 1.0, 1.0, 1.0 ); //Reflexin Especular... no_shininess:GLfloat=0.0; //Sin brillo... low_shininess:GLfloat=5.0; //Bajo Brillo... high_shininess:GLfloat=100.0; //Alto Brillo... mat_emission:Array[0..3] of GLfloat=(0.3, 0.2, 0.2, 0.0); //Luz emitida por el material... begin ActivateRenderingContext(Canvas.Handle,RC); // Hacer el contexto dibujable

44

Iluminacin con OpenGL (2)glClearColor(0.0, 0.1, 0.1, 0.0); // Color de Fondo... glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Borra el Fondo y DepthBuffer glMatrixMode(GL_MODELVIEW); glLoadIdentity; glulookat(0,0,20,0,0,19,0,1,0); //Definimos el puerto de visin.... glEnable(GL_DEPTH_TEST); //Habilitamos la prueba en profundidad... glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, @diffuse); glLightfv(GL_LIGHT0, GL_POSITION, @position); //Se habilitan las luces... glEnable(GL_LIGHTING); glenable(GL_LIGHT0); //Se dibujan las esferas... //* Esfera en primer rengln, primera columna //* solo reflexin difusa ; sin brillo glPushMatrix(); glTranslatef (-3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, @no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en primer rengln, segunda columna solo reflexin difusa y especular ; bajo en brillo glPushMatrix(); glTranslatef (-1.25, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, @low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); Esfera en primer rengln, tercera columna solo reflexin difusa y especular ; alto en brillo glPushMatrix(); glTranslatef (1.25, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, @high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en primer rengln, Cuarta columna solo reflexin difusa y emisin sin brillo //Se definen //Las Cacartersticas de la luz

//* //*

45

Iluminacin con OpenGL (2)glPushMatrix(); glTranslatef (3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, @no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @mat_emission); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Segundo rengln, Primera columna solo reflexin de ambiente y difusa, sin brillo glPushMatrix(); glTranslatef (-3.75, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, @no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Segundo rengln, Segunda columna Reflexin de ambiente, difusa y especular, bajo en brillo glPushMatrix(); glTranslatef (-1.25, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, @low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Segundo rengln, Tercera columna Reflexin de ambiente, difusa y especular, alto en brillo glPushMatrix(); glTranslatef (1.25, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, @high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Segundo rengln, Cuarta columna Reflexin de ambiente y difusa; con emisin, sin brillo glPushMatrix(); glTranslatef (3.75, 0.0, 0.0);

46

Iluminacin con OpenGL (2)glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, @no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @mat_emission); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Tercer rengln, Primera columna Reflexin de ambiente y difusa, sin brillo... glPushMatrix(); glTranslatef (-3.75, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, @no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Tercer rengln, Segunda columna Reflexin de color del ambiente, difusa y especular, bajo en brillo glPushMatrix(); glTranslatef (-1.25, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, @low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Tercer rengln, Tercera columna Reflexin del color del ambiente, difusa y especular; alto en brillo glPushMatrix(); glTranslatef (1.25, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, @high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @no_mat); glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //* //* Esfera en Tercer rengln, Cuarta columna Reflexin del color del ambiente y difusa; con emisin; sin brillo glPushMatrix(); glTranslatef (3.75, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, @mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, @mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, @no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, @no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, @mat_emission);

47

Iluminacin con OpenGL (2)glrotatef(360-4*angle,1,1,1); glutSolidSphere(1.0,10,10); glPopMatrix(); //Se terminan las esferas SwapBuffers(Canvas.Handle); //Copiar el Back Buffer en el canvas del formulario... DeactivateRenderingContext; //Libera el contexto... end; procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char); begin// Se acaba el demo ... if Key = #27 then Application.Terminate; end; procedure TMainForm.FormResize(Sender: TObject); begin // Cuando se cambia de tamao hay que actualizar el puerto de visin... wglMakeCurrent(Canvas.handle,RC); // Otra manera de hacer el contexto dibujable glViewport(0,0,Width,Height); // Especificar un puerto de visin.... glMatrixMode(GL_PROJECTION); // Activar matriz de proyeccin... glLoadIdentity; // Poner estado inicial... gluPerspective(35,Width/Height,1,100); // Especificar Perspectiva ... wglMakeCurrent(0,0); // Otra manera de liberar el contexto... Refresh; // Redibujar la escena ... end; procedure TMainForm.Timer1Timer(Sender: TObject); begin // Se hace la animacin..... Inc(Angle,1); if Angle >= 360 then Angle:=0; Repaint; end; procedure TMainForm.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin //Para borrar el fondo, y evitar el parpadeo ... Message.Result:=1; end; end.

sirven para definir colores, y otros coordenadas. Por ejemplo, para el caso de los arreglos que definen nuestra luz, vemos que usamos una luz que no tiene efecto sobre el ambiente, y que es completamente blanca (pura como la nieve!), que est colocada en las coordenadas: (0.0,3.0,2.0). Para el caso del material tenemos m s arreglos, tenemos un arreglo con valores de 0, para determinar cuando no usaremos color para definir alguna caracterstica del material (ambiente, difusa, especular, brillo), y del mismo modo para el brillo tenemos tres posibles valores, que puede ser un alto coeficiente de brillo, o uno bajo, o de plano ningn brillo. Bien, nuestro demo lo construiremos a partir de esferas usando un procedimiento de la librera GLUT: glutSolidSphere() al cual se le pasan como parmetros el radio que tendr esa esfera, as como el nmero de meridianos y paralelos que la definirn. Por el mismo hecho de que estamos definiendo esferas, solo usamos GL_FRONT para las caractersticas, ya que al ser stas objetos cerrados, nunca veremos la cara posterior de los polgonos que las forman.

Dibujaremos las esferas situndolas en 3 lneas y 4 columnas, ordenadas de acuerdo a las caractersticas que presenta el material usado para construirla. As tenemos que en la primera y la cuarta columna no usamos ning n coeficiente de brillo, en la segunda usamos un brillo alto, y en la tercera un brillo bajo. Y as vamos haciendo combinaciones. Si se fijan un poco vern por ustedes mismos cuales han sido los criterios que hemos aplicado a cada una de las filas y columnas en nuestra escena de esferas. En algunas usamos valores de emisin, en otras no; y en el caso de la tercera fila usamos un color de material un poco diferente. Observen como cada vez que vamos a dibujar, debemos definir de nuevo todas las caractersticas del material a utilizar, porque se conservan las anteriores, Recuerdan lo de la mquina de estados que mencionbamos?. Y hasta aqu llegamos por ahora con la iluminacin, en lo que se refiere a sus conceptos bsicos. Ms adelante, en posteriores artculos, y cuando ya estemos ms avanzados hablaremos de conceptos que tienen que ver tambin con el

48

Iluminacin con OpenGL (2)tratamiento de la luz, pero que se estudian desde otros puntos de vista, tales como las superficies que reflejan imgenes (espejos), los cuerpos transparentes, y los efectos de niebla, entre otros. Como ven, an quedan muchos temas por estudiar. Hasta Pronto.

49

Texturas con OpenGL(I)Principios bsicos de texturizaci n.

En esta ocasi n tocaremos el tema de las texturas. Este es un tema bastante interesante ya que aunque de primera vista pareciera sencilla la idea de poner una imagen sobre una cara de una figura, en realidad es algo que involucra muchas cuestiones adicionales. Las texturas vienen a darle un mayor realismo a las escenas que elaboramos no solo con OpenGL, sino con cualquier motor de gr ficos. Estas nos pueden ser tiles para representar de manera sencilla la rugosidad la finura de una superficie. Bien dicen que Una imagen dice ms que mil palabras; pues esto tambi n es muy aplicable a n propiamente a las cuestiones de los gr ficos. Y en cuanto a la aplicabilidad suele ser tambi n muy Figura 1.- La textura original. variada. Pueden servir por ejemplo para representar el nivel de altitud de una coordenada sobre un terreno, o simplemente para definir el estampado que presenta una pared en una habitaci n. El caso es que las texturas son algo indispensable a la hora de generar gr ficos de alto realismo. La texturizaci n es t picamente usada para proveer detalles de color a superficies intrincadas. Por ejemplo, supongamos que deseamos modelar un mueble de madera barnizada, es necesario dibujar sobre las partes de ese mueble para que realmente parezca de madera. Aunque la texturizaci n tambi n puede ayudarnos a solucionar algunos otros problemas que resultar an menos obvios, y que estudiaremos a su tiempo. Figura 2.La misma textura rotada 45 grados.

a las figuras que defin amos en la matriz de modelado les pod amos aplicar escalamientos y rotaciones, a las texturas tambi n podemos rotarlas y escalarlas respecto a cualquier coordenada, siempre teniendo en cuenta, claro, que estamos trabajando con superficies, y que las im genes que manejaremos (por lo menos en este nmero) son de 2 dimensiones. Veamos las Figuras 1, 2 y 3 donde aparecen ejemplos de transformaciones lineales aplicadas a una textura. OpenGL soporta im genes de texturas de una y dos dimensiones (1D y Una matriz especial para las texturas 2D) y cuyas medidas OpenGL soporta dos t cnicas de texturizado: Por sean una potencia de Manipulaci n del Color de la Superficie y por Mapeado dos. Por ejemplo: del Ambiente. La primera de estas se refiere a manipular i m g e n e s directamente los colores de las superficies de las caras a bidimensionales de afectar, sin tomar en cuenta nada m s que el color de la 64 X 64 p xeles, de textura a aplicar. Y la segunda consiste en involucrar los 256 X 128, etc. En colores de los materiales de los objetos a texturizar, as a l g u n a s como las luces y las normales obteniendo una textura implementaciones de combinada con el ambiente. OpenGL se han Hasta ahora ya hab amos estudiado las matrices de extendido y se modelado y proyecci n, mencionando cada una de sus soportan texturas de 3 Figura 3.caracter sticas y para qu nos sirven. Pues es el turno de y La misma textura despu s de haber 4 dimensiones hablar de la matriz de texturas. tambi n (3D y 4D), sido escalada linealmente. Esta matriz, como las anteriores, nos va a servir para pero por ahora definir transformaciones lineales; en este caso para las empezaremos por lo texturas que utilicemos en nuestra aplicaci n. Al igual que

50

Texturas con OpenGL(I)sencillito. tanto la superficie como la textura tengan el mismo tamao, en cuyo caso la relacin resulta ser lineal (1 Pxel = 1 Texel), o que la Superficie sea de un tamao mayor a la imagen, o bien que sea la imagen la que resulte ser de un tamao mayor. Para solucionar este tipo de problemas OpenGL implementa 2 tipos de filtros. A estos se les llama: Filtros de Minificacin y de Magnificacin. El Filtro de Minificacin se ocupa cuando muchos texeles se mapean a un mismo pxel (Texel < Pxel), y el filtro de Magnificacin se ocupa cuando muchos pxeles del despliegue estn mapeados por un mismo texel (Texel > Pxel). No es tan complicado, O s?, Viendo la Figura 4 nos enteraremos mejor. El ms simple de estos filtros es conocido como "Point Sampling" (Muestreo de puntos). En OpenGL denominamos a este filtro con la sentencia GL_NEAREST.

Un concepto nuevo: Los TexelesUn Texel, vendra siendo como el elemento relativo a un pxel en un objeto Canvas, solo que aplicado a la lgica de una textura. Es decir, se refiere a cada uno de los pxeles de la imagen que forman nuestra textura, (o al menos as podemos nosotros entenderlo) Algo que debemos hacer primeramente es mapear la superficie que vamos a texturizar. Es decir, determinar las esquinas y las orillas de nuestra textura en la cara. Para que nos quede un poco ms claro, supongamos que deseamos texturizar un cuadrado, bien, pues tenemos que decirle a nuestro motor de grficos que esquina de nuestra textura es la que debe aplicar a qu vrtice de nuestro cuadro, as podemos texturizar con la imagen invertida, en cualquier orientacin. Cada vez que una primitiva de las que ya hemos estudiado como un cuadro, un triangulo, un polgono, etc, es mandada a dibujar texturizada se calcula una coordenada de textura para cada uno de los fragmentos de pxeles de esa primitiva. Esa coordenada de textura es usada para buscar un valor entre los texeles para ser aplicado al mapa de textura correspondiente. Las coordenadas del mapa de textura fluctan entre un rango de 0 a 1. O sea que siempre tratamos al rectngulo de las imgenes como un rea que va desde [0,0] hasta [1,1]; aunque tambin se pueden utilizar valores decimales para determinar una coordenada intermedia dentro de nuestro mapa de textura.

Figura 5.- Los criterios de los filtros. Este consiste en encontrar simplemente aquel Texel que resulte ser el ms cercano a la coordenada de la textura, este es muy rpido, pero obviamente no el de mejores resultados. Sin embargo si es utilizado, porque funciona para aquellos casos en los que la velocidad es m s importante, pero son ms recomendables aquellos filtros que utilizan la interpolacin de texeles. Para magnificacin OpenGL 1.0 soporta interpolacin lineal entre cuatro valores de Texeles. Algunas otras versiones soportan adems una filtracin bicbica, la cual consiste en hacer una suma ponderada de los valores de un arreglo de Texeles de 4 X 4 (a esta tcnica de filtracin tambin se le conoce con el nombre de Filter4) Para definir la interpolacin lineal en OpenGL utilizaremos la sentencia GL_LINEAR. Para minificacin OpenGL 1.0 soporta varios tipos de Mipmapping. EL mipmapping consiste en tomar diferentes ejemplos de la imagen (a cada nivel de estos

La Minificacin y la Magnificacin...Al momento de aplicarle una textura a una superficie, puede darse el caso de que esta superficie no sea del mismo tamao en pxeles y texeles que nuestra imagen. Aqu pueden sucederse tres casos (Ver Figura 4), Que

Figura 4.- Los 3 casos posibles de filtrado.

51

Texturas con OpenGL(I)se le llama mipmap) y a cada uno de estos aplicarle una interpolacin distinta para despus hacer una interpolacin entre cada uno de estos mismos ejemplos, obteniendo as una mejor definicin para el mapeado final. El ms usado de estos filtros (y tambin el ms caro computacionalmente hablando) es el de mipmapping trilineal, el cual consiste en tomar 4 ejemplos de cada uno de los 2 niveles de mipmaps ms cercanos y entonces interpolar los dos conjuntos de ejemplos. OpenGL no provee de comandos para la construccin de mipmaps, pero la librera GLU nos proporciona algunas rutinas simples para generar mipmaps usando un filtro simple. En el ejemplo mostraremos como se construyen mipmaps con esta librera. Pero profundizaremos en su utilizacin en el siguiente nmero. En la Figura 5 se muestra grfic