Vous êtes sur la page 1sur 11

DAIE: Desenvolupament dAplicacions Informtiques a lEnginyeria EUETIB - UPC

Tutorial 5. Volando sobre el terreno


Al finalizar este tutorial se obtiene un programa que permite crear un terreno un mapa en tres dimensiones y volar sobre l movindonos a voluntad y con la posibilidad de mirar hacia cualquier lado. 1. 2. 3. 4. Creacin de la tierra Creacin del cielo Aprendiendo a volar Vista de guila

Copyright (c) 2005 Samir Kanaan. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections and no Back-Cover Texts. The most recent version of this document can be obtained from the following web address: http://webon.euetib.upc.es/samir/daie.html.

1. Creacin de la tierra
El primer elemento en esta escena ser el propio terreno, que como veremos utiliza un mapa de alturas para elevar montaas o quedarse en llanura. Para visualizar el terreno en nuestra escena, en primer lugar hay que crear una escena vaca, con una cmara con sus valores por defecto y conectada al visor. Una vez hecho eso, hay que aadir a la escena un objeto de tipo terreno: SceneObjects>Add Objects>Mesh Objects>TerrainRenderer. De momento no se ver nada, aunque el editor de la escena debera aparecer as:

La representacin de terreno en GLScene tiene algunas caractersticas que conviene conocer antes de seguir adelante: Aunque en GLScene la x es horizontal, la y vertical y la z sale de la pantalla, el TerrainRenderer se extiende en el plano xy y las alturas se representan en z, luego hay que girar toda la escena para verla adecuadamente. La representacin del terreno se hace en tiempo de ejecucin, as que mientras estamos editando la escena no veremos gran cosa (una superficie plana, como mucho). Las alturas del terreno deben provenir de un control GLBitmapHDS, que se encuentra en la pestaa GLScene Utils. En este control cargaremos un mapa de bits que representar la altura (blanco altura mxima, negro mnima).

Ejemplo de mapa de alturas Por lo tanto, para que el terreno contenga alguna informacin y podamos empezar a trabajar, es necesario seguir los siguientes pasos: Crear un control GLBitmapHDS. Decirle al TerrainRenderer que tome la informacin de alturas del GLBitmapHDS mediante la propiedad HeightDataSource del TerrainRenderer. Cargar, en el GLBitmapHDS, la imagen del mapa de alturas (adjunta con el programa de ejemplo) mediante su propiedad Picture. Aun as, seguiremos sin ver nada; sin embargo, si ejecutamos el programa, podremos ver algo como esto:

Aunque no lo parezca, estamos viendo ya el terreno, lo que pasa es que la cmara est en (0, 0, 0) y con direccin z=-1, as que segn lo que hemos explicado de la situacin del terreno (en el plano xy), para conseguir una vista hacia el horizonte hay que hacer dos cosas: elevar la cmara, que ahora significa aumentar la z de la cmara por ejemplo hasta 10; por otra parte, hay que hacer que la cmara no

mire hacia abajo como ahora, sino hacia delante, luego su direccin debera ser, por ejemplo y=1. La nueva vista es la siguiente:

que, la verdad, no parece mucho mejor que antes. El problema es que estamos justo detrs de una montaa, y por eso lo vemos casi todo negro. Se trata de un problema de escala: la propiedad Scale del TerrainRenderer controla las dimensiones del terreno en cada eje; no nos interesa que sea tan alto como ancho, luego conviene aumentar la extensin y disminuir la altura, por ejemplo poniendo (4, 4, 0,25). De esta forma ya queda ms claro que estamos tras una montaa:

Ahora que ya estamos ms o menos bien situados, vamos a intentar cambiar el color del terreno, pues si vemos todo en negro es porque no hay ninguna luz y estamos viendo slo la silueta de las montaas. Esto se puede resolver de dos maneras: aadiendo una luz, o bien asociando una textura al terreno, y como la textura queda iluminada independientemente de la luz, empezaremos a ver algo. Para elegir una textura, como en cualquier otro objeto, terreno > Material > Texture, propiedades Image y Disabled. El resultado es el siguiente:

2. Creacin del cielo


Para mejorar estticamente el programa anterior, un elemento imprescindible es el cielo, que adems sirve de referencia para nuestro futuro movimiento sobre el terreno. Adems es un componente muy fcil de utilizar: slo hay que ir al editor de la escena, hacer click derecho sobre Scene Objects, e ir a Add Objects>Environment Objects>SkyDome (cpula celeste). La ventana del editor debera quedar as:

Si ejecutamos el programa, efectivamente veremos el cielo... pero demasiado cielo:

Este problema tiene su origen en que el cielo se pinta sin tener en cuenta qu objetos hay delante o detrs, y como el la ventana del editor el cielo aparece antes que el terreno, primero se pinta el terreno y luego el cielo encima, tapndolo parcialmente. La solucin es sencilla: se coge el GLSkyDome1 y se arrastra sobre el elemento Scene Objects, anteponindolo as al terreno y consiguiendo por tanto el resultado que esperbamos en un principio:

La configuracin del editor de la escena debera ser la siguiente:

Por cierto, el cielo est formado por una serie de bandas (propiedad Bands), y si tocamos en los puntos suspensivos se abre una ventanita que nos muestra todas las bandas del cielo (por defecto una blanca en el horizonte y la azul arriba):

Si seleccionamos una banda podemos cambiar su extensin y su color:

Tambin es posible aadir otras bandas o cambiar su extensin (en grados). Adems, el SkyDome tiene la opcin de aadir sol o estrellas, aunque no las utilizaremos aqu.

3. Aprendiendo a volar
Una vez hemos conseguido ver el terreno, vamos a aadir a nuestro programa la capacidad de movernos por la escena que hemos creado como si pudiramos volar por el terreno que hemos definido. El objetivo es que mediante las flechas del teclado se pueda mover la cmara, dndonos la sensacin de movernos por la escena. Habitualmente, en Delphi esperamos un evento OnKeyDown para recoger las pulsaciones de teclas; sin embargo, ese tipo de eventos slo se activan una vez cada vez que tocamos la tecla. Si queremos avanzar simplemente manteniendo presionada la flecha, hay que recurrir a otro mtodo: comprobar peridicamente qu teclas hay presionadas, y segn eso realizar el movimiento correspondiente. Dentro de GLScene hay un control muy parecido al Timer de Delphi, el TGLCadencer, cuya misin es generar un evento OnProgress cada cierto tiempo; la diferencia respecto al Timer es que el Cadencer no genera el evento cada tantos milisegundos, sino que lo genera siempre que el fotograma anterior ha terminado y por tanto el ordenador est preparado para generar un nuevo fotograma, aprovechando as al mximo la velocidad del ordenador.

De momento vamos a utilizarlo para que la cmara avance sola; para ello colocamos el Cadencer en el formulario, lo asociamos a la escena (propiedad Scene) y hacemos doble click en l para que aparezca el evento OnProgress, y en l escribimos lo siguiente:

procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double); begin camara.Position.y:=camara.Position.y+10*deltaTime; end;

En los eventos OnProgress del Cadencer, el parmetro deltaTime indica el tiempo transcurrido desde el anterior evento, y en base a l podemos calcular, por ejemplo, cunto deberamos movernos en este paso de la animacin. En el ejemplo, el 10 sera la velocidad, y al multiplicarla por el tiempo nos da el espacio a recorrer por la cmara. Al ejecutar el programa se ve que, efectivamente, nos movemos por el terreno, pero con algunas limitaciones: No podemos controlar ese movimiento. Nos metemos dentro de las montaas, vamos en lnea recta. El terreno ms alejado no se ve. Los dos primeros problemas los resolveremos ahora; el tercero, en el apartado siguiente. Aunque podramos aadir controles manualmente para controlar la cmara, hay una forma mucho ms sencilla y potente de mover objetos, sean cmaras o no: el control TGLNavigator.

Para utilizarlo slo hay que colocarlo en el formulario, asociarlo mediante la propiedad MovingObject a la cmara y sustituir el cdigo del OnProgress del Cadencer por el siguiente, para que las teclas de flecha sirvan para decirle al Navigator que mueva la cmara, y para que la tecla retroceder pgina haga subir la cmara y la de avanzar pgina la haga bajar:
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double); var velocidad:real; begin velocidad:=20; if IsKeyDown(VK_UP) then GLNavigator1.MoveForward(velocidad*deltaTime); if IsKeyDown(VK_DOWN) then GLNavigator1.MoveForward(-velocidad*deltaTime); if IsKeyDown(VK_RIGHT) then GLNavigator1.StrafeHorizontal(velocidad*deltaTime); if IsKeyDown(VK_LEFT) then GLNavigator1.StrafeHorizontal(-velocidad*deltaTime); if IsKeyDown(VK_PRIOR) then GLNavigator1.StrafeVertical(velocidad*deltaTime); if IsKeyDown(VK_NEXT) then GLNavigator1.StrafeVertical(-velocidad*deltaTime); end;

Para poder utilizar la funcin IsKeyDown, que dice si una tecla determinada est pulsada o no, hay que aadir la unidad Keyboard a la lista de Uses al principio del cdigo. De esta forma, podemos navegar utilizando las teclas y movernos sobre el terreno a voluntad; incluso se pueden combinar dos teclas y conseguir un movimiento en diagonal. Pero todava hay un problema: nos metemos dentro de las montaas, ya que el movimiento de la cmara no tiene en cuenta la altura del terreno. Para evitar este problema simplemente hay que consultar en cada momento a qu altura est el terreno en ese punto y, si la cmara est ms baja, ponerla al nivel del terreno (o un poco ms alta). La funcin InterpolatedHeight del TerrainRenderer nos da la altura de un punto dado, en nuestro caso la posicin de la cmara. Hay que dejar un margen de 5 unidades para que en ningn momento se vea el terreno por debajo y d la sensaci n de que nos movemos por encima.
altura:=terreno.InterpolatedHeight(camara.Position.AsVector); if camara.Position.Z<altura+5 then camara.Position.Z:=altura+5;

Este cdigo debe ir a continuacin del anterior, en el OnProgress del Cadencer; obviamente, hay que declarar la variable altura, que ser de tipo real. Con estas modificaciones, ya nos podemos mover libremente por todo el terreno. Slo nos falta poder mirar a donde queramos y mejorar algunos aspectos visuales.

4. Vista de guila
La forma ms intuitiva de mirar dentro de una aplicacin 3D como la que estamos creando es utilizar el ratn para girar la cabeza libremente. Para conseguir esto fcilmente, vamos a utilizar el control GLUserInterface (est en GLSceneUtils, al lado del GLNavigator).

Para utilizarlo, hay que asociarlo al Navigator que ya tenamos (propiedades GLNavigator y GlVertNavigator), ponerle una velocidad adecuada (MouseSpeed, por ejemplo 25) y hacer que capture los movimientos del ratn mediante la orden siguiente:

GLUserInterface1.MouseLookActivate;

que deber ir en el FormCreate para que el navegador capture el ratn (si ejecutis ahora veris que el ratn no se ve, pero tampoco hace nada), y aadir las siguientes rdenes al final del OnProgress del Cadencer para que se actualice la vista de la cmara con los moviemientos del ratn:
GLUserInterface1.MouseUpdate; GLUserInterface1.MouseLook;

Si ejecutis el programa observaris que, si todo es correcto, funciona, pero hay un par de problemas: no hay forma de acabar el programa (s la hay: Alt+F4 acaba cualquier programa, aunque ahora lo mejoraremos) y cuando nos movemos bastante la pantalla queda girada y es difcil resituarse:

Para evitar este ltimo problema hay que poner a True la propiedad UseVirtualUp del Navigator, que hace que siempre tenga presente dnde est la cabeza del sujeto y por tanto no gire de esa forma extraa (tambin quita cierta libertad, en otro tipo de aplicaciones puede interesar la libertad completa de movimientos). Por otra parte, para facilitar la salida del programa se suele hacer que la tecla Escape tenga este objetivo, para lo que hay que aadir esta lnea de cdigo al principio del OnProgress del Cadencer:
if IsKeyDown(VK_ESCAPE) then Close;

Quedan algunos problemas estticos por resolver. En primer lugar, el hecho de que slo se vea el terreno ms prximo; eso es debido a que la cmara s lo muestra los objetos que estn a una distancia determinada (propiedad DepthOfView), que por defecto vale 100, y que deberamos cambiar a, por ejemplo, 1000 para que nos muestre terreno ms lejano:

10

Este parmetro no afecta al cielo, que se visualiza siempre, independientemente de lo lejos que est. Por otra parte est la molesta franja gris que se ve al fondo, entre el cielo y el terreno, y que aparece sobre todo al elevarnos y mirar a lo lejos (pues tan lejos no se visualiza el terreno). Una posible solucin sera hacer que la cmara tuviera un campo de visin infinito, pero eso ralentizara muchsimo la ejecucin del programa. Hay dos soluciones estticas a este problema (que al fin y al cabo tambin es esttico): Hacer que la primera franja del cielo empiece en -10 (y que acabe, por ejemplo, en 25 para que se siga viendo una zona blanca; la siguiente franja deber empezar en 25 tambin, claro). Lo que estamos viendo es el fondo del visor; si cambiamos Visor>Buffer>BackgroundColor y ponemos blanco, tambin parecer que sigue el cielo. Lo mejor es combinar ambas soluciones, aunque tambin es posible limitar la altura mxima de la cmara de forma parecida a lo que hemos hecho para evitar que se hunda en el terreno para evitar que suba mucho y se vea la consabida franja.

11

Vous aimerez peut-être aussi