Vous êtes sur la page 1sur 308

2

Carlos Gonzlez Morcillo Javier A. Albusac Jimnez Csar Mora Castro Sergio Fernndez Durn

Ttulo: Desarrollo de 1ideo$uegos: 2rogramaci,n Gr+ica Autores: Carlos Gonzlez Morcillo! Javier A. Albusac Jimnez! Csar Mora Castro! Sergio Fernndez Durn ISBN: 345/56/757/60(7/7 8de la Edicin Fsica, a la venta en www.bubok.es9 Publica: :ubo; 8Edicin Fsica9 <ibro1irtual.org 8Edicin electrnica9 Edita: David 1alle$o Fernndez " Carlos Gonzlez Morcillo Diseo: Carlos Gonzlez Morcillo
=ste libro +ue com uesto con <a>e? a artir de una lantilla de Carlos Gonzlez Morcillo! Sergio Garc@a Mondara" " David 1illa Alises. <a ortada " las entradillas +ueron diseAadas con GBM2! :lender! Bn;Sca e " C enC++ice.

Creative Commons License: Usted es libre de co iar! distribuir " comunicar #blicamente la obra! ba$o las condiciones siguientes: %. &econocimiento. Debe reconocer los crditos de la obra de la manera es eci'cada or el autor o el licenciador. (. )o comercial. )o uede utilizar esta obra ara 'nes comerciales. *. Sin obras derivadas. )o se uede alterar! trans+ormar o generar una obra derivada a artir de esta obra. Ms in+ormaci,n en: -tt :..creativecommons.org.licenses.b"/nc/nd.*.0.

Carlos Gonzlez (2007, Doctor Europeo en Informtica, Universidad de Castilla-La Manc a! es "rofesor #itular de Universidad e imparte docencia en la Escuela de Informtica de Ciudad $eal (UCLM! en asi%naturas relacionadas con Informtica &rfica, '(ntesis de Ima%en $ealista ) 'istemas *perativos desde 2002+ ,ctualmente, su actividad investi%adora %ira en torno a los 'istemas Multi-,%ente, el $enderin% Distri-uido ) la $ealidad ,umentada+

Javier Albusac (200., Doctor Europeo en Informtica, Universidad de Castilla-La Manc a! es "rofesor ,)udante Doctor e imparte docencia en la Escuela de In%enier(a Minera e Industrial de ,lmad/n (EIMI,! en las asi%naturas de Informtica, *fimtica ,plicada a la In%enier(a ) 'istemas de Comunicaci0n en Edificios desde 2007+ ,ctualmente, su actividad investi%adora %ira en torno a la 1i%ilancia Inteli%ente, $o-0tica M0vil ) ,prendi2a3e ,utomtico+

Csar Mora (2045, Master en Computer 'cience por la Universidad de Minnesota, 2044 In%eniero en Informtica, Universidad de Casilla-La Manc a!+ 'us temas de inter/s estn relacionados con la Informtica &rfica, la 1isi0n ,rtificial ) la $ealidad ,umentada+

Sergio Fernndez (6inali2ando estudios de &rado en In%enier(a Informtica, Universidad de Castilla-La Manc a!+ "articip0 en la primera edici0n del Curso de E7perto en Desarrollo de 1ideo3ue%os (UCLM!+ ,ctualmente tra-a3a como desarrollador i*' ) $ails en tico Estudio+ Desarrollador de aplicaciones para i*' de forma independiente en vsoftworks+

Prefacio

Con ms de 40.000 descargas y 4TB servidos desde Junio de 2012, el material docente y el cdigo fuente de los ejemplos del Curso de Experto en Desarrollo de Videojuegos, impartido en la Escuela Superior de Informtica de Ciudad Real de la Universidad de Castilla-La Mancha, se ha convertido en un referente internacional en la formacin de desarrolladores de videojuegos. Puedes obtener ms informacin sobre el curso, as como los resultados de los trabajos creados por los alumnos de la 1a y la 2a edicin, en la web del mismo: http://www.cedv.es. La versin electrnica de este libro (y del resto de libros de la coleccin) puede descargarse desde la web anterior. El libro fsico puede adquirirse desde la pgina web de la editorial online Bubok en http://www.bubok.es.

Sobre este libro...


Este libro forma parte de una coleccin de 4 volmenes, con un perl principalmente tcnico, dedicados al Desarrollo de Videojuegos : 1. Arquitectura del Motor. En este primer libro se estudian los aspectos esenciales del diseo de un motor de videojuegos, as como las tcnicas bsicas de programacin y patrones de diseo. 2. Programacin Grca. El segundo libro de la coleccin se centra en algoritmos y tcnicas de representacin grca, as como en optimizaciones y simulacin fsica. 3. Tcnicas Avanzadas. En este tercer volumen se recogen ciertos aspectos avanzados, como estructuras de datos especcas, tcnicas de validacin y pruebas. 4. Desarrollo de Componentes. El ltimo libro est dedicado a ciertos componentes especcos del motor, como la Inteligencia Articial, Networking, Sonido y Multimedia o tcnicas avanzadas de Interaccin.

Requisitos previos
Este libro tiene un pblico objetivo con un perl principalmente tcnico. Al igual que el curso, est orientado a la capacitacin de profesionales de la programacin de videojuegos. De esta forma, este libro no est orientado para un pblico de perl artstico (modeladores, animadores, msicos, etc.) en el mbito de los videojuegos. Se asume que el lector es capaz de desarrollar programas de nivel medio en C y C++. Aunque se describen algunos aspectos clave de C++ a modo de resumen, es recomendable refrescar los conceptos bsicos con alguno de los libros recogidos en la bibliografa del curso. De igual modo, se asume que el lector tiene conocimientos de estructuras de datos y algoritmia. El libro est orientado principalmente para titulados o estudiantes de ltimos cursos de Ingeniera en Informtica.

Programas y cdigo fuente


El cdigo de los ejemplos puede descargarse en la siguiente pgina web: http://www.cedv.es. Salvo que se especique explcitamente otra licencia, todos los ejemplos del libro se distribuyen bajo GPLv3.

Agradecimientos
Los autores del libro quieren agradecer en primer lugar a los alumnos de la 1a y 2a edicin del Curso de Experto en Desarrollo de Videojuegos por su participacin en el mismo y el excelente ambiente en las clases, las cuestiones planteadas y la pasin demostrada en el desarrollo de todos los trabajos. Los autores tambin agradecen el soporte del personal de administracin y servicios de la Escuela Superior de Informtica de Ciudad Real, a la propia Escuela y el Departamento de Tecnologas y Sistema de Informacin de la Universidad de Castilla-La Mancha. De igual modo, se quiere reejar especialmente el agradecimiento a las 8 empresas que ofertarn prcticas en la 3a edicin del curso: Devilish Games (Alicante), Dolores Entertainment (Barcelona), from the bench (Alicante), Iberlynx Mobile Solutions (Ciudad Real), Kitmaker (Palma), playspace (Palma), totemcat - Materia Works (Madrid) y Zuinqstudio (Sevilla). Este agradecimiento se extiende a los portales y blogs del mundo de los videojuegos que han facilitado la difusin de este material, destacando a Meristation, Eurogamer, Genbeta Dev, Vidaextra y HardGame2. Finalmente, los autores desean agradecer su participacin a los colaboradores del curso: Indra Software Labs, DocPath, la asociacin de desarrolladores de videojuegos Stratos y Libro Virtual.

Resumen

El objetivo de este mdulo titulado Programacin Grca del Curso de Experto en Desarrollo de Videojuegos es cubrir los aspectos esenciales relativos al desarrollo de un motor grco interactivo. En este contexto, el presente mdulo cubre aspectos esenciales y bsicos relativos a los fundamentos del desarrollo de la parte grca, como por ejemplo el pipeline grco, como elemento fundamental de la arquitectura de un motor de juegos, las bases matemticas, las APIs de programacin grca, el uso de materiales y texturas, la iluminacin o los sistemas de partculas. As mismo, el presente mdulo tambin discute aspectos relativos a la exportacin e importacin de datos, haciendo especial hincapi en los formatos existentes para tratar con informacin multimedia. Finalmente, se pone de maniesto la importancia del uso de elementos directamente conectados con el motor grco, como la simulacin fsica, con el objetivo de dotar de ms realismo en el comportamiento de los objetos y actores que intervienen en el juego.

ndice general

1.

Fundamentos de Grcos Tridimensionales . . . . . . . . 1.1. 1.2. Introduccin . . . . . . . . . . . . . . . . . . . . El Pipeline Grco . . . . . . . . . . . . . . . . . .

1 1 4 5 5 8 9

1.2.1. Etapa de Aplicacin . . . . . . . . . . . . . . . . 1.2.2. Etapa de Geometra . . . . . . . . . . . . . . . . 1.2.3. Etapa Rasterizacin . . . . . . . . . . . . . . . . 1.2.4. Proyeccin en Perspectiva . . . . . . . . . . . . . 1.3.

Implementacin del Pipeline en GPU . . . . . . . . . . 10

1.3.1. Vertex Shader . . . . . . . . . . . . . . . . . . 12 1.3.2. Geometry Shader . . . . . . . . . . . . . . . . . 12 1.3.3. Pixel Shader . . . . . . . . . . . . . . . . . . . 12 1.4. 1.5. 1.6. Arquitectura del motor grco . . . . . . . . . . . . . 13 Casos de Estudio . . . . . . . . . . . . . . . . . . 14 Introduccin a OGRE . . . . . . . . . . . . . . . . 15

1.6.1. Arquitectura General . . . . . . . . . . . . . . . 18 1.6.2. Instalacin . . . . . . . . . . . . . . . . . . . 23 1.7. 2. Hola Mundo en OGRE . . . . . . . . . . . . . . . . 24

Matemticas para Videojuegos . . . . . . . . . . . . . . 29 2.1. Puntos, Vectores y Coordenadas . . . . . . . . . . . . 29 2.1.1. Puntos . . . . . . . . . . . . . . . . . . . . . 30 2.1.2. Vectores . . . . . . . . . . . . . . . . . . . . 31 2.2. Transformaciones Geomtricas . . . . . . . . . . . . 34 2.2.1. Representacin Matricial . . . . . . . . . . . . . . 35
III

2.2.2. Transformaciones Inversas . . . . . . . . . . . . . 37 2.2.3. Composicin. . . . . . . . . . . . . . . . . . . 38 2.3. 2.4. Perspectiva: Representacin Matricial . . . . . . . . . . 39 Cuaternios . . . . . . . . . . . . . . . . . . . . . 41

2.4.1. Suma y Multiplicacin . . . . . . . . . . . . . . . 43 2.4.2. Inversa . . . . . . . . . . . . . . . . . . . . . 43 2.4.3. Rotacin empleando Cuaternios . . . . . . . . . . . 44 2.5. 2.6. 3. Interpolacin Lineal y Esfrica . . . . . . . . . . . . . 44 El Mdulo Math en OGRE . . . . . . . . . . . . . . . 45

Grafos de Escena . . . . . . . . . . . . . . . . . . . . 49 3.1. 3.2. Justicacin . . . . . . . . . . . . . . . . . . . . 49 El Gestor de Escenas de OGRE . . . . . . . . . . . . . 52 3.1.1. Operaciones a Nivel de Nodo . . . . . . . . . . . . 50 3.2.1. Creacin de Objetos. . . . . . . . . . . . . . . . 52 3.2.2. Transformaciones 3D . . . . . . . . . . . . . . . 54 3.2.3. Espacios de transformacin . . . . . . . . . . . . 56 . . . . . . . . . 59

4.

Recursos Grcos y Sistema de Archivos 4.1.

Formatos de Especicacin . . . . . . . . . . . . . . 59

4.1.1. Introduccin. . . . . . . . . . . . . . . . . . . 59 4.1.2. Recursos de grcos 3D: formatos y requerimientos de almacenamiento . . . . . . . . . . . . . . . . . . 61 4.1.3. Casos de Estudio . . . . . . . . . . . . . . . . . 67 4.2. Exportacin y Adaptacin de Contenidos. . . . . . . . . 79 4.2.1. Instalacin del exportador de Ogre en Blender . . . . . 81 4.2.2. Creacin de un modelo en Blender . . . . . . . . . . 81 4.2.3. Aplicacin de texturas mediante UV Mapping . . . . . 81 4.2.4. Exportacin del objeto en formato Ogre XML . . . . . . 85 4.2.5. Carga del objeto en una aplicacin Ogre 4.3. 4.4. Procesamiento de Recursos Grcos 4.3.1. Ejemplo de uso . . . . . . . 87 . . . . . . . . . . 89

. . . . . . . . . . . . . . . . . 92

Gestin de Recursos y Escena . . . . . . . . . . . . . 94

4.4.1. Recursos empaquetados . . . . . . . . . . . . . . 95 4.4.2. Gestin del ratn . . . . . . . . . . . . . . . . . 95 4.4.3. Geometra Esttica . . . . . . . . . . . . . . . . 96

4.4.4. Queries. . . . . . . . . . . . . . . . . . . . . 98 4.4.5. Mscaras . . . . . . . . . . . . . . . . . . . . 101 5. APIS de Grcos 3D. . . . . . . . . . . . . . . . . . . 103 5.1. 5.2. Introduccin . . . . . . . . . . . . . . . . . . . . 103 Modelo Conceptual . . . . . . . . . . . . . . . . . 105

5.2.1. Cambio de Estado . . . . . . . . . . . . . . . . 105 5.2.2. Dibujar Primitivas . . . . . . . . . . . . . . . . 106 5.3. Pipeline de OpenGL . . . . . . . . . . . . . . . . . 107 . . . . . . . . . . 107 5.3.1. Transformacin de Visualizacin 5.3.3. Transformacin de Proyeccin

5.3.2. Transformacin de Modelado . . . . . . . . . . . . 108 . . . . . . . . . . . 109 5.3.4. Matrices . . . . . . . . . . . . . . . . . . . . 109 5.3.5. Dos ejemplos de transformaciones jerrquicas . . . . . 111 5.4. 6. Ejercicios Propuestos . . . . . . . . . . . . . . . . 114

Gestin Manual OGRE 3D . . . . . . . . . . . . . . . . 115 6.1. Inicializacin Manual . . . . . . . . . . . . . . . . 115 6.1.1. Inicializacin . . . . . . . . . . . . . . . . . . 116

6.1.2. Carga de Recursos . . . . . . . . . . . . . . . . 119 6.1.3. FrameListener . . . . . . . . . . . . . . . . . . 119 6.2. 6.3. 6.4. 7. Uso de OIS . . . . . . . . . . . . . . . . . . . . . 121 Creacin manual de Entidades. . . . . . . . . . . . . 125 Uso de Overlays . . . . . . . . . . . . . . . . . . . 126 6.2.1. Uso de Teclado y Ratn . . . . . . . . . . . . . . 122

Interaccin y Widgets . . . . . . . . . . . . . . . . . . 131 7.1. Interfaces de usuario en videojuegos . . . . . . . . . . 131 . . . . . . . . . . . . . . . . . . . . . 134 7.1.1. Men 7.2.

7.1.2. HUD . . . . . . . . . . . . . . . . . . . . . . 135 Introduccin CEGUI . . . . . . . . . . . . . . . . . 135 . . . . . . . . . . . . . . . . . . 137 . . . . . . . . . 139 7.2.1. Instalacin . . . . . . . . . . . . . . . . . . . 136 7.2.2. Inicializacin 7.2.3. El Sistema de Dimensin Unicado 7.3.

7.2.4. Deteccin de eventos de entrada. . . . . . . . . . . 140 Primera aplicacin. . . . . . . . . . . . . . . . . . 142

7.4. 7.5. 7.6. 7.7. 7.8.

Tipos de Widgets . . . . . . . . . . . . . . . . . . 145 Layouts . . . . . . . . . . . . . . . . . . . . . . 146 Ejemplo de interfaz . . . . . . . . . . . . . . . . . 147 Editores de layouts grcos . . . . . . . . . . . . . . 149 Scripts en detalle . . . . . . . . . . . . . . . . . . 150

7.8.1. Scheme . . . . . . . . . . . . . . . . . . . . . 150 7.8.2. Font . . . . . . . . . . . . . . . . . . . . . . 151 7.8.3. Imageset . . . . . . . . . . . . . . . . . . . . 152 7.8.4. LookNFeel . . . . . . . . . . . . . . . . . . . . 152 7.9. Cmara de Ogre en un Window . . . . . . . . . . . . 152 7.10. Formateo de texto . . . . . . . . . . . . . . . . . . 155 7.10.1.Introduccin. . . . . . . . . . . . . . . . . . . 156 7.10.2.Color. . . . . . . . . . . . . . . . . . . . . . 156 7.10.3.Formato . . . . . . . . . . . . . . . . . . . . 156 7.10.4.Insertar imgenes 7.10.6. Padding . . . . . . . . . . . . . . . . 157 7.10.5.Alineamiento vertical . . . . . . . . . . . . . . . 157 . . . . . . . . . . . . . . . . . . . . 157 7.10.7.Ejemplo de texto formateado . . . . . . . . . . . . 158 7.11. Caractersticas avanzadas. . . . . . . . . . . . . . . 159 8. Materiales y Texturas . . . . . . . . . . . . . . . . . . 161 8.1. 8.2. 8.3. 8.4. Introduccin . . . . . . . . . . . . . . . . . . . . 161 Modelos de Sombreado . . . . . . . . . . . . . . . . 163 Mapeado de Texturas Materiales en Ogre . . . . . . . . . . . . . . . . 164 . . . . . . . . . . . . . . . . . 166

8.4.1. Composicin. . . . . . . . . . . . . . . . . . . 167 8.4.2. Ejemplo de Materiales . . . . . . . . . . . . . . . 167 8.5. 8.6. 8.7. Mapeado UV en Blender . . . . . . . . . . . . . . . 170 Ejemplos de Materiales en Ogre . . . . . . . . . . . . 175 Render a Textura . . . . . . . . . . . . . . . . . . 178 8.5.1. Costuras . . . . . . . . . . . . . . . . . . . . 174

8.7.1. Texture Listener . . . . . . . . . . . . . . . . . 181 8.7.2. Espejo (Mirror) . . . . . . . . . . . . . . . . . . 182 9. Iluminacin . . . . . . . . . . . . . . . . . . . . . . 185 9.1. Introduccin . . . . . . . . . . . . . . . . . . . . 185

9.2. 9.3.

Tipos de Fuentes de Luz . . . . . . . . . . . . . . . 186 Sombras Estticas Vs Dinmicas . . . . . . . . . . . . 187 . . . . . . . . . 188 . . . . . . . . . . . 191

9.3.1. Sombras basadas en Stencil Buffer 9.3.2. Sombras basadas en Texturas 9.4. 9.5. 9.6. 9.7.

Ejemplo de uso . . . . . . . . . . . . . . . . . . . 192 Mapas de Iluminacin . . . . . . . . . . . . . . . . 194 Ambient Occlusion . . . . . . . . . . . . . . . . . 196 Radiosidad . . . . . . . . . . . . . . . . . . . . . 197 . . . . . . . . 203

10. Exportacin y Uso de Datos de Intercambio

10.1. Introduccin . . . . . . . . . . . . . . . . . . . . 203 11. Animacin. . . . . . . . . . . . . . . . . . . . . . . 211 11.1. Introduccin . . . . . . . . . . . . . . . . . . . . 211 11.1.1.Animacin Bsica 11.2. Animacin en Ogre . . . . . . . . . . . . . . . . 212 11.1.2.Animacin de Alto Nivel . . . . . . . . . . . . . . 213 . . . . . . . . . . . . . . . . . 215 11.2.1.Animacin Keyframe . . . . . . . . . . . . . . . 215 11.2.2.Controladores . . . . . . . . . . . . . . . . . . 216 11.3. Exportacin desde Blender . . . . . . . . . . . . . . 216 11.4. Mezclado de animaciones . . . . . . . . . . . . . . . 221 12. Simulacin Fsica . . . . . . . . . . . . . . . . . . . 227

12.1. Introduccin . . . . . . . . . . . . . . . . . . . . 227 12.1.1.Algunos Motores de Simulacin . . . . . . . . . . . 228 12.1.2.Aspectos destacables . . . . . . . . . . . . . . . 229 12.1.3.Conceptos Bsicos . . . . . . . . . . . . . . . . 231 12.2. Sistema de Deteccin de Colisiones . . . . . . . . . . . 232 12.2.1.Formas de Colisin . . . . . . . . . . . . . . . . 232 12.2.2.Optimizaciones. . . . . . . . . . . . . . . . . . 235 12.2.3.Preguntando al sistema... . . . . . . . . . . . . . 236 12.3. Dinmica del Cuerpo Rgido . . . . . . . . . . . . . . 237 12.4. Restricciones . . . . . . . . . . . . . . . . . . . . 238 12.5. Introduccin a Bullet . . . . . . . . . . . . . . . . 239 12.5.1.Pipeline de Fsicas de Cuerpo Rgido . . . . . . . . . 240 12.5.2.Hola Mundo en Bullet . . . . . . . . . . . . . . . 242

12.6. Integracin manual en Ogre . . . . . . . . . . . . . . 250 12.7. Hola Mundo en OgreBullet . . . . . . . . . . . . . . 253 12.8. RayQueries . . . . . . . . . . . . . . . . . . . . 257 12.9. TriangleMeshCollisionShape. . . . . . . . . . . . . . 260 12.10. Deteccin de colisiones . . . . . . . . . . . . . . . . 261 12.11. Restriccin de Vehculo . . . . . . . . . . . . . . . . 263 12.12. Determinismo . . . . . . . . . . . . . . . . . . . 267 . . . . . . . . . . . . . . . . 269 12.13. Escala de los Objetos

12.14. Serializacin . . . . . . . . . . . . . . . . . . . . 270 A. Introduccin a OgreFramework . . . . . . . . . . . . . . 271 Introduccin . . . . . . . . . . . . . . . . . . . . 271 Basic OgreFramework . . . . . . . . . . . . . . . . 272 Advanced OgreFramework . . . . . . . . . . . . . . 274

A.1. A.2. A.3.

A.2.1. Arquitectura. . . . . . . . . . . . . . . . . . . 273 A.3.1. Sistema de Estados . . . . . . . . . . . . . . . . 276 A.3.2. Arquitectura. . . . . . . . . . . . . . . . . . . 276 A.4. SdkTrays . . . . . . . . . . . . . . . . . . . . . 280 A.4.1. Introduccin. . . . . . . . . . . . . . . . . . . 280 A.4.2. Requisitos. . . . . . . . . . . . . . . . . . . . 280 A.4.3. SdkTrayManager . . . . . . . . . . . . . . . . . 280 A.4.4. Widgets. . . . . . . . . . . . . . . . . . . . . 280 A.4.5. SdkTrayListener . . . . . . . . . . . . . . . . . 281 A.4.6. Skins A.5. A.6. btOgre . . . . . . . . . . . . . . . . . . . . . 281 A.4.7. OgreBites . . . . . . . . . . . . . . . . . . . . 281 . . . . . . . . . . . . . . . . . . . . . . 282 . . . . . . . . . . . . . . . . . . . . 284 Referencias

Listado de acrnimos

API AVI B-R EP BIK BMP BRDF CAD CCD CEGUI CMYK CPU CSG DOM DVD GIMP GLUT GLU GNU GPL GPU IEEE IPO JPG MP3 MPEG OGRE OIS

Application Program Interface Audio Video Interleave Boundary Representation BINK Video BitMaP Bidirectional Reactance Distribution Function Computer Aided Design Charge-Coupled Device Crazy Eddies GUI Cyan Magenta Yellow Key Central Processing Unit Constructive Solid Geometry Document Object Model Digital Video Disc
GNU Image Manipulation Program

OpenGL Utility Toolkit OpenGL Utility


GNU is Not Unix

General Public License Graphic Processing Unit Institute of Electrical and Electronics Engineers InterPOlation curve Joint Photographic Experts Group
MPEG-2 Audio Layer III

Moving Picture Experts Group Object-Oriented Graphics Rendering Engine Object Oriented Input System
IX

PNG RGBA RGB RTT SAX SDL SLERP SRU SVG TGA TIFF TIF UCLM WAV XML

Portable Network Graphics Red Green Blue Alpha Red Green Blue Render To Texture Simple API for XML Simple Directmedia Layer spherical linear interpolation Sistema de Referencia Universal Scalable Vector Graphics Truevision Graphics Adapter Tagged Image File Format
TIFF

Universidad de Castilla-La Mancha WAVeform eXtensible Markup Language

Captulo

Fundamentos de Grcos Tridimensionales


Carlos Gonzlez Morcillo

no de los aspectos que ms llaman la atencin en los videojuegos actuales son sus impactantes grcos 3D. En este primer captulo introduciremos los conceptos bsicos asociados al pipeline en grcos 3D. Se estudiarn las diferentes etapas de transformacin de la geometra hasta su despliegue nal en coordenadas de pantalla. En la segunda parte del captulo estudiaremos algunas de las capacidades bsicas del motor grco de videojuegos y veremos los primeros ejemplos bsicos de uso de Ogre.

1.1.
An ms rpido!!
Si cada frame tarda en desplegarse ms de 40ms, no conseguiremos el mnimo de 25 fps (frames per second ) establecido como estndar en cine. En videojuegos, la frecuencia recomendable mnima es de unos 50 fps.

Introduccin

Desde el punto de vista del usuario, un videojuego puede denirse como una aplicacin software que responde a una serie de eventos, redibujando la escena y generando una serie de respuestas adicionales (sonido en los altavoces, vibraciones en dispositivos de control, etc...). El redibujado de esta escena debe realizarse lo ms rpidamente posible. La capa de aplicacin en el despliegue grco es una de las actividades que ms ciclos de CPU consumen (incluso, como veremos en la seccin 1.3, con el apoyo de las modernas GPUs Graphics Processing Unit existentes en el mercado). Habitualmente el motor grco trabaja con geometra descrita mediante mallas triangulares. Las tcnicas empleadas para optimizar el despliegue de esta geometra, junto con las propiedades de materia1

[2]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

les, texturas e iluminacin, varan dependiendo del tipo de videojuego que se est desarrollando. Por ejemplo, en un simulador de vuelo, el tratamiento que debe darse de la geometra distante (respecto de la posicin de la cmara virtual) debe ser diferente que la empleada para optimizar la visualizacin de interiores en un videojuego de primera persona.

Uno de los errores habituales en videojuegos amateur es la falta de comunicacin clara entre programadores y diseadores. El desarrollador debe especicar claramente las capacidades soportadas por el motor grco al equipo de modeladores, animadores y equipo artstico en general. Esta informacin debe comprender tanto las tcnicas de despliegue soportadas, como el nmero de polgonos disponibles para el personaje principal, enemigos, fondos, etc...

A un alto nivel de abstraccin podemos ver el proceso de render como el encargado de convertir la descripcin de una escena tridimensional en una imagen bidimensional. En los primeros aos de estudio de esta disciplina, la investigacin se centr en cmo resolver problemas relacionados con la deteccin de supercies visibles, sombreado bsico, etc. Segn se encontraban soluciones a estos problemas, se continu el estudio de algoritmos ms precisos que simularan el comportamiento de la luz de una forma ms precisa. En esencia, el proceso de rendering de una escena 3D requiere los siguientes elementos: Supercies. La geometra de los objetos que forman la escena debe ser denida empleando alguna representacin matemtica, para su posterior procesamiento por parte del ordenador. Cmara. La situacin del visor debe ser denida mediante un par (posicin, rotacin) en el espacio 3D. El plano de imagen de esta cmara virtual denir el resultado del proceso de rendering. Como se muestra en la Figura 1.1, para imgenes generadas en perspectiva, el volumen de visualizacin dene una pirmide truncada que selecciona los objetos que sern representados en la escena. Esta pirmide se denomina Frustum. Fuentes de luz. Las fuentes de luz emiten rayos que interactan con las supercies e impactarn en el plano de imagen. Dependiendo del modo de simulacin de estos impactos de luz (de la resolucin de la denominada ecuacin de render ), tendremos diferentes mtodos de rendering. Propiedades de las supercies. En este apartado se incluyen las propiedades de materiales y texturas que describen el modelo de rebote de los fotones sobre las supercies. Uno de los principales objetivos en sntesis de imagen es el realismo. En general, segn el mtodo empleado para la resolucin de la
Tiempo de cmputo
En sntesis de imagen realista (como por ejemplo, las tcnicas de rendering empleadas en pelculas de animacin) el clculo de un solo fotograma de la animacin puede requerir desde varias horas hasta das, empleando computadores de altas prestaciones. Figura 1.1: Descripcin general del proceso de rendering.

1.1. Introduccin

[3]

Plano de Imagen

Lista de despliegue

Plano de Imagen

Pipeline Raster

Punto de Vista

Punto de Vista

Pipeline Hardware (Interactivo)


Mapeado hacia delante

Mapeado Inverso

RayCasting

Figura 1.2: Diferencias entre las tcnicas de despliegue interactivas (mtodos basados en ScanLine ) y realistas (mtodos basados en RayCasting). En el Pipeline Hardware, la seleccin del pxel ms cercano relativo a cada tringulo se realiza directamente en Hardware, empleando informacin de los fragmentos (ver Seccin 1.2).

ecuacin de render tendremos diferentes niveles de realismo (y diferentes tiempos de cmputo asociados). El principal problema en grcos en tiempo real es que las imgenes deben ser generadas muy rpidamente. Eso signica, como hemos visto anteriormente, que el motor grco dispone de menos de 40 ms para generar cada imagen. Habitualmente este tiempo es incluso menor, ya que es necesario reservar tiempo de CPU para otras tareas como el clculo de la Inteligencia Articial, simulacin fsica, sonido... Los primeros mtodos de sombreado de supercies propuestos por Gouraud y Phong no realizaban ninguna simulacin fsica de la reexin de la luz, calculando nicamente las contribuciones locales de iluminacin. Estos modelos tienen en cuenta la posicin de la luz, el observador y el vector normal de la supercie. Pese a su falta de realismo, la facilidad de su cmputo hace que estas aproximaciones sigan siendo ampliamente utilizadas en el desarrollo de videojuegos.
RayTracing
El algoritmo original del RayCasting de Appel, fue el precursor del mtodo de RayTracing (Trazado de Rayos) de Whitted de 1980. El mtodo de RayTracing sirvi de base para los principales mtodos de sntesis de imagen hiperrealistas que se emplean en la actualidad (Metrpolis, Path Tracing, etc...).

En 1968 Arthur Appel describi el primer mtodo para generar imgenes por computador lanzando rayos desde el punto de vista del observador. En este trabajo, generaba la imagen resultado en un plotter donde dibujaba punto a punto el resultado del proceso de render. La idea general del mtodo de RayCasting es lanzar rayos desde el plano de imagen, uno por cada pxel, y encontrar el punto de interseccin ms cercano con los objetos de la escena. La principal ventaja de este mtodo frente a los mtodos de tipo scanline que emplean zbuffer es que es posible generar de forma consistente la imagen que represente el mundo 3D, ya que cualquier objeto que pueda ser descrito mediante una ecuacin puede ser representado de forma correcta mediante RayCasting. Como puede verse en la Figura 1.2, existen diferencias importantes entre el mtodo de despliegue que implementan las tarjetas aceleradoras 3D (y en general los motores de visualizacin para aplicaciones in-

[4]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

teractivas) y el mtodo de RayCasting. El pipeline grco de aplicaciones interactivas (como veremos en la seccin 1.2) puede describirse de forma general como el que, a partir de una lista de objetos geomtricos a representar y, tras aplicar la serie de transformaciones geomtricas sobre los objetos, la vista y la perspectiva, obtienen una imagen raster dependiente del dispositivo de visualizacin. En este enfoque, las primitivas se ordenan segn la posicin de la cmara y slo las visibles sern dibujadas. Por el contrario, en mtodos de sntesis de imagen realista (como la aproximacin inicial de RayCasting) calcula los rayos que pasan por cada pxel de la imagen y recorre la lista de objetos, calculando la interseccin (si hay alguna) con el objeto ms cercano. Una vez obtenido el punto de interseccin, se evala (empleando un modelo de iluminacin) el valor de sombreado correspondiente a ese pxel.

App Etapa de Geometra Rasterizacin

1.2.

El Pipeline Grco

Aplicacin
Coord. Modelo (Locales)

Para obtener una imagen de una escena 3D denida en el Sistema de Referencia Universal, necesitamos denir un sistema de referencia de coordenadas para los parmetros de visualizacin (tambin denominados parmetros de cmara ). Este sistema de referencia nos denir el plano de proyeccin, que sera el equivalente de la zona de la cmara sobre la que se registrar la imagen1 . De este modo se transeren los objetos al sistema de coordenadas de visualizacin y nalmente se proyectan sobre el plano de visualizacin (ver Figura 1.4). El proceso de visualizar una escena en 3D mediante grcos por computador es similar al que se realiza cuando se toma una fotografa real. En primer lugar hay que situar el trpode con la cmara en un lugar del espacio, eligiendo as una posicin de visualizacin. A continuacin, rotamos la cmara eligiendo si la fotografa la tomaremos en vertical o en apaisado, y apuntando al motivo que queremos fotograar. Finalmente, cuando disparamos la fotografa, slo una pequea parte del mundo queda representado en la imagen 2D nal (el resto de elementos son recortados y no aparecen en la imagen). La Figura 1.3 muestra los pasos generales del Pipeline asociado a la transformacin de una escena 3D hasta su representacin nal en el dispositivo de visualizacin (tpicamente una pantalla con una determinada resolucin). El Pipeline est dividido en etapas funcionales. Al igual que ocurre en los pipeline de fabricacin industrial, algunas de estas etapas se realizan en paralelo y otras secuencialmente. Idealmente, si dividimos un proceso en n etapas se incrementar la velocidad del proceso en ese factor n. As, la velocidad de la cadena viene determinada por el tiempo requerido por la etapa ms lenta.

Transf Modelado
Coord. Universales

Transf Visualizacin
Coord. Visualizacin

Vertex Shader Transf Proyeccin


Coord. Normalizadas

Transf Recorte
Coord. Recortadas

Transf Pantalla
Coord. antalla

Config. Tri!n"ulo Recorrido Tri!n". Pixel Shader Fusin (Mer"in")

Figura 1.3: Pipeline general en grcos 3D.


1 En el mundo fsico, la pelcula en antiguas cmaras analgicas, o el sensor de imagen de las cmaras digitales.

1.2. El Pipeline Grco

[5]

Y Sistema de Coordenadas Local (Objeto) Z

Sistema de Coordenadas Universal (SRU) Z X

Sistema de Coordenadas de Visualizacin Y

Z X

Y X

lano de visualizacin

Figura 1.4: Sistema de coordenadas de visualizacin y su relacin con otros sistemas de coordenadas de la escena.

Como seala Akenine-Mler [3], el pipeline interactivo se divide en tres etapas conceptuales de Aplicacin, Geometra y Rasterizacin (ver Figura 1.3). A continuacin estudiaremos estas etapas.

1.2.1. Etapa de Aplicacin


La etapa de aplicacin se ejecuta en la CPU. Actualmente la mayora de las CPUs son multincleo, por lo que el diseo de esta aplicacin se realiza mediante diferentes hilos de ejecucin en paralelo. Habitualmente en esta etapa se ejecutan tareas asociadas al clculo de la posicin de los modelos 3D mediante simulaciones fsicas, deteccin de colisiones, gestin de la entrada del usuario (teclado, ratn, joystick...). De igual modo, el uso de estructuras de datos de alto nivel para la aceleracin del despliegue (reduciendo el nmero de polgonos que se envan a la GPU) se implementan en la etapa de aplicacin.

1.2.2. Etapa de Geometra


En su tortuoso viaje hasta la pantalla, cada objeto 3D se transforma en diferentes sistemas de coordenadas. Originalmente, como se muestra en la Figura 1.4, un objeto tiene su propio Sistema de Coordenadas Local que nos denen las Coordenadas de Modelo, por lo que desde su punto de vista no est transformado. A los vrtices de cada modelo se le aplican la denominada Transformacin de Modelado para posicionarlo y orientarlo respecto del Sistema de Coordenadas Universal, obteniendo as las denominadas Coordenadas Universales o Coordenadas del Mundo.

[6]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

Z Y X
Transformacin de Visualizacin

Esquema Superior: Representacin en espacio 3D. Esquema Inferior: Vista de planta desde eje Y del SRU.

X Z

Transformacin de Visualizacin

X Z

Figura 1.5: El usuario especica la posicin de la cmara (izquierda) que se transforma, junto con los objetos de la escena, para posicionarlos a partir del origen del SRU y mirando en la direccin negativa del eje Z. El rea sombreada de la cmara se corresponde con el volumen de visualizacin de la misma (slo los objetos que estn contenidos en esa pirmide sern nalmente representados).

1.2. El Pipeline Grco

[7]

Instancias
Gracias a la separacin entre Coordenadas de Modelo y Transformacin de Modelado podemos tener diferentes instancias de un mismo modelo para construir una escena a las que aplicamos diferentes transformaciones. Por ejemplo, para construir un templo romano tendramos un nico objeto de columna y varias instancias de la columna a las que hemos aplicado diferentes traslaciones.

Como este sistema de coordenadas es nico, tras aplicar la transformacin de modelado a cada objeto, ahora todas las coordenadas estarn expresadas en el mismo espacio. La posicin y orientacin de la cmara nos determinar qu objetos aparecern en la imagen nal. Esta cmara tendr igualmente unas coordenadas universales. El propsito de la Transformacin de Visualizacin es posicionar la cmara en el origen del SRU, apuntando en la direccin negativa del eje Z y el eje Y hacia arriba. Obtenemos de este modo las Coordenadas de Visualizacin o Coordenadas en Espacio Cmara (ver Figura 1.5). Habitualmente el pipeline contiene una etapa adicional intermedia que se denomina Vertex Shader Sombreado de Vrtice que consiste en obtener la representacin del material del objeto modelando las transformaciones en las fuentes de luz, utilizando los vectores normales a los puntos de la supercie, informacin de color, etc. Es conveniente en muchas ocasiones transformar las posiciones de estos elementos (fuentes de luz, cmara, ...) a otro espacio (como Coordenadas de Modelo ) para realizar los clculos. La Transformacin de Proyeccin convierte el volumen de visualizacin en un cubo unitario (ver Seccin 1.2.4). Este volumen de visualizacin se dene mediante planos de recorte 3D y dene todos los elementos que sern visualizados. En la gura 1.5 se representa mediante el volumen sombreado. Existen multitud de mtodos de proyeccin, aunque como veremos ms adelante, los ms empleados son la ortogrca (o paralela) y la perspectiva. En la seccin 1.2.4 estudiaremos cmo se realiza la proyeccin en perspectiva de un modo simplicado. Cuando veamos en el captulo 2, determinaremos la expresin mediante la que los objetos de la escena se proyectan en un volumen simple (el cubo unitario ) antes de proceder al recorte y su posterior rasterizacin. Tras la proyeccin, el volumen de visualizacin se transforma en Coordenadas Normalizadas (obteniendo el cubo unitario ), donde los modelos son proyectados de 3D a 2D. La coordenada Z se guarda habitualmente en un buffer de profundidad llamado Z-Buffer. nicamente los objetos que estn dentro del volumen de visualizacin deben ser generados en la imagen nal. Los objetos que estn totalmente dentro del volumen de visualizacin sern copiados ntegramente a la siguiente etapa del pipeline. Sin embargo, aquellos que estn parcialmente incluidas necesitan ser recortadas, generando nuevos vrtices en el lmite del recorte. Esta operacin de Transformacin de Recorte se realiza automticamente por el hardware de la tarjeta grca. En la Figura 1.6 se muestra un ejemplo simplicado de recorte. Finalmente la Transformacin de Pantalla toma como entrada las coordenadas de la etapa anterior y produce las denominadas Coordenadas de Pantalla, que ajustan las coordenadas x e y del cubo unitario a las dimensiones de ventana nales.

X Z

Vrtices Nuevos

X Z
Figura 1.6: Los objetos que intersecan con los lmites del cubo unitario (arriba) son recortados, aadiendo nuevos vrtices. Los objetos que estn totalmente dentro del cubo unitario se pasan directamente a la siguiente etapa. Los objetos que estn totalmente fuera del cubo unitario son descartados.

[8]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

1.2.3. Etapa Rasterizacin


A partir de los vrtices proyectados (en Coordenadas de Pantalla ) y la informacin asociada a su sombreado obtenidas de la etapa anterior, la etapa de rasterizacin se encarga de calcular los colores nales que se asignarn a los pxeles de los objetos. Esta etapa de rasterizacin se divide normalmente en las siguientes etapas funciones para lograr mayor paralelismo. En la primera etapa del pipeline llamada Conguracin de Tringulos (Triangle Setup), se calculan las coordenadas 2D que denen el contorno de cada tringulo (el primer y ltimo punto de cada vrtice). Esta informacin es utilizada en la siguiente etapa (y en la interpolacin), y normalmente se implementa directamente en hardware dedicado. A continuacin, en la etapa del Recorrido de Tringulo (Triangle Traversal ) se generan fragmentos para la parte de cada pxel que pertenece al tringulo. El recorrido del tringulo se basa por tanto en encontrar los pxeles que forman parte del tringulo, y se denomina Triangle Traversal (o Scan Conversion ). El fragmento se calcula interpolando la informacin de los tres vrtices denidos en la etapa de Conguracin de Tringulos y contiene informacin calculada sobre la profundidad desde la cmara y el sombreado (obtenida en la etapa de geometra a nivel de todo el tringulo). La informacin interpolada de la etapa anterior se utiliza en el Pixel Shader (Sombreado de Pxel ) para aplicar el sombreado a nivel de pxel. Esta etapa habitualmente se ejecuta en ncleos de la GPU programables, y permite implementaciones propias por parte del usuario. En esta etapa se aplican las texturas empleando diversos mtodos de proyeccin (ver Figura 1.7). Finalmente en la etapa de Fusin (Merging) se almacena la informacin del color de cada pxel en un array de colores denominado Color Buffer. Para ello, se combina el resultado de los fragmentos que son visibles de la etapa de Sombreado de Pxel. La visibilidad se suele resolver en la mayora de los casos mediante un buffer de profundidad Z-Buffer, empleando la informacin que almacenan los fragmentos.

Config. Tringulos (Tr. Setup)

Recorrido Tringulos (Scan Conv.)

Sombreado

de Pxel (P. Shading)


Figura 1.7: Representacin del resultado de las principales etapas del Pipeline de Rasterizacin.

El Z-Buffer es un buffer ampliamente empleado en grcos por computador. Tiene el mismo tamao en pxeles que el buffer de color, pero almacena la menor distancia para cada pxel a todos los fragmentos de la escena. Habitualmente se representa como una imagen en escala de grises, y asocia valores ms cercanos a blanco a distancias menores.

1.2. El Pipeline Grco

[9]

1.2.4. Proyeccin en Perspectiva


En grcos por computador es posible elegir entre diferentes modelos de proyeccin de los objetos sobre el plano de visualizacin. Un modo muy utilizado en aplicaciones de CAD es la proyeccin de los objetos empleando lneas paralelas sobre el plano de proyeccin, mediante la denominada proyeccin paralela. En este modo de proyeccin se conservan las proporciones relativas entre objetos, independientemente de su distancia. Mediante la proyeccin en perspectiva se proyectan los puntos hasta el plano de visualizacin empleando trayectorias convergentes en un punto. Esto hace que los objetos situados ms distantes del plano de visualizacin aparezcan ms pequeos en la imagen. Las escenas generadas utilizando este modelo de proyeccin son ms realistas, ya que sta es la manera en que el ojo humano y las cmaras fsicas forman imgenes.
Perspectiva
La mayora de los juegos 3D se basan en el uso de cmaras de proyeccin en perspectiva. Estudiaremos con ms detalle este tipo de modelos de proyeccin en el captulo 2.

En la proyeccin en perspectiva, las lneas paralelas convergen en un punto, de forma que los objetos ms cercanos se muestran de un tamao mayor que los lejanos. Desde el 500aC, los griegos estudiaron el fenmeno que ocurra cuando la luz pasaba a travs de pequeas aberturas. La primera descripcin de una cmara estenopeica se atribuye al atrnomo y matemtico holands Gemma Frisius que en 1545 public la primera descripcin de una cmara oscura en la observacin de un eclipse solar (ver Figura 1.8). En las cmaras esteneopeicas la luz pasa a travs de un pequeo agujero para formar la imagen en la pelcula fotosensible, que aparece invertida. Para que la imagen sea ntida, la abertura debe ser muy pequea. Siguiendo la misma idea y desplazando el plano de proyeccin delante del origen, tenemos el modelo general proyeccin en perspectiva. Consideraremos en el resto de la seccin que ya se ha realizado la transformacin de visualizacin alineando la cmara y los objetos de la escena mirando en direccin al eje negativo Z , que el eje Y est apuntando hacia arriba y el eje X positivo a la derecha (como se muestra en la Figura 1.5).

Figura 1.8: Descripcin de la primera cmara estenopeica (pinhole camera o camera obscura ) por Gemma Frisius.

En la Figura 1.9 se muestra un ejemplo de proyeccin simple, en la que los vrtices de los objetos del mundo se proyectan sobre un plano innito situado en z = d (con d > 0). Suponiendo que la transformacin de visualizacin se ha realizado, proyectamos un punto p sobre el plano de proyeccin, obteniendo un punto p = (p x , py , d). Empleando tringulos semejantes (ver Figura 1.9 derecha), obtenemos las siguientes coordenadas: d p x = px pz p x = d px pz (1.1)

[10]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

Y
pz p' P'z = -d d p' p

X Z Z

p'x

px

Figura 1.9: Modelo de proyeccin en perspectiva simple. El plano de proyeccin innito est denido en z = d, de forma que el punto p se proyecta sobre p .

De igual forma obtenemos la coordenada p y = d py /pz , y pz = d. Como veremos en el Captulo 2, estas ecuaciones se pueden expresar fcilmente de forma matricial (que es la forma habitual de trabajar internamente en el pipeline). Estudiaremos ms detalles sobre el modelo de proyeccin en perspectiva en el Captulo 2, as como la transformacin que se realiza de la pirmide de visualizacin (Frustum ) al cubo unitario.

1.3.

Implementacin del Pipeline en GPU


El trmino GPU
Desde el 1999, se utiliza el trmino GPU (Grpahics Processing Unit ) acuado por NVIDIA para diferenciar la primera tarjeta grca que permita al programador implementar sus propios algoritmos (GeForce 256 ).

El hardware de aceleracin grca ha sufrido una importante transformacin en la ltima dcada. Como se muestra en la Figura 1.10, en los ltimos aos el potencial de las GPUs ha superado con creces al de la CPU. Resulta de especial inters conocer aquellas partes del Pipeline de la GPU que puede ser programable por el usuario mediante el desarrollo de shaders. Este cdigo se ejecuta directamente en la GPU, y permite realizar operaciones a diferentes niveles con alta eciencia. En GPU, las etapas del Pipeline grco (estudiadas en la seccin 1.2) se implementan en un conjunto de etapas diferente, que adems pueden o no ser programables por parte del usuario (ver Figura 1.11). Por cuestiones de eciencia, algunas partes del Pipeline en GPU no son programables, aunque se prevee que la tendencia en los prximos aos sea permitir su modicacin. La etapa asociada al Vertex Shader es totalmente programable, y encapsula las cuatro primeras etapas del pipeline grco que estudiamos en la seccin 1.2: Transformacin de Modelado, Transformacin de Visualizacin, Sombreado de Vrtices (Vertex Shader) y Transformacin de Proyeccin.

1.3. Implementacin del Pipeline en GPU

[11]

Nmero de Transistores ( Miles de Millones)

2
GT200 IBM z196

1
G80 ore 2 Duo Pentium IV Pentium III GF4 Itanium 2

AMD K10

A!o 1999

2001

2003

2005

2007

2009

CP U

GP U

GF100

Opteron 2400

2011

Figura 1.10: Evolucin del nmero de transistores en GPU y CPU (1999-2010)

P P F C C C P F

Vertex Shader Geometry Shader Transf. Recorte Transf. Pantalla Config. Tringulo Recorrido Tring. Pixel Shader Fusin (Merger)

La etapa referente al Geometry Shader es otra etapa programable que permite realizar operaciones sobre las primitivas geomtricas. Las etapas de Transformacin de Recorte, Transformacin de Pantalla, Conguracin de Tringulo, Recorrido de Tringulo y Fusin tienen un comportamiento funcional similar al estudiado en la seccin 1.2, por lo que no sern descritas de nuevo. Finalmente, el Pixel Shader es la ltima etapa totalmente programable del pipeline en GPU y permite al programador desarrollar operaciones especcas a nivel de pxel. El desarrollo de shaders actualmente se realiza en lenguajes de alto nivel con una sintaxis similar a C, como HLSL, GLSL y Cg. Estos lenguajes de alto nivel son compilados a un lenguaje ensamblador intermedio independiente de la tarjeta grca. Son los drivers de cada tarjeta grca los que transforman este lenguaje intermedio en instrucciones especcas para cada tarjeta.

Figura 1.11: Implementacin tpica del pipeline en GPU. La letra asociada a cada etapa indica el nivel de modicacin permitida al usuario; P indica totalmente programable, F indica jo (no programable), y C indica congurable pero no programable.

Los tres lenguajes de desarrollo de shading ms empleados actualmente son HLSL (High Level Shader Language ), desarrollado por Microsoft en colaboracin con NVIDIA para Direct3D, GLSL (OpenGL Shading Language ), que forma parte del estndar multiplataforma OpenGL, y Cg (C for Graphics) lenguaje abierto propuesto por NVidia.

[12]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

Veremos a continuacin brevemente algunas caractersticas de estas etapas programables de la GPU.

Ensamblador?
En realidad este cdigo ensamblador intermedio puede verse como una especie de cdigo de mquina virtual que garantiza la compatibilidad entre diferentes dispositivos hardware.

1.3.1. Vertex Shader


Los vertex shaders permiten aplicar transformaciones y deformaciones a nivel de vrtice. Este shader se aplica en la primera etapa del pipeline de la GPU. En esta etapa, los ujos de datos que la CPU enva a la tarjeta son procesados y se aplican las matrices de transformacin especicadas por el usuario. En esta etapa se aplican las instancias sobre los datos enviados a la GPU (evitando enviar varias veces las mismas primitivas geomtricas). A este nivel, el vertex shader nicamente trabaja con la informacin relativa a los vrtices (posicin, vector normal, color y coordenadas de textura). El vertex shader no conoce nada sobre la conexin de estos vrtices entre s para formar tringulos. Algunas operaciones clsicas que se implementan empleando vertex shader son efectos de lente (como por ejemplo, de ojo de pez o distorsiones como las causadas en escenas submarinas), deformaciones de objetos, animaciones de textura, etc.

1.3.2. Geometry Shader


Los geometry shaders facilitan la creacin y destruccin de primitivas geomtricas en la GPU en tiempo de ejecucin (vrtices, lneas y tringulos). La entrada de este mdulo lo forman la especicacin de los objetos con sus vrtices asociados. Para cada primitiva de entrada, el geometry shader devolver cero o ms primitivas de salida. Las primitivas de entrada y salida no tienen por qu ser del mismo tipo. Por ejemplo, es posible indicar un tringulo como entrada (tres vrtices 3d) y devolver el centroide (un punto 3D) como salida. Las primitivas del ujo de salida del geometry shader se obtienen en el mismo orden que se especicaron las primitivas de entrada. Este tipo de shaders se emplean para la simulacin de pelo, para encontrar los bordes de los objetos, o para implementar algunas tcnicas de visualizacin avanzadas como metabolas o simulacin de telas.

1.3.3. Pixel Shader


A nivel de pixel shader se pueden aplicar operaciones a nivel de pxel, permitiendo denir complejas ecuaciones de sombreado que sern evaluadas para cada pxel de la imagen.

Figura 1.12: Resultado de aplicar un Vertex Shader para deformar un modelo.

1.4. Arquitectura del motor grco

[13]

Notacin...
En OpenGL al Pixel Shader se le denomina Fragment Shader. En realidad es un mejor nombre, porque se trabaja a nivel de fragmento.

El Pixel Shader tiene inuencia nicamente sobre el fragmento que est manejando. Esto implica que no puede aplicar ninguna transformacin sobre fragmentos vecinos. El uso principal que se da a este tipo de shaders es el establecimiento mediante cdigo del color y la profundidad asociada al fragmento. Actualmente se emplea para aplicar multitud de efectos de representacin no realista, reexiones, etc.

1.4.

Arquitectura del motor grco

El objetivo de esta seccin es proporcionar una primera visin general sobre los conceptos generales subyacentes en cualquier motor grco 3D interactivo. Estos conceptos sern estudiados en profundidad a lo largo de este documento, mostrando su uso prctico mediante ejemplos desarrollados en C++ empleando el motor grco OGRE. Como se ha visto en la introduccin del captulo, los videojuegos requieren hacer un uso eciente de los recursos grcos. Hace dos dcadas, los videojuegos se diseaban especcamente para una plataforma hardware especca, y las optimizaciones podan realizarse a muy bajo nivel. Actualmente, el desarrollo de un videojuego tiende a realizarse para varias plataformas, por lo que el uso de un motor grco que nos abstraiga de las particularidades de cada plataforma no es una opcin, sino una necesidad.
Compatiblidad
En algunos casos, como en el desarrollo de videojuegos para PC, el programador no puede hacer casi ninguna suposicin sobre el hardware subyacente en la mquina donde se ejecutar nalmente el programa. En el caso de desarrollo para consolas, los entornos de ejecucin concretos estn mucho ms controlados.

En estos desarrollos multiplataforma es necesario abordar aproximaciones de diseo que permitan emplear diferentes perles de ejecucin. Por ejemplo, en mquinas con grandes prestaciones se emplearn efectos y tcnicas de despliegue ms realistas, mientras que en mquinas con recursos limitados se utilizarn algoritmos con menores requisitos computacionales y versiones de los recursos grcos adaptadas (con diferente nivel de detalle asociado). Las limitaciones asociadas a los recursos computacionales son una constante en el rea del desarrollo de videojuegos. Cada plataforma conlleva sus propias limitaciones y restricciones, que pueden asociarse en las categoras de: Tiempo de Procesamiento. El desarrollo de videojuegos en prcticamente cualquier plataforma actual require el manejo de mltiples ncleos de procesamiento (tanto de CPU como GPU). El manejo explcito de la concurrencia (habitualmente a nivel de hilos) es necesario para mantener una alta tasa de Frames por Segundo. Almacenamiento. En el caso de ciertos dispositivos como consolas, la variedad de unidades de almacenamiento de los recursos del juego (con velocidades de acceso y transferencia heterogneas), dicultan el desarrollo del videojuego. En ciertas plataformas, no se dispone de aproximaciones de memoria virtual, por lo que el programador debe utilizar explcitamente superposiciones

[14]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

Figura 1.13: Capturas de algunos videojuegos desarrollados con motores libres. La imagen de la izquierda se corresponde con Planeshift, realizado con Crystal Space. La captura de la derecha es del videojuego H-Craft Championship, desarrollado con Irrlicht.

(overlays) para cargar las zonas del juego que van a emplearse en cada momento. Dada la gran cantidad de restricciones que deben manejarse, as como el manejo de la heterogeneidad en trminos software y hardware, es necesario el uso de un motor de despliegue grco para desarrollar videojuegos. A continuacin enunciaremos algunos de los ms empleados.

1.5.

Casos de Estudio

En esta seccin se estudiarn algunos de los motores grcos 3D libres, comentando brevemente algunas de sus caractersticas ms destacables. Crystal Space. Crystal Space (http://www.crystalspace3d.org/) es un framework completo para el desarrollo de videojuegos escrito en C++, desarrollado inicialmente en 1997. Se distribuye bajo licencia libre LGPL, y es multiplataforma (GNU/Linux, Windows y Mac). Panda 3D. Panda 3D (http://www.panda3d.org/) es un motor para el desarrollo de videojuegos multiplataforma. Inicialmente fue desarrollado por Disney para la construccin del software asociado a las atracciones en parques temticos, y posteriormente liberado en 2002 bajo licencia BSD. Este motor multiplataforma (para GNU/Linux, Windows y Mac) incluye interfaces para C++ y Python. Su corta curva de aprendizaje hace que haya sido utilizado en varios cursos universitarios, pero no ofrece caractersticas

1.6. Introduccin a OGRE

[15] de representacin avanzadas y el interfaz de alto nivel de Python conlleva una prdida de rendimiento. Irrlicht. Este motor grco de renderizado 3D, con primera versin publicada en el 2003 (http://irrlicht.sourceforge.net/), ofrece interfaces para C++ y .NET. Existen gran cantidad de wrappers a diferentes lenguajes como Java, Perl, Python o Lua. Irrlicht tiene una licencia Open Source basada en la licencia de ZLib. Irrlicht es igualmente multiplataforma (GNU/Linux, Windows y Mac). OGRE. OGRE (http://www.ogre3d.org/) es un motor para grcos 3D libre multiplataforma. Sus caractersticas sern estudiadas en detalle en la seccin 1.6. De entre los motores estudiados, OGRE 3D ofrece una calidad de diseo superior, con caractersticas tcnicas avanzadas que han permitido el desarrollo de varios videojuegos comerciales. Adems, el hecho de que se centre exclusivamente en el capa grca permite utilizar gran variedad de bibliotecas externas (habitualmente accedidas mediante plugins) para proporcionar funcionalidad adicional. En la siguiente seccin daremos una primera introduccin y toma de contacto al motor libre OGRE.

Figura 1.14: El logotipo de OGRE 3D es un... OGRO!

1.6.

Introduccin a OGRE

OGRE es un motor orientado a objetos libre para aplicaciones grcas 3D interactivas. El nombre del motor OGRE es un acrnimo de Object-oriented Graphics Rendering Engine. Como su propio nombre indica, OGRE no es un motor para el desarrollo de videojuegos; se centra exclusivamente en la denicin de un middleware para el renderizado de grcos 3D en tiempo real.
Slo Rendering!
El desarrollo de OGRE se centra exclusivamente en la parte de despliegue grco. El motor no proporciona mecanismos para capturar la interaccin del usuario, ni para reproduccin audio o gestin del estado interno del videojuego.

El proyecto de OGRE comenz en el 2000 con el propsito de crear un motor grco bien diseado. El lder del proyecto Steve Streeting dene el desarrollo de OGRE como un proyecto basado en la calidad ms que en la cantidad de caractersticas que soporta, porque la cantidad viene con el tiempo, y la calidad nunca puede aadirse a posteriori. La popularidad de OGRE se basa en los principios de meritocracia de los proyectos de software libre. As, el sitio web de OGRE 2 recibe ms de 500.000 visitas diarias, con ms de 40.000 descargas mensuales. El ncleo principal de desarrolladores en OGRE se mantiene deliberadamente pequeo y est formado por profesionales con dilatada experiencia en proyectos de ingeniera reales. OGRE tiene una licencia LGPL Lesser GNU Public License. Esta licencia se utiliza con frecuencia en bibliotecas que ofrecen funcionalidad que es similar a la de otras bibliotecas privativas. Por cuestin de estrategia, se publican bajo licencia LGPL (o GPL Reducida ) para
2 http://www.ogre3d.org

[16]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

permitir que se enlacen tanto por programas libres como no libres. La nica restriccin que se aplica es que si el enlazado de las bibliotecas es esttico, la aplicacin resultado debe ser igualmente LGPL (porque el enlazado esttico tambin enlaza la licencia ). La versin ocial de OGRE est desarrollada en C++ (el lenguaje estndar en el mbito del desarrollo de videojuegos). La rama ocial de OGRE nicamente se centra en este lenguaje sobre los sistemas operativos GNU/Linux, Mac OS X y Microsoft Windows. No obstante, existen wrappers de la API a otros lenguajes (como Java, Python o C#) que son mantenidos por la comunidad de usuarios (presentando diferentes niveles de estabilidad y completitud), que no forman parte del ncleo ocial de la biblioteca. Algunas caractersticas destacables de OGRE son: Motor Multiplataforma. Aunque el desarrollo original de OGRE se realiz bajo plataformas Microsoft Windows, la distribucin ocial ofrece versiones binarias para GNU/Linux y Mac OS X. Adems, gracias al soporte nativo de OpenGL, es posible compilar la biblioteca en multitud de plataformas (como diversas versiones de Unix, adems de algunos ports no ociales para Xbox y dispositivos porttiles). OGRE soporta la utilizacin de las APIs de despliegue grco de bajo nivel OpenGL y Direct3D. Diseo de Alto Nivel. OGRE encapsula la complejidad de acceder directamente a las APIs de bajo nivel (como OpenGL y Direct3D) proporcionando mtodos intuitivos para la manipulacin de objetos y sus propiedades relacionadas. De este modo no es necesario gestionar manualmente la geometra o las matrices de transformacin. Todos los objetos representables de la escena se abstraen en un interfaz que encapsula las operaciones necesarias para su despliegue (tcnicas empleadas y pasadas de composicin). OGRE hace un uso de varios patrones de diseo para mejorar la usabilidad y la exibilidad de la bibloteca. Por ejemplo, para informar a la aplicacin sobre eventos y cambios de estado utiliza el patrn Observador. El patrn Singleton se emplea en gran nmero de Gestores para forzar que nicamente exista una instancia de una clase. El patrn Visitor se emplea para permitir operaciones sobre un objeto sin necesidad de modicarlo (como en el caso de los nodos del grafo de escena), el patrn Facade para unicar el acceso a operaciones, Factora para la creacin de instancias concretas de interfaces abstractos, etc. La denicin de estos patrones sern estudiadas en detalle en el Mdulo 1 del curso. Grafos de Escena. Prcticamente cualquier biblioteca de despliegue de grcos 3D utiliza un Grafo de Escena para organizar los elementos que sern representados en la misma. Un objetivo fundamental en el diseo de esta estructura de datos es permitir bsquedas ecientes. Una de las caractersticas ms potentes de OGRE es el desacople del grafo de escena del contenido de la escena, deniendo una arquitectura de plugins. En pocas palabras,
Portabilidad
Uno de los objetivos de diseo de OGRE es utilizar otras bibliotecas multiplataforma estables en su desarrollo, como FreeType para el despliegue de fuentes TrueType, OpenIL para la carga y manipulacin de imgenes y ZLib para la gestin de archivos comprimidos ZIP.

1.6. Introduccin a OGRE

[17] a diferencia de otros motores grcos como Irrlicht3D, Blitz3D o TrueVision3D (o motores de videojuegos como Torque, CryEngine o Unreal), OGRE no se basa en la Herencia como principio de diseo del Grafo de Escena, sino en la Composicin. Esto permite expandir el diseo cmodamente para soportar otros tipos de datos (como audio o elementos de simulacin fsica). La Figura 1.15 muestra el esquema general de gestin del grafo de escena en OGRE. Los Renderables manejan la geometra de la escena. Todas las propiedades para el despliegue de estos Renderables (como por ejemplo los materiales) se gestionan en objetos de tipo Entidad (Entity) que pueden estar formados por varios objetos SubEntidad (SubEntity). Como se ha comentado anteriormente, la escena se Compone de nodos de escena. Estos SceneNodes se adjuntan a la escena. Las propiedades de esos nodos de escena (geometra, materiales, etc...) se ofrecen al SceneGraph mediante un MovableObject. De forma similar, los MovableObjects no son subclases de SceneNode, sino que se adjuntan. Esto permite realizar modicaciones en la implementacin del grafo de escena sin necesidad de tocar ninguna lnea de cdigo en la implementacin de los objetos que contiene. Veremos ms detalles sobre el trabajo con el grafo de escena a lo largo de este mdulo. Aceleracin Hardware. OGRE necesita una tarjeta aceleradora grca para poder ejecutarse (con soporte de direct rendering mode ). OGRE permite denir el comportamiento de la parte programable de la GPU mediante la denicin de Shaders, estando al mismo nivel de otros motores como Unreal o CryEngine. Materiales. Otro aspecto realmente potente en OGRE es la gestin de materiales. Es posible crear materiales sin modicar ni una lnea de cdigo a compilar. El sistema de scripts para la denicin de materiales de OGRE es uno de los ms potentes existentes en motores de rendering interactivo. Los materiales de OGRE se denen mediante una o ms Tcnicas, que se componen a su vez de una o ms Pasadas de rendering (el ejemplo de la Figura 1.16 utiliza una nica pasada para simular el sombreado a lpiz mediante hatching). OGRE busca automticamente la mejor tcnica disponible en un material que est soportada por el hardware de la mquina de forma transparente al programador. Adems, es posible denir diferentes Esquemas asociados a modos de calidad en el despliegue.

SceneGraph
Adjunto Attached

SceneNode

SceneNode

Adjunto Attached MovableObject MovableObject Implementa Entity Entity Contiene Subentity SubEntity Implementa Renderable A Renderable B

Figura 1.15: Esquema general de la gestin del grafo de escena en OGRE.

Figura 1.16: Ejemplo de Shader desarrollado por Assaf Raman para simular trazos a Lpiz empleando el sistema de materiales de OGRE.

Animacin. OGRE soporta tres tipos de animacin ampliamente utilizados en la construccin de videojuegos: basada en esqueletos (skeletal), basada en vrtices (morph y pose ). En la animacin mediante esqueletos, OGRE permite el uso de esqueletos con animacin basada en cinemtica directa. Existen multitud de exportadores para los principales paquetes de edicin 3D. En este mdulo utilizaremos el exportador de Blender. El sistema de animacin de OGRE se basa en el uso de controladores, que modican el valor de una propiedad en funcin de otro valor. En el caso de animaciones se utiliza el tiempo como

[18]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES valor para modicar otras propiedades (como por ejemplo la posicin del objeto). El motor de OGRE soporta dos modelos bsicos de interpolacin: lineal y basada en splines cbicas. La animacin y la geometra asociada a los modelos se almacena en un nico formato binario optimizado. El proceso ms empleado se basa en la exportacin desde la aplicacin de modelado y animacin 3D a un formato XML (Ogre XML ) para convertirlo posteriormente al formato binario optimizado mediante la herramienta de lnea de rdenes OgreXMLConverter. Composicin y Postprocesado. El framework de composicin facilita al programador incluir efectos de postprocesado en tiempo de ejecucin (siendo una extensin del pixel shader del pipeline estudiado en la seccin 1.3.3). La aproximacin basada en pasadas y diferentes tcnicas es similar a la explicada para el gestor de materiales. Plugins. El diseo de OGRE facilita el diseo de Plugins como componentes que cooperan y se comunican mediante un interfaz conocido. La gestin de archivos, sistemas de rendering y el sistema de partculas estn implementados basados en el diseo de Plugins. Gestin de Recursos. Para OGRE los recursos son los elementos necesarios para representar un objetivo. Estos elementos son la geometra, materiales, esqueletos, fuentes, scripts, texturas, etc. Cada uno de estos elementos tienen asociado un gestor de recurso especco. Este gestor se encarga de controlar la cantidad de memoria empleada por el recurso, y facilitar la carga, descarga, creacin e inicializacin del recurso. OGRE organiza los recursos en niveles de gestin superiores denominados grupos. Veremos en la seccin 1.6.1 los recursos gestionados por OGRE. Caractersticas especcas avanzadas. El motor soporta gran cantidad de caractersticas de visualizacin avanzadas, que estudiaremos a lo largo del mdulo, tales como sombras dinmicas (basadas en diversas tcnicas de clculo), sistemas de partculas, animacin basada en esqueletos y de vrtices, y un largo etctera. OGRE soporta adems el uso de otras bibliotecas auxiliares mediante plugins y conectores. Entre los ms utilizados cabe destacar las bibliotecas de simulacin fsica ODE, el soporte del metaformato Collada, o la reproduccin de streaming de vdeo con Theora. Algunos de estos mdulos los utilizaremos en el mdulo 3 del presente curso.
Optimizacin ofine
El proceso de optimizacin de al formato binario de OGRE calcula el orden adecuado de los vrtices de la malla, calcula las normales de las caras poligonales, as como versiones de diferentes niveles de detalle de la malla. Este proceso evita el clculo de estos parmetros en tiempo de ejecucin.

1.6.1. Arquitectura General


El diagrama de la Figura 1.17 resume algunos de los objetos principales del motor OGRE. No es un diagrama exhaustivo, pero facilita la comprensin de los principales mdulos que utilizaremos a lo largo del curso.

1.6. Introduccin a OGRE

[19]

Root

Gestin de Escena
Scene Node Material SceneManager Mo!able"b#ect

Plugin
"ctreeSceneManager

Plugin
Entit$ %amera &ight %ustomMo!able

Gestin de Recursos
ResourceGroupManager GPUProgram Mesh ResourceManager 'rchi!e(actor$ )e*ture

Rendering
Renderable Render indow HwBufferManager RenderS$stem

Plugin
%ustom'rchi!e(actor$ G&)e*ture

Plugin
G&RenderS$stem

Figura 1.17: Diagrama general de algunos de los objetos principales de OGRE

Objeto Root
El objeto Root es el eje pricipal sobre el que se dene una aplicacin que utiliza OGRE. La creacin de una instancia de esta clase har que se inicie OGRE, y su destruccin har que se libere la memoria asociada a todos los objetos que dependen de l.

Uno de los objetos principales del sistema es el denominado Root. Root proporciona mecanismos para la creacin de los objetos de alto nivel que nos permitirn gestionar las escenas, ventanas, carga de plugins, etc. Gran parte de la funcionalidad de Ogre se proporciona a travs del objeto Root. Como se muestra en el diagrama 1.17, existen otros tres grupos de clases principales en OGRE: Gestin de Escena: Los objetos de este grupo de clases se encargan de denir el contenido de la escena virtual, su estructura, as como otras propiedades de alto nivel de abstraccin (posicin de la cmara, posicin de los objetos, materiales, etc...). Como se estudi en la Figura 1.15, el grafo de escena es un elemento principal en la arquitectura de cualquier motor 3D. En el caso de OGRE, el Gestor de Escena (clase SceneManager ) es el que se encarga de implementar el grafo de escena. Los nodos de escena SceneNode son elementos relacionados jerrquicamente, que pueden adjuntarse o desligarse de una escena en tiempo de ejecucin. El contenido de estos SceneNode se adjunta en la forma de instancias de Entidades (Entity), que son implementaciones de la clase MovableObject. Gestin de Recursos: Este grupo de objetos se encarga de gestionar los recursos necesarios para la representacin de la escena (geometra, texturas, tipografas, etc...). Esta gestin permite su

[20]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES carga, descarga y reutilizacin (mediante cachs de recursos). En la siguiente subseccin veremos en detalle los principales gestores de recursos denidos en OGRE. Rendering: Este grupo de objetos sirve de intermediario entre los objetos de Gestin de Escena y el pipeline grco de bajo nivel (con llamadas especcas a APIs grcas, trabajo con buffers, estados internos de despliegue, etc.). La clase RenderSystem es un interfaz general entre OGRE y las APIs de bajo nivel (OpenGL o Direct3D). La forma ms habitual de crear la RenderWindow es a travs del objeto Root o mediante el RenderSystem (ver Figura 1.18). La creacin manual permite el establecimiento de mayor cantidad de parmetros, aunque para la mayora de las aplicaciones la creacin automtica es ms que suciente.
Entidades Procedurales
La mayor parte de las entidades que incluyas en el SceneNode sern cargadas de disco (como por ejemplo, una malla binaria en formato .mesh). Sin embargo, OGRE permite la dencin en cdigo de otras entidades, como una textura procedural, o un plano.

Por ser la gestin de recursos uno de los ejes principales en la creacin de una aplicacin grca interactiva, estudiaremos a continuacin los grupos de gestin de recursos y las principales clases relacionadas en OGRE. Gestin de Recursos Como hemos comentado anteriormente, cualquier elemento necesario para represesntar una escena se denomina recurso. Todos los recursos son gestionados por un nico objeto llamado ResourceGroupManager, que se encarga de buscar los recursos denidos en la aplicacin e inicializarlos. Cada tipo de recurso tiene asociado un gestor de recurso particular. Veamos a continuacin los tipos de recursos soportados en OGRE: Mallas. La geometra de los elementos de la escena se especica en un formato de malla binario (.mesh). Este formato almacena la geometra y la animacin asociada a los objetos. Materiales. Como se ha descrito anteriormente, el material se especica habitualmente mediante scripts (en cheros de extensin .material). Estos scripts pueden estar referenciados en el propio archivo .mesh o pueden ser enlazados a la malla mediante cdigo compilado. Texturas. OGRE soporta todos los formatos de texturas 2D admitidos por la biblioteca OpenIL. El formato se reconoce por la extensin asociada al mismo. Esqueletos. Habitualmente el esqueleto est referenciado en el chero .mesh. El chero de denicin de esqueleto contiene la jerarqua de huesos asociada al mismo y tiene una extensin .skeleton. Fuentes. Las fuentes empleadas en la etapa de despliegue de Overlays se denen en un archivo .fontdef. Composicin. El framework de composicin de OGRE carga sus scripts con extensin .compositor.

1.6. Introduccin a OGRE

[21]

ResourceManager

TextureManager MaterialManager RenderSystem

FontManager

MeshManager

GpuProgramManager

SkeletonManager HighLevelGpuProgramManager

ExternalTextureSourceManager SceneManager Render indo! OverlayManager ResourceGroupManager

Root

ParticleSystemManager Plat%ormManager

LogManager

"ynLi#Manager

$rchiveManager

Figura 1.18: Diagrama de clases simplicado de los Gestores de alto nivel que dan acceso a los diferentes subsistemas denidos en OGRE

GPU. El cdigo de shaders denidos para la GPU (de HLSL, GLSL y Cg) se describe en archivos con extensin .program. De igual modo se pueden denir cdigo en ensamblador mediante archivos .asm. Los programas de GPU son cargados antes que se procese cualquier archivo de material .material, de forma que estos shaders puedan ser referenciados en los archivos de denicin de material. Un gestor (Manager ) en OGRE es una clase que gestiona el acceso a otros tipos de objetos (ver Figura 1.18). Los Managers de OGRE se implementan mediante el patrn Singleton que garantiza que nicamente hay una istancia de esa clase en toda la aplicacin. Este patrn permite el acceso a la instancia nica de la clase Manager desde cualquier lugar del cdigo de la aplicacin. Como puede verse en la Figura 1.18, el ResourceManager es una clase abstracta de la que heredan un gran nmero de Managers, tales como el encargado de las Fuentes, las Texturas o las Mallas. A continuacin se ofrece una descripcin general de los Managers (por orden alfabtico) denidos en OGRE. A lo largo del documento se describirn (y se utilizarn ampliamente) muchos de estos gestores. Archive Manager. Se encarga de abstraer del uso de cheros con diferentes extensiones, directorios y archivos empaquetados .zip.

[22]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES CompositorManager. Esta clase proporciona acceso al framework de composicin y postprocesado de OGRE. ControllerManager. Es el gestor de los controladores que, como hemos indicado anteriormente, se encargan de producir cambios en el estado de otras clases dependiendo del valor de ciertas entradas. DynLibManager. Esta clase es una de las principales en el diseo del sistema de Plugins de OGRE. Se encarga de gestionar las bibliotecas de enlace dinmico (DLLs en Windows y objetos compartidos en GNU/Linux). ExternalTextureSourceManager. Gestiona las fuentes de textura externas (como por ejemplo, en el uso de video streaming). FontManager. Gestiona las fuentes disponibles para su representacin en superposiciones 2D (ver OverlayManager ). GpuProgramManager. Carga los programas de alto nivel de la GPU, denidos en ensamblador. Se encarga igualmente de cargar los programas compilados por el HighLevelGpuProgramManager. HighLevelGpuProgramManager. Gestiona la carga y compilacin de los programas de alto nivel en la GPU (shaders) utilizados en la aplicacin en HLSL, GLSL o Cg. LogManager. Se encarga de enviar mensajes de Log a la salida denida por OGRE. Puede ser utilizado igualmente por cualquier cdigo de usuario que quiera enviar eventos de Log. MaterialManager. Esta clase mantiene las instancias de Material cargadas en la aplicacin, permitiendo reutilizar los objetos de este tipo en diferentes objetos. MeshManager. De forma anloga al MaterialManager, esta clase mantiene las instancias de Mesh permitiendo su reutilizacin entre diferentes objetos. OverlayManager. Esta clase gestiona la carga y creacin de instancias de superposiciones 2D, que permiten dibujar el interfaz de usuario (botones, iconos, nmeros, radar...). En general, los elementos denidos como HUDs (Head Up Display). ParticleSystemManager. Gestiona los sistemas de partculas, permitiendo aadir gran cantidad de efectos especiales en aplicaciones 3D. Esta clase gestiona los emisores, los lmites de simulacin, etc. PlatformManager. Esta clase abstrae de las particularidades del sistema operativo y del hardware subyacente de ejecucin, proporcionando rutinas independientes del sistema de ventanas, temporizadores, etc. ResourceGroupManager. Esta clase gestiona la lista de grupos de recursos y se encarga de noticar a los Managers de la necesidad de cargar o liberar recursos en cada grupo.

1.6. Introduccin a OGRE

[23] SceneManager. Como se ha explicado anteriormente, esta clase se encarga de la gestin, organizacin y rendering de la escena. Esta clase permite denir subclases que organicen la escena de una forma ms eciente, dependiendo del tipo de aplicacin. Por defecto, el SceneManager utiliza una jerarqua de cajas lmite (bounding boxes) para optimizar el despliegue de los objetos.

SceneManager
Los SceneManagers de OGRE son implementados como Plugins, de forma que el usuario puede cargar varios gestores de escena en su aplicacin. Si el videojuego requiere escenas de interiores con mucha geometra, as como escenas de exteriores, puede ser interesante cargar dos gestores de escena diferentes optimizados para cada parte del juego.

SkeletonManager. Al igual que el MaterialManager y el MeshManager, esta clase mantiene las instancias de Skeleton cargadas en la aplicacin, permitiendo su reutilizacin entre diferentes objetos. TextureManager. Gestiona la carga y uso de las texturas de la aplicacin.

1.6.2. Instalacin
En esta seccin se detallar el proceso de instalacin de la biblioteca OGRE 1.8 en sistemas GNU/Linux y Microsoft Windows. Nos centraremos en la instalacin en distribuciones Debian, que servirn como base para el desarrollo del presente curso. No obstante, se proporcionarn igualmente las herramientas necesarias y makeles adaptados para Microsoft Windows empleando MinGW. GNU/Linux (Debian) Para comenzar, instalaremos las herramientas de compilacin bsicas necesarias para compilar: gcc, g++ y make se encuentran disponibles en el metapaquete build-essential :
apt-get install build-essential

A continuacin instalaremos los paquetes especcos de OGRE:


apt-get install libogre-1.8.0 libogre-1.8-dev ogre-1.8-doc ogre-1.8tools

El paquete libogre-1.8.0 contiene las bibliotecas necesarias para la ejecucin de las aplicaciones desarrolladas con OGRE. El paquete libogre-dev contiene los cheros de cabecera instalados en /usr/include/OGRE necesarios para compilar nuestros propios ejemplos. El paquete de documentacin ogre-doc instala en /usr/share/doc/ogre-doc la documentacin (manual de usuario y API). Finalmente el paquete ogre-tools contiene las herramientas para convertir al formato de malla binario optimizado de OGRE. Como se coment en la introduccin, OGRE se centra en proporcionar exclusivamente un motor de despliegue grco 3D interactivo. OGRE no proporciona mecanismos para gestionr la entrada del usuario. En este mdulo utilizaremos OIS (Object Oriented Input System), una biblioteca desarrollada en C++ multiplataforma que permite trabajar con teclado, ratn, joysticks y otros dispositivos de juego. Instalaremos igualmente el paquete binario y las cabeceras.

[24]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

apt-get install libois-1.3.0 libois-dev

Tanto OGRE como OIS puede ser igualmente instalado en cualquier distribucin compilando directamente los fuentes. En el caso de OGRE, es necesario CMake para generar el makele especco para el sistema donde va a ser instalado. En el caso de OIS, es necesario autotools. Microsoft Windows Aunque no utilizaremos ningn entorno de desarrollo en esta plataforma, dada su amplia comunidad de usuarios, puede ser conveniente generar los ejecutables para esta plataforma. A continuacin se detallarn los pasos necesarios para instalar y compilar los desarrollos realizados con OGRE en plataformas Windows. Como entorno de compilacin utilizaremos MinGW (Minimalist GNU for Windows), que contiene las herramientas bsicas de compilacin de GNU para Windows. El instalador de MinGW mingw-get-inst puede obtenerse de la pgina web http://www.mingw.org/. Puedes instalar las herramientas en C:\MinGW\. Una vez instaladas, debers aadir al path el directorio C:\MinGW\bin. Para ello, podrs usar la siguiente orden en un terminal del sistema.
path = %PATH %;C:\MinGW\bin

De igual modo, hay que descargar el SDK de DirectX3 . Este paso es opcional siempre que no queramos ejecutar ningn ejemplo de OGRE que utilice Direct3D. A continuacin instalaremos la biblioteca OGRE3D para MinGW4 . Cuando acabe, al igual que hicimos con el directorio bin de MinGW, hay que aadir los directorios boost_1_44\lib\ y bin\Release al path.
path = %PATH %;C:\Ogre3D\boost_1_44\lib\; C:\Ogre3D\bin\

Sobre Boost...
Boost es un conjunto de bibliotecas libres que aaden multitud de funcionalidad a la biblioteca de C++ (estn en proceso de aceptacin por el comit de estandarizacin del lenguaje).

1.7.

Hola Mundo en OGRE

A continuacin examinaremos un ejemplo bsico de funcionamiento de OGRE. Utilizaremos la estructura de directorios mostrada en la Figura 1.19 en los ejemplos desarrollados a lo largo de este mdulo. En el directorio include se incluirn los archivos de cabecera. En este primer ejemplo, no es necesario ningn archivo de cabecera adicional, por lo que este directorio estar vaco.
3 Puede descargarse de: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=6812 4 Puede descargarse de: http://www.ogre3d.org/download/sdk

1.7. Hola Mundo en OGRE

[25] El directorio media contendr los archivos de geometra, animaciones y texturas necesarios para ejecutar el ejemplo. Todos estos archivos sern cargados por el ResourceManager. En obj se generarn automticamente los cheros objeto compilados a partir de los fuentes existentes en src. El diretorio plugins contendr los plugins de Ogre. En GNU/Linux, podemos crear un enlace simblico de este directorio al lugar donde se encuentran los plugins (archivos .so) en disco. En Windows deberemos copiar los .dll a este directorio. La ruta de este directorio, como veremos ms adelante, se debe indicar en el archivo plugins.cfg. El directorio src contiene los cheros fuente de la aplicacin. Gracias al makefile que veremos a continuacin, la compilacin de todos los cheros fuente en objetos binarios se realiza automticamente. Para compilar el ejemplo, deniremos un makefile para ambos sistemas operativos. En el siguiente listado se muestra el resultado para GNU/Linux. El formato y uso de make ser estudiado en detalle a lo largo del primer mdulo del curso. En la lnea 0 se dene el nombre del ejecutable que queremos obtener. A continuacin en las lneas 1-3 se denen los para directorios los archivos fuente, objetos y cabeceras. Las lneas 8 y 11 denen los ags para la compilacin y enlazado respectivamente. El makele construido permite indicar el modo de compilacin, utilizando unos ags de compilacin en modo Debug y otros en modo Release. Si llamamos a make con mode=release, se utilizarn los ags de compilacin optimizada. En otro caso, utilizaremos la compilacin con smbolos para el depurado posterior con GDB. En las lneas 23-24 se utilizan las funciones de make para generar la lista de objetos a partir de los fuentes .cpp existentes en el directorio apuntado por DIRSRC. De este modo, se obtienen los objetos con el mismo nombre que los fuentes, pero situados en el directorio indicado por DIROBJ. Finalmente, en las lneas 36-42 se emplean las reglas de compilacin implcitas de make para generar el ejecutable. Se incluye al nal la tpica regla de clean para limpiar los temporales obtenidos. De este modo, para compilar el ejemplo en modo release ejecutaremos en un terminal
make mode=release

holaMundo
include * media obj * plugins * src makefile makefile.win [ogre.cfg] plugins.cfg resources.cfg
Figura 1.19: Descripcin de directorios del ejemplo Hola Mundo .

Si no indicamos modo, o indicamos explcitamente mode=debug, se utilizarn los ags de compilacin en modo debug.

[26]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

Listado 1.1: Makele genrico para GNU/Linux


0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

EXEC := helloWorld DIRSRC := src/ DIROBJ := obj/ DIRHEA := include/ CXX := g++ # Flags de compilacion -------------------------------------------CXXFLAGS := -I $(DIRHEA) -Wall pkg-config --cflags OGRE # Flags del linker -----------------------------------------------LDFLAGS := pkg-config --libs-only-L OGRE LDLIBS := pkg-config --libs-only-l OGRE -lOIS -lGL -lstdc++ # Modo de compilacion (-mode=release -mode=debug) ----------------ifeq ($(mode), release) CXXFLAGS += -O2 -D_RELEASE else CXXFLAGS += -g -D_DEBUG mode := debug endif # Obtencion automatica de la lista de objetos a compilar ---------OBJS := $(subst $(DIRSRC), $(DIROBJ), \ $(patsubst %.cpp, %.o, $(wildcard $(DIRSRC)*.cpp))) .PHONY: all clean all: info $(EXEC) info: @echo @echo @echo @echo

--------------------------------------------------- >>> Using mode $(mode) (Please, call "make" with [mode=debug|release]) ---------------------------------------------------

# Enlazado -------------------------------------------------------$(EXEC): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) # Compilacion ----------------------------------------------------$(DIROBJ) %.o: $(DIRSRC) %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ $(LDLIBS) # Limpieza de temporales -----------------------------------------clean: rm -f *.log $(EXEC) *~ $(DIROBJ)* $(DIRSRC)*~ $(DIRHEA)*~

El makele en su versin para plataformas windows se ha nombrado como makele.win. Bsicamente es similar al estudiado para GNU/Linux, pero cambian los ags de compilacin. Para compilar, tendremos que ejecutar el make de MinGW que se denomina mingw32make. De este modo, para compilar ejecutaremos desde una consola:
mingw32-make -f makefile-windows mode=release Figura 1.20: Ventana de conguracin de las propiedades de Rendering.

Como se muestra en la Figura 1.19, adems de los archivos para make, en el directorio raiz se encuentran tres archivos de conguracin. Estudiaremos a continuacin su contenido:

1.7. Hola Mundo en OGRE

[27] ogre.cfg. Este archivo, si existe, intentar ser cargado por el objeto Root. Si el archivo no existe, o est creado de forma incorrecta, se le mostrar al usuario una ventana para congurar los parmetros (resolucin, mtodo de anti-aliasing, profundidad de color, etc...). En el ejemplo que vamos a realizar, se fuerza a que siempre se abra el dilogo (ver Figura 1.20), recuperando los parmetros que el usuario especic en la ltima ejecucin. plugins.cfg. Como hemos comentado anteriormente, un plugin es cualquier mdulo que implementa alguno de los interfaces de plugins de Ogre (como SceneManager o RenderSystem ). En este archivo se indican los plugins que debe cargar OGRE, as como su localizacin. En el ejemplo del holaMundo, el contenido del archivo indica la ruta al lugar donde se encuentran los plugins (PluginFolder), as como el Plugin que emplearemos (pueden especicarse varios en una lista) para el rendering con OpenGL.

Plugins.cfg en Windows
En sistemas Windows, como no es posible crear enlaces simblicos, se deberan copiar los archivos .dll al directorio plugins del proyecto e indicar la ruta relativa a ese directorio en el archivo plugins.cfg. Esta aproximacin tambin puede realizarse en GNU/Linux copiando los archivos .so a dicho directorio.

resources.cfg. En esta primera versin del archivo de recursos, se especica el directorio general desde donde OGRE deber cargar los recursos asociados a los nodos de la escena. A lo largo del curso veremos cmo especicar manualmente ms propiedades a este archivo. Una vez denida la estructura de directorios y los archivos que forman el ejemplo, estudiaremos la docena de lneas de cdigo que tiene nuestro Hola Mundo.
Listado 1.2: El main.cpp del Hola Mundo en OGRE
0 #include <ExampleApplication.h> 1 2 class SimpleExample : public ExampleApplication { 3 public : void createScene() { 4 Ogre::Entity *ent = mSceneMgr->createEntity("Sinbad", "Sinbad.

mesh");
5 mSceneMgr->getRootSceneNode()->attachObject(ent); 6 } 7 }; 8 9 int main(void) { 10 SimpleExample example; 11 example.go(); 12 13 return 0; 14 }

Nombres en entidades
Si no indicamos ningn nombre, OGRE elegir automticamente un nombre para la misma. El nombre debe ser nico. Si el nombre existe, OGRE devolver una excepcin.

Como vemos, en el main se crea una instancia de la clase SimpleE). Esta clase es derivada de la clase xample (denida en las lneas 2-7 base ExampleApplication, que se proporciona en el SDK de OGRE para facilitar el aprendizaje de la biblioteca. En esta clase denimos el mtodo pblico CreateScene. En la lnea 4 llamamos al SceneManager (creado automticamente por la clase base ExampleApplication ) a travs de su puntero, solicitando la creacin de una entidad con nombre nico Sinbad, asociado a Sinbad.mesh

[28]

CAPTULO 1. FUNDAMENTOS DE GRFICOS TRIDIMENSIONALES

d
Figura 1.21: Trabajos nales de los alumnos del Curso de Experto en Desarrollo de Videojuegos (Edicin 2011/2012), que utilizaban OGRE como motor de representacin grca. a) Impulse (I. Cuesta, S. Fernndez), b) Vault Defense (D. Frutos, J. Lpez, D. Palomares), c) Robocorps (E. Aguilar, J. Alczar, R. Pozuelo, M. Romero), d) Shadow City (L.M. Garca-Muoz, D. Martn-Lara, E. Monroy), e) Another Fast West (R.C. Daz, J.M. Garca, A. Suarez), f) Msica Maestro (P. Santos, C. de la Torre).

(que se encontrar en el directorio especicado en resources.cfg). Esta llamada nos crear la entidad, y nos devolver un puntero a un objeto de ese tipo. A continuacin, adjuntamos la entidad creada a la escena. Para ello, accedemos al mtodo attachObject() del nodo raz devuelto por getRootSceneNode(). Si compilamos y ejecutamos el holaMundo, primero nos aparecer una ventana para congurar las opciones de rendering (como se muestra en la Figura 1.20). Cuando pulsemos Accept , se abrir una ventana con el modelo cargado (muy pequeito). Si pulsamos la echa , el modelo se acercar. Podemos variar la posicin de la del cursor cmara y la rotacin del modelo (as como su modo rendering) de con los otros tres cursores , y las teclas A , S , D , W y R . La salida del modelo se muestra en la Figura 1.22. La clase ExampleApplication nos abstrae de la complejidad de crear una aplicacin desde cero con OGRE. Utilizaremos esta clase base en algunos ejemplos ms del siguiente captulo, pero la abandonaremos rpidamente para controlar todos los aspectos relativos a la inicializacin (carga de Plugins, denicin del RenderSystem, gestin de la cmara virtual, control de eventos, etc).
Figura 1.22: Resultado, tras ajustar el modelo, del Hello World.

Captulo

Matemticas para Videojuegos


Carlos Gonzlez Morcillo

n este captulo comenzaremos a estudiar las transformaciones anes bsicas que sern necesarias para en el desarrollo de Videojuegos. Las transformaciones son herramientas imprescindibles para cualquier aplicacin que manipule geometra o, en general, objetos descritos en el espacio 3D. La mayora de API (Application Program Interface)s y motores grcos que trabajan con grcos 3D (como OGRE (Object-Oriented Graphics Rendering Engine)) implementan clases auxiliares para facilitar el trabajo con estos tipos de datos.

2.1.
Figura 2.1: Aunque en desarrollo de videojuegos se hace uso de prcticamente todas las reas de las matemticas (desde trigonometra, lgrebra, estadstica o clculo), en este captulo nos centraremos en los fundamentos ms bsicos del lgebra lineal.

Puntos, Vectores y Coordenadas

Los videojuegos necesitan posicionar objetos en el espacio 3D. El motor grco debe gestionar por tanto la posicin, orientacin y escala de estos objetos (y sus cambios a lo largo del tiempo). Como vimos en el captulo 1, en grcos interactivos suelen emplearse representaciones poligionales basadas en tringulos para mejorar la eciencia. Los vrtices de estos tringulos se representan mediante puntos, y las normales mediante vectores. Veamos a continuacin algunos conceptos bsicos relacionados con los puntos y los vectores.

29

[30]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

2.1.1. Puntos
Un punto puede denirse como una localizacin en un espacio n dimensional. En el caso de los videojuegos, este espacio suele ser bidimensional o tridimensional. El tratamiento discreto de los valores asociados a la posicin de los puntos en el espacio exige elegir el tamao mnimo y mximo que tendrn los objetos en nuestro videojuego. Es crtico denir el convenio empleado relativo al sistema de coordenadas y las unidades entre programadores y artistas. Existen diferentes sistemas de coordenadas en los que pueden especicarse estas posiciones, como se puede ver en la Figura 2.2:

y py p pz z px pr x ph

h p pr r r p p

p p

Coordenadas Cartesianas

Coordenadas Cilndricas

Coordenadas Esfricas

Figura 2.2: Representacin de un punto empleando diferentes sistemas de coordenadas.

Mano Izquierda

z
Coordenadas Cartesianas. Es sin duda el sistema de coordenadas ms habitual. Este sistema de coordenadas dene ejes perpediculares para especicar la posicin del punto en el espacio. Como se muestra en la gura 2.3, existen dos convenios para la denicin de los ejes de coordenadas cartesianas; segn la regla de la mano derecha o de la mano izquierda. Es muy sencillo convertir entre ambos convenios; basta con invertir el valor del eje que cambia. Coordenadas Cilndricas. En este sistema se utiliza un eje vertical para denir la altura h, un eje radial r que mide la distancia con ese eje h, y un ngulo de rotacin denido en la circunferencia sobre ese radio. Coordenadas Esfricas. Este sistema emplea dos ngulos y , y una distancia radial r.

x y
Mano Derecha

Figura 2.3: Convenios para establecer los sistemas de coordenadas cartesianas.

2.1. Puntos, Vectores y Coordenadas

[31]

Coordenadas en OGRE. OGRE utiliza el convenio de la mano derecha. El pulgar (eje positivo X ) y el ndice (eje positivo Y ) denen el plano de la pantalla. El pulgar apunta hacia la derecha de la pantalla, y el ndice hacia el techo. El anular dene el eje positivo de las Z , saliendo de la pantalla hacia el observador.

2.1.2. Vectores
Un vector es una tupla n-dimensional que tiene una longitud (denominada mdulo ), una direccin y un sentido. Puede ser representado mediante una echa. Dos vectores son iguales si tienen la misma longitud, direccin y sentido. Los vectores son entidades libres que no estn ancladas a ninguna posicin en el espacio.
Convenio en OGRE
En OGRE se utilizan las clases Vector2 y Vector3 para trabajar indistintamente con puntos y vectores en 2 y 3 dimensiones.

Como en algn momento es necesario representar los vectores como tuplas de nmeros en nuestros programas, en muchas bibliotecas se emplea la misma clase Vector para representar puntos y vectores en el espacio. Es imprescindible que el programador distinga en cada momento con qu tipo de entidad est trabajando. A continuacin describiremos brevemente algunas de las operaciones habituales realizadas con vectores. Suma y resta de vectores La suma de vectores se puede realizar grcamente empleando la regla del paralelogramo, de modo de la suma puede calcularse como el resultado de unir el inicio del primero con el nal del segundo (situando el segundo a continuacin del primero). La suma, al igual que con nmeros reales es conmutativa. El vector suma grcamente completa el tringulo (ver Figura 2.4). Dado un vector a, el vector a tiene el mismo mdulo y direccin que a, pero sentido contrario. La resta de un vector con otro puede igualmente representarse mediante un paralelogramo. En el diagrama de la Figura 2.4, puede verse cmo efectivamente la resta del vector b a puede verse como la suma de (b a) + a, como hemos indicado anteriormente. El resultado de multiplicar un vector a por un valor escalar obtiene como resultado un vector con la misma direccin y sentido, pero con el mdulo escalado al factor por el que se ha multiplicado. Grcamente, la operacin de multiplicacin puede verse como el efecto de estirar del vector manteniendo su direccin y sentido.

[32]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

Las operaciones de suma y resta, multiplicacin por un escalar e inversin, se realizan componente a componente del vector: a + b = [(ax + bx ), (ay + by ), (az + bz )] a b = [(ax bx ), (ay by ), (az bz )] n a = (n ax , n ay , n az ) a = ( ax , ay , az ) Recordemos que, la suma de dos vectores da como resultado un vector, mientras que la suma de un punto y un vector se interpreta como la obtencin del punto destino de aplicar la transformacin del vector sobre el punto. La resta de dos puntos (pb pa ) da como resultado un vector, con mdulo igual a la distancia existente entre ambos puntos, la direccin de la recta que pasa por ambos puntos y el sentido de ir del punto pa a pb . Mdulo y normalizacin

a b

b a+
a

c
d c-d a -a e e

El mdulo de un vector es un valor escalar que representa la longitud del mismo. Puede calcularse como: | a| =
2 2 a2 x + ay + az

2e
Figura 2.4: Representacin de algunas operaciones con vectores. Comenzando por arriba: suma y resta de vectores, inversin y multiplicacin por escalar.

Si dividimos un vector por su longitud (es decir, escalamos el vector a por el factor 1/|a|), obtenemos como resultado un vector con la misma direccin y sentido, pero de mdulo la unidad (vector unitario ). Esta operacin se denomina normalizacin, y da como resultado un vector normalizado que se emplea en gran cantidad de algoritmos en programacin de videojuegos. aN = a | a|

Los vectores pueden multiplicarse entre s, pero a diferencia de los escalares, admiten dos operaciones de multiplicacin; el producto escalar (que da como resultado un escalar), y el producto vectorial (que lgicamente da como resultado otro vector). Veamos a continuacin cmo se denen estas dos operaciones y algunas de sus aplicaciones prcticas. Producto Escalar El producto escalar (dot product ) es conmutativo (a b = b a), y se calcula como: a b = a x bx + a y b y + a z b z (2.1) Tambin puede ser calculado mediante la siguiente expresin que relaciona el ngulo que forman ambos vectores. a b = |a| |b| cos() (2.2)

2.1. Puntos, Vectores y Coordenadas

[33]

a
a b

Combinando las expresiones 2.1 y 2.2, puede calcularse el ngulo que forman dos vectores (operacin muy utilizada en informtica grca).

Otra operacin muy til es el clculo de la proyeccin de un vector sobre otro, que se dene a b como la longitud del vector a que se proyecta mediante un ngulo recto sobre el vector b (ver Figura 2.5). a b = |a| cos() = ab | b|

Figura 2.5: La proyeccin de a sobre b obtiene como resultado un escalar.

a ab>0 b a ab=0 b a

El producto escalar se emplea adems para detectar si dos vectores tienen la misma direccin, o si son perpendiculares, o si tienen la misma direccin o direcciones opuestas (para, por ejemplo, eliminar geometra que no debe ser representada). Colineal. Dos vectores son colineales si se encuentran denidos en la misma lnea recta. Si normalizamos ambos vectores, y aplicamos el producto escalar podemos saber si son colineales con el mismo sentido (a b = 1) o sentido opuesto (a b = 1). Perpendicular. Dos vectores son perpendiculares si el ngulo que forman entre ellos es 90 (o 270), por lo que a b = 0. Misma direccin. Si el ngulo que forman entre ambos vectores est entre 270 y 90 grados, por lo que a b > 0 (ver Figura 2.6). Direccin Opuesta . Si el ngulo que forman entre ambos vectores es mayor que 90 grados y menor que 270, por lo que a b < 0. Esta interpretacin de misma direccin y direccin opuesta no es literal. Nos servir para comprobar si el vector normal de una cara poligonal est de frente a la cmara virtual (si tiene direccin opuesta al vector look ) de la cmara, o por el contrario est siendo visto de espaldas. Producto Vectorial Mediante el producto vectorial (cross product ) de dos vectores se obtiene otro vector que es perpendicular a los dos vectores originales. a b = [(ay bz az by ), (az bx ax bz ), (ax by ay bx )] El sentido del vector resultado del producto escalar sigue la regla de la mano derecha (ver Figura 2.7): si agarramos a b con la palma de la mano, el pulgar apunta en el sentido positivo del vector producto si el giro del resto de los dedos va de a a b. En caso contrario, el sentido del vector es el inverso. Por tanto, el producto vectorial no es conmutativo. El mdulo del producto vectorial est directamente relacionado con el ngulo que forman ambos vectores . Adems, el mdulo del producto vectorial de dos vectores es igual al rea del paralelogramo formado por ambos vectores (ver Figura 2.7).

ab<0

Figura 2.6: Algunos ejemplos de uso del producto escalar.

[34]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

|a b| = |a| |b| sin El producto vectorial se utiliza en gran cantidad de situaciones. El clculo del vector perpendicular a dos vectores es til para calcular el vector normal asociado a un tringulo (habitualmente se devuelve normalizado para su posterior utilizacin en la etapa de shading).

axb

Ms Mates?, S!! Existen multitud de objetos matemticos empleados en grcos interactivos, como rayos, planos, segmentos, as como estructuras de datos para la aceleracin de los clculos. Estos elementos sern estudiados en cada seccin que haga uso de ellos.

A continuacin describiremos las transformaciones geomtricas ms comunes empleadas en grcos por computador. Para introducir los conceptos generales asociados a las transformaciones, comenzaremos con una discusin sobre las operaciones en 2D para pasar a la notacin matricial 2D y, posteriormente, a la generalizacin tridimensional empleando coordenadas homogeneas.

Figura 2.7: Representacin del produto vectorial. El mdulo del producto vectorial a b es igual al rea del paralelogramo representado en la gura.

y p

p'

2.2.

Transformaciones Geomtricas

x
En la representacin de grcos 3D es necesario contar con herramientas para la transformacin de los objetos bsicos que compondrn la escena. En grcos interactivos, estas primitivas son habitualmente conjuntos de tringulos que denen mallas poligonales. Las operaciones que se aplican a estos tringulos para cambiar su posicin, orientacin y tamao se denominan transformaciones geomtricas. En general podemos decir que una transformacin toma como entrada elementos como vrtices y vectores y los convierte de alguna manera. La transformacin bsica bidimensional ms sencilla es la traslacin. Se realiza la traslacin de un punto mediante la suma de un vector de desplazamiento a las coordenadas iniciales del punto, para obtener una nueva posicin de coordenadas. Si aplicamos esta traslacin a todos los puntos del objeto, estaramos desplazando ese objeto de una posicin a otra. De este modo, podemos denir la traslacin como la suma de un vector libre de traslacin t a un punto original p para obtener el punto trasladado p (ver Figura 2.8). Podemos expresar la operacin anterior como: p x = px + tx p y = py + t y (2.3)

x
Figura 2.8: Arriba. Traslacin de un punto p a p empleando el vector t. Abajo. Es posible trasladar un objeto poligonal completo aplicando la traslacin a todos sus vrtices.

2.2. Transformaciones Geomtricas

[35]

De igual modo podemos expresar una rotacin de un punto p = (x, y ) a una nueva posicin rotando un ngulo respecto del origen de coordenadas, especicando el eje de rotacin y un ngulo . Las coordenadas iniciales del punto se pueden expresar como (ver Figura 2.9): px = d cos py = d sen (2.4)

p'

d d

p x

Siendo d la distancia entre el punto y el origen del sistema de coordenadas. As, usando identidades trigonomtricas se pueden expresar las coordenadas transformadas como la suma de los ngulos del punto original y el que queremos rotar como: p x = d cos( + ) = d cos cos d sen sen p y = d sen( + ) = d cos sen d sen cos Que sustituyendo en la ecuacin 2.4, obtenemos: p x = px cos py sen p y = px sin py cos (2.5)

Figura 2.9: Rotacin del punto p un ngulo respecto del origen de coordenadas.

y p p' x

De forma similar, un cambio de escala de un objeto bidimensional puede llevarse a cabo multiplicando las componentes x, y del objeto por el factor de escala Sx , Sy en cada eje. As, como se muestra en la Figura 2.10 un cambio de escala se puede expresar como: p x = px S x p y = py S y (2.6)

Figura 2.10: Conversin de un cuadrado a un rectngulo empleando los factores de escala Sx = 2, Sy = 1,5.

Cuando queremos cambiar la localizacin de un objeto, habitualmente necesitamos especicar una combinacin de traslaciones y rotaciones en el mismo (por ejemplo, cuando cogemos el telfono mvil de encima de la mesa y nos lo guardamos en el bolsillo, sobre el objeto se aplican varias traslaciones y rotaciones). Es interesante por tanto disponer de alguna representacin que nos permita combinar transformaciones de una forma eciente.

2.2.1. Representacin Matricial


Homogenezate!!
Gracias al uso de coordenadas homogneas es posible representar las ecuaciones de transformacin geomtricas como multiplicacin de matrices, que es el mtodo estndar en grcos por computador (soportado en hardware por las tarjetas aceleradoras grcas).

En muchas aplicaciones grcas los objetos deben transformarse geomtricamente de forma constante (por ejemplo, en el caso de una animacin, en la que en cada frame el objeto debe cambiar de posicin. En el mbito de los videojuegos, es habitual que aunque un objeto permanezca inmvil, es necesario cambiar la posicin de la cmara virtual para que se ajuste a la interaccin con el jugador. De este modo resulta crtica la eciencia en la realizacin de estas transformaciones. Como hemos visto en la seccin anterior, las ecuaciones 2.3, 2.5 y 2.6 nos describan las operaciones de traslacin, rotacin y escalado. Para la primera es necesario realizar una suma, mientras que las dos ltimas requieren multiplicaciones. Sera conveniente poder combinar las transformaciones de forma que la posicin nal de las coordenadas de cada punto se obtenga de forma directa a partir de las coordenadas iniciales.

[36]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

Si reformulamos la escritura de estas ecuaciones para que todas las operaciones se realicen multiplicando, podramos conseguir homogeneizar estas transformaciones. Si aadimos un trmino extra (parmetro homogneo h) a la representacin del punto en el espacio (x, y ), obtendremos la representacin homognea de la posicin descrita como (xh , yh , h). Este parmetro homogneo h es un valor distinto de cero tal que x = xh /h, y = yh /h. Existen, por tanto innitas representaciones homogneas equivalentes de cada par de coordenadas, aunque se utiliza normalmente h = 1. Como veremos en la seccin 2.3, no siempre el parmetro h es igual a uno. De este modo, la operacin de traslacin, que hemos visto anteriormente, puede expresarse de forma matricial como: x 1 0 y = 0 1 1 0 0 Tx x Ty y 1 1
Puntos y Vectores
En el caso de puntos, la componente homognea h = 1. Los vectores emplean como parmetro h = 0.

(2.7)

Al resolver la multiplicacin matricial se obtienen un conjunto de ecuaciones equivalentes a las enunciadas en 2.3. De forma anloga, las operaciones de rotacin Tr y escalado Ts tienen su equivalente matricial homogneo.

y
cos Tr = sen 0 sen cos 0 0 0 1 Sx Ts = 0 0 0 Sy 0 0 0 1 (2.8)

Las transformaciones inversas pueden realizarse sencillamente cambiando el signo en el caso de la traslacin y rotacin (distancias y ngulos negativos), y en el caso de la escala, utilizando los valores 1/Sx y 1/Sy . Las transformaciones en el espacio 3D requieren simplemente aadir el parmetro homogneo y describir las matrices (en este caso 4x4). As, las traslaciones Tt y escalados Ts en 3D pueden representarse de forma homognea mediante las siguientes matrices: 1 0 Tt = 0 0 0 1 0 0 0 0 1 0 Tx Ty Tz 1 Sx 0 Ts = 0 0 0 Sy 0 0 0 0 Sz 0 0 0 0 1

Figura 2.11: Sentido de las rotaciones positivas respecto de cada eje de coordenadas.

(2.9)

Las rotaciones requieren distinguir el eje sobre el que se realizar la rotacin. Las rotaciones positivas alrededor de un eje se realizan en sentido opuesto a las agujas del reloj, cuando se est mirando a lo largo de la mitad positiva del eje hacia el origen del sistema de coordenadas (ver Figura 2.11).

2.2. Transformaciones Geomtricas

[37]

Las expresiones matriciales de las rotaciones son las siguientes: 1 0 0 cos Rx = 0 sen 0 0 0 sen cos 0 0 0 0 1 cos 0 Ry = sen 0 0 sen 1 0 0 cos 0 0 0 0 0 1 cos sen Rz = 0 0 sen cos 0 0 0 0 1 0 0 0 0 1

(2.10)

Las tres transformaciones estudiadas (traslacin, rotacin y escalado) son ejemplos de transformaciones anes, en las que cada una de las coordenadas transformadas se pueden expresar como una funcin lineal de la posicin origen, y una serie de constantes determinadas por el tipo de transformacin.

Afines Lineales
Escalado

C. Rg.
Traslacin Rotacin

Una subclase de las transformaciones anes, es la formada por las transformaciones lineales, que permiten aplicar todas las transformaciones mediante multiplicaciones. Como hemos visto anteriormente, las traslacin anes no homognea no es una operacin lineal (porque no puede realizarse mediante una multiplicacin). Las transformaciones anes mantienen la mayora de las propiedades de los objetos, excepto los ngulos y las distancias. Aplicando transformaciones anes se mantiene la colineridad (ver Tabla 2.1), por lo que las lneas paralelas seguirn siendo paralelas. Como caso particular de estudio, las transformaciones de cuerpo rgido preservan todas las propiedades geomtricas de los objetos. Cualquier combinacin de rotaciones y traslaciones homogneas son transformaciones de cuerpo rgido.
Cuadro 2.1: Propiedades geomtricas preservadas segn la clase de transformacin: Transformaciones anes, Lineales y de Cuerpo Rgido.

Figura 2.12: Esquema de subclases de transformaciones anes y operaciones asociadas.

Propiedad ngulos Distancias Ratios de distancias Lneas paralelas Lneas rectas

T. Anes No No S S S

T. Lineales No No S S S

T. Cuerpo Rgido S S S S S

2.2.2. Transformaciones Inversas


En muchas situaciones resulta interesante calcular la inversa de una matriz. Un ejemplo tpico es en la resolucin de ecuaciones, como en el caso de la expresin A = Bx. Si queremos obtener el valor de B , tendramos B = A/x. Por desgracia, las matrices no tienen asociado un operador de divisin, por lo que debemos usar el concepto de matriz inversa.

[38]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

Para una matriz A, se dene su inversa A1 como la matriz que, multiplicada por A da como resultado la matriz identidad I : A A1 = A1 A = I (2.11)
Matrices Inversas
No todas las matrices tienen inversa (incluso siendo cuadradas). Un caso muy simple es una matriz cuadrada cuyos elementos son cero.

Tanto la matriz A como su inversa deben ser cuadradas y del mismo tamao. Otra propiedad interesante de la inversa es que la inversa de la inversa de una matriz es igual a la matriz original (A1 )1 = A. En la ecuacin inicial, podemos resolver el sistema utilizando la matriz inversa. Si partimos de A = B x, podemos multiplicar ambos trminos a la izquierda por la inversa de B , teniendo B 1 A = B 1 B x, de forma que obtenemos la matriz identidad B 1 A = I x, con el resultado nal de B 1 A = x. En algunos casos el clculo de la matriz inversa es directo, y puede obtenerse de forma intuitiva. Por ejemplo, en el caso de una traslacin pura (ver ecuacin 2.9), basta con emplear como factor de traslacin el mismo valor en negativo. En el caso de escalado, como hemos visto bastar con utilizar 1/S como factor de escala. Cuando se trabaja con matrices compuestas, el clculo de la inversa tiene que realizarse con mtodos generales, como por ejemplo el mtodo de eliminacin de Gauss o la traspuesta de la matriz adjunta.

2.2.3. Composicin
Como hemos visto en la seccin anterior, una de las principales ventajas derivadas del trabajo con sistemas homogneos es la composicin de matrices. Matemticamente esta composicin se realiza multiplicando las matrices en un orden determinado, de forma que es posible obtener la denominada matriz de transformacin neta MN resultante de realizar sucesivas transformaciones a los puntos. De este modo, bastar con multiplicar la MN a cada punto del modelo para obtener directamente su posicin nal. Por ejemplo, si P es el punto original y P es el punto transformado, y T1 Tn son transformaciones (rotaciones, escalados, traslaciones) que se aplican al punto P , podemos expresar la transformacin neta como: P = Tn T2 T1 P Este orden de multiplicacin de matrices es el habitual empleado en grcos por computador, donde las transformaciones se premultiplican (la primera est ms cerca del punto original P , ms a la derecha. La matriz de transformacin neta MN se denira como MN = Tn T2 T1 , de tal forma que slo habra que calcularla una vez para todos los puntos del modelo y aplicarla a todos vrtices en su posicin original para obtener su posicin nal. De este modo, si un objeto poligonal est formado por V vrtices, habr que calcular la matriz de transformacin neta MN y aplicarla una vez a cada vrtice del modelo. P = MN P
Figura 2.13: El formato de la matriz de transformacin neta permite identicar la posicin nal del objeto (traslacin) en la cuarta columna Px Py Pz . La matriz 3 3 interior combina las rotaciones y escalados que se aplicarn al objeto.

2.3. Perspectiva: Representacin Matricial

[39]

T(-p)

Rz()

T(p)

y x x

Figura 2.14: Secuencia de operaciones necesarias para rotar una gura respecto de un origen arbitrario.

Conmutatividad. Recordemos que la multiplicacin de matrices es asociativa, pero no es conmutativa, por lo que el orden de aplicacin de las transformaciones es importante (ver Figura 2.16). La propiedad asociativa se utiliza para resumir en la Matriz de Transformacin Neta la secuencia de transformaciones que se aplicarn sobre los modelos. De este modo, bastar con multiplicar una nica matriz todos los vrtices del modelo.

Otro aspecto a tener en cuenta es que la expresin de las transformaciones para trabajar con coordenadas homogeneas, que se han comentado en las ecuaciones 2.9 y 2.10 se reeren al Sistema de Referencia Universal (SRU ) o Sistema de Referencia Global.

y x

Esto implica que si se quiere realizar una transformacin respecto de un punto distinto a ese origen del sistema de referencia universal, habr que hacer coincidir primero el punto con el origen del sistema de referencia, aplicar la transformacin y devolver el objeto a su posicin original. As, en el ejemplo de la Figura 2.14 si queremos rotar el objeto respecto del punto p es necesario, primero trasladar el objeto para que su origen quede situado en el origen del SRU, luego aplicar la rotacin, y nalmente aplicar la traslacin inversa. De este modo, la Matriz Neta quedara denida como MN = Tp Rz Tp .

Figura 2.15: Resultado de aplicar directamente la rotacin Rz () respecto del SRU. Puede comprobarse el diferente resultado obtenido en comparacin con el de la gura 2.14.

2.3.

Perspectiva: Representacin Matricial

Como vimos en la seccin 1.2.4, en la proyeccin en perspectiva se tomaban como entrada las coordenadas de visualizacin, generando la proyeccin de los objetos sobre el plano de imagen. Vimos en la Figura 1.9 que, empleando tringulos semejantes, obtenamos las siguientes coordenadas: d p x = px pz p x = d px pz (2.12)

[40]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

y
Rz(/4)

y
Sx(2)

y
Sx(2)

y
Rz(/4)

Figura 2.16: La multiplicacin de matrices no es conmutativa, por lo que el orden de aplicacin de las transformaciones es relevante para el resultado nal. Por ejemplo, la gura de arriba primero aplica una rotacin y luego el escalado, mientras que la secuencia inferior aplica las transformaciones en orden inverso.

De igual forma obtenemos la coordenada p y = d py /pz , y pz = d. Estas ecuaciones se pueden expresar fcilmente de forma matricial como se muestra en la siguiente expresin (siendo Mp la matriz de proyeccin en perspectiva).

1 0 p = Mp p = 0 0

0 1 0 0

0 0 1 1/d

0 px px d px /pz 0 py py d py /pz = = 0 pz pz d 0 1 pz /d 1

(2.13)

El ltimo paso de la ecuacin 2.13 corresponde con la normalizacin de los componentes dividiendo por el parmetro homogneo h = pz /d. De esta forma tenemos la matriz de proyeccin que nos aplasta los vrtices de la geometra sobre el plano de proyeccin. Desafortunadamente esta operacin no puede deshacerse (no tiene inversa). La geometra una vez aplastada ha perdido la informacin sobre su componente de profundidad. Es interesante obtener una trasnformacin en perspectiva que proyecte los vrtices sobre el cubo unitario descrito previamente (y que s puede deshacerse). De esta forma, denimos la pirmide de visualizacin o frustum, como la pirmide truncada por un plano paralelo a la base que dene los objetos de la escena que sern representados. Esta pirmide de

2.4. Cuaternios

[41] visualizacin queda denida por cuatro vrtices que denen el plano de proyeccin (left l, right r, top t y bottom b), y dos distancias a los planos de recorte (near n y far f ), como se representa en la Figura 2.17. El ngulo de visin de la cmara viene determinado por el ngulo que forman l y r (en horizontal) y entre t y b (en vertical).

Y
top
left

botto m

right

Mp

near far

Figura 2.17: La matriz Mp se encarga de transformar la pirmide de visualizacin en el cubo unitario.

Denicin near y far


Un error comn suele ser que la denicin correcta de los planos near y far nicamente sirve para limitar la geometra que ser representada en el Frustum. La denicin correcta de estos parmetros es imprescindible para evitar errores de precisin en el Z-Buffer.

La matriz que transforma el frustum en el cubo unitario viene dada por la expresin de la ecuacin 2.14.
2n r l

0
2n t b

0 Mp = 0 0

r +l r l t+b t b f +n f n

0 0 0

0 0

2f n f n

(2.14)

Si se usa este tipo de proyeccin, el valor de profundidad normalizado no cambia linealmente con la entrada, sino que se va perdiendo precisin. Es recomendable situar los planos de recorte cercano y lejano (distancias n y f en la matriz) lo ms juntos posibles para evitar errores de precisin en el Z-Buffer en distancias grandes.

2.4.

Cuaternios

Los cuaternios (quaternion ) fueron propuestos en 1843 por William R. Hamilton como extensin de los nmeros complejos. Los cuaternios se representan mediante una 4-tupla q = [qx , qy , qz , qw ]. El trmino qw puede verse como un trmino escalar que se aade a los tres trminos que denen un vector (qx , qy , qz ). As, es comn representar el cuaternio como q = [qv , qs ] siendo qv = (qx , qy , qz ) y qs = qw en la tupla de cuatro elementos inicial.
Figura 2.18: Representacin de un cuaternio unitario.
2 Los cuaternios unitarios, que cumplen la restriccin de que (qx + 2 2 + qz + qw ) = 1, se emplean ampliamente para representar rotaciones en el espacio 3D. El conjunto de todos los cuaternios unitarios denen la hiperesfera unitaria en R4 . 2 qy

[42]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

z
a) b)

z
c)

z
d)

x y y

x y

x y

Figura 2.19: El problema del bloqueo de ejes (Gimbal Lock). En a) se muestra el convenio de sistema de coordenadas que utilizaremos, junto con las elipses de rotacin asociadas a cada eje. En b) aplicamos una rotacin respecto de x, y se muestra el resultado en el objeto. El resultado de aplicar una rotacin de 90o en y se muestra en c). En esta nueva posicin cabe destacar que, por el orden elegido de aplicacin de las rotaciones, ahora el eje x y el eje z estn alineados, perdiendo un grado de libertad en la rotacin. En d) se muestra cmo una rotacin en z tiene el mismo efecto que una rotacin en x, debido al efecto de Gimbal Lock.

Si denimos como a al vector unitario que dene el eje de rotacin, como el ngulo de rotacin sobre ese eje empleando la regla de la mano derecha (si el pulgar apunta en la direccin de a, las rotaciones positivas se denen siguiendo la direccin de los dedos curvados de la mano), podemos describir el cuaternio como (ver Figura 2.18):
Teorema de Euler

q = [qv , qs ] = [a sin(/2), cos(/2)] De forma que la parte vectorial se calcula escalando el vector de direccin unitario por el seno de /2, y la parte escalar como el coseno de /2. Obviamente, esta multiplicacin en la parte vectorial se realiza componente a componente. Como hemos visto en la seccin 2.2.1, es posible utilizar una matriz para resumir cualquier secuencia de rotaciones en el espacio 3D. Sin embargo, las matrices no son la mejor forma de representar rotaciones, por las siguientes razones: 1. Almacenamiento. La representacin mediante matrices require nueve valores de punto otante para almacenar una rotacin. Segn el Teorema de Rotacin de Euler es suciente con establecer la rotacin frente a un nico eje (el Polo de Euler). 2. Tiempo de Cmputo. En la composicin de la matriz con un vector, se necesitan calcular nueve multiplicaciones y seis sumas en punto otante. 3. Interpolacin. En muchas ocasiones es necesario calcular valores intermedios entre dos puntos conocidos. En el caso de rotaciones, es necesario calcular los valores de rotacin intermedios entre dos rotaciones clave (en la animacin de la rotacin de una cmara virtual, o en las articulaciones de un personaje animado). La interpolacin empleando matrices es muy complicada.

Segn el Teorema de Rotacin de Leonhard Euler (1776), cualquier composicin de rotaciones sobre un slido rgido es equivalente a una sola rotacin sobre un eje, llamado Polo de Euler.

Figura 2.20: Los cuaternios unitarios pueden ser representados como puntos sobre la esfera unitaria. La interpolacin esfrica lineal entre dos cuaternios p y q se puede igualmente representar como un arco sobre la esfera..

2.4. Cuaternios

[43] 4. Bloque de Ejes. El problema del bloqueo de ejes (denominado Gimbal Lock ) ocurre cuando se trabaja con ngulos de Euler. Como hemos visto, cualquier rotacin se puede descomponer en una secuencia de tres rotaciones bsicas sobre cada uno de los ejes. Como hemos visto, el orden de aplicacin de las rotaciones importa (no es conmutativo), por lo que tendremos que decidir uno. Por ejemplo, podemos aplicar primero la rotacin en x, a continuacin en y y nalmente en z . El orden de las rotaciones es relevante porque rotaciones posteriores tienen inuencia jerrquica sobre las siguientes. El problema de Gimbal Lock ocurre cuando, por accidente uno de los ejes queda alineado con otro, reduciendo los grados de libertad del objeto. En el ejemplo de la Figura 2.19, tras aplicar la rotacin de 90o sobre el eje y en c), el eje x sufre la misma transformacin (por arrastrar la rotacin en y por jerarqua), de modo que queda alineado con Z. Ahora, la rotacin en z equivale a la rotacin en x, por lo que hemos perdido un grado de libertad. De este modo, es interesante trabajar con cuaternios para la especicacin de rotaciones. Veamos a continuacin algunas de las operaciones ms comunmente utilizadas con esta potente herramienta matemtica.

2.4.1. Suma y Multiplicacin


La suma de dos cuaternios se realiza sumando la parte escalar y vectorial por separado: p + q = [(pv + qv ), (ps + qs )] La multiplicacin de dos cuaternios representa su composicin (es decir, el resultado de aplicar la rotacin de uno a continuacin del otro). Existen diferentes formas de multiplicar cuaternios. A continuacin deniremos la ms ampliamente utilizada en grcos por computador, que es la multiplicacin de Grassman : pq = [(ps qv + qs pv + pv qv ), (ps qs pv qv )] Como vemos, este tipo de multiplicacin utiliza el producto vectorial y la suma de vectores en la parte vectorial de cuaternio, y el producto escalar en la parte escalar del cuaternio.
Inversin de cuaternios
La inversa de un cuaternio es mucho ms rpida que el clculo de la inversa de una matriz cuadrada. sta es otra razn ms por la que elegir cuaternios para especicar rotaciones.

2.4.2. Inversa
En el caso de cuaternios unitarios, la inversa del cuaternio q 1 es igual al conjugado q . El conjugado se calcula simplemente negando la parte vectorial, por lo que, trabajando con cuaternios unitarios, podemos calcularlos simplemente como: q 1 = q = [ q v , qs ]

[44]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

La multiplicacin de un cuaternio por su inversa obtiene como resultado el escalar 1 (es decir, rotacin 0). De este modo, q q 1 = [0 0 0 1].

2.4.3. Rotacin empleando Cuaternios


Para aplicar una rotacin empleando cuaternios, primero convertimos el punto o el vector que rotaremos a cuaternio. En ambos casos, se le aplica 0 como trmino de la parte escalar. As, dado el vector v , el cuaternio correspondiente a v se calcula como v = [v 0] = [vx vy vz 0]. Una vez que tenemos expresado en formato de cuaternio el vector, para aplicar la rotacin empleando el cuaternio, primero lo premultiplicamos por q y posteriormente lo post-multiplicamos por el inverso (o el conjugado, en el caso de trabajar con cuaternios unitarios). As, el resultado de la rotacin v puede expresarse como: v = qvq 1 La concatenacin de cuaternios funciona exactamente igual que la concatenacin de matrices. Basta con multiplicar los cuaternios entre s. Si quisiramos aplicar las rotacioens de los cuaternios q1 y q2 sobre el vector v (especicado en formato de cuaternio), bastar con realizar la operacin: 1 1 v = q2 q1 v q1 q2
Asociatividad
La concatenacin de cuaternios cumple la propiedad asociativa, por lo que es posible obtener la expresin del cuaternio neto y aplicarlo a varios objetos de la escena.

Es habitual realizar conversiones entre matrices y cuaternios. OGRE incorpora llamadas a su biblioteca (ver seccin 2.6) para realizar esta operacin. Se recomienda el artculo de Gamasutra de Nick Bobic Rotating Objects Using Quaternions para profundizar en su uso.

2.5.

Interpolacin Lineal y Esfrica

Una de las operaciones ms empleadas en grcos por computador es la interpolacin. Un claro ejemplo de su uso es para calcular la posicin intermedia en una animacin de un objeto que se traslada desde un punto A, hasta un punto B . La interpolacin lineal es un mtodo para calcular valores intermedios mediante polinomios lineales. Es una de las formas ms simples de interpolacin. Habitualmente se emplea el acrnimo LERP para referirse a este tipo de interpolacin. Para obtener valores intermedios entre dos puntos A y B , habitualmente se calcula el vector v = B A con origen en A y destino en B .

6 5 4 3 2 1

B v A
1 2 3 4 5 6 7

Figura 2.21: Ejemplo de interpolacin lineal entre dos puntos. Se han marcado sobre el vector v los puntos correspondientes a t = 0, 25, t = 0,5 y t = 0,75.

2.6. El Mdulo Math en OGRE

[45]

SLERP (p,q, t=0.5) (0.816, 0, 0.408, 0.408)

cuaternio q (0.707, 0, 0.707, 0)

z y y x
cuaternio p (0.707, 0, 0, 0.707)

y x x

Figura 2.22: Ejemplo de aplicacin de interpolacin esfrica SLERP en la rotacin de dos cuaternios p y q sobre un objeto.

Para calcular valores intermedios, se utiliza una representacin paramtrica, de forma que, modicando el valor de t (0, 1), obtenemos puntos intermedios: LERP (A, B, u) = A + vt Como podemos ver en el ejemplo de la Figura 2.21, para t = 0,25 tenemos que v = (6, 4), por lo que v 0,25 = (1,5, 1). As, LERP (A, B, 0,25) = (1, 2) + (1,5, 1) = (2,5, 3). Como se enunci en la seccin 2.4, una de las ventajas del uso de cuaternios es la relativa a la facilidad de realizar interpolacin entre ellos. La Interpolacin Lineal Esfrica (tambin llamada slerp de Spherical Linear Interpolation ) es una operacin que, dados dos cuaternios y un parmetro t (0, 1), calcula un cuaternio interpolado entre ambos, mediante la siguiente expresin: SLERP (p, q, t) = sin((1 t)) sin(t) p+ q sin() sin()

Siendo el ngulo que forman los dos cuaternios unitarios.


Documentacin...
Recordemos que en distribuciones de GNU/Linux basadas en Debian, puedes encontrar la documentacin de OGRE en local en

2.6.

El Mdulo Math en OGRE

/usr/share/doc/ogre-doc.

La biblioteca de clases de OGRE proporciona una amplia gama de funciones matemticas para trabajar con matrices, vectores, cuaternios y otras entidades matemticas como planos, rayos, esferas, polgonos, etc... La documentacin relativa a todas estas clases se encuentra en el Mdulo Math, que forma parte del ncleo (Core ) de OGRE. A continuacin se muestra un sencillo ejemplo que utiliza algunos operadores de la clase Vector3 y Quaternion.

[46]

CAPTULO 2. MATEMTICAS PARA VIDEOJUEGOS

Listado 2.1: Ejemplo de algunas clases de Math


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

cout << " Ejemplo de algunas clases de Math en OGRE " << endl; cout << "-------------------------------------------" << endl; Vector3 v1(1.0, 0.0, 0.0); Vector3 v2(0.0, 2.0, 0.0); Quaternion p(0.707107, 0.0, 0.0, 0.707107); Quaternion q(Degree(90), Vector3(0.0, 1.0, 0.0)); cout cout cout cout cout cout cout cout cout cout cout cout << << << << " " " " Vector V1 Vector V2 Cuaternio Cuaternio = = P Q " " = = << v1 << endl; << v2 << endl; " << p << endl; " << q << endl;

<< "--- Algunos operadores de Vectores ------" << endl; << " Suma: V1 + V2 = " << v1 + v2 << endl; << " Producto por escalar: V1 * 7.0 = " << v1*7.0 << endl; << " P. escalar: V1 * V2 = " << v1.dotProduct(v2) << endl; << " P. vectorial: V1 x V2 =" << v1.crossProduct(v2) << endl; << " Modulo: |V1| = " << v1.length() << endl; << " Normalizar: V2n = " << v2.normalisedCopy() << endl; << " Angulo (V1,V2)= " << v1.angleBetween(v2).valueDegrees() << endl; cout << "--- Algunos operadores de Cuaternios ----" << endl; cout << " Suma: P + Q = " << p + q << endl; cout << " Producto: P * Q = " << p * q << endl; cout << " Producto escalar: P * Q = " << p.Dot(q) << endl; cout << " SLERP(p,q,0.5)= "<< Quaternion::Slerp(0.5, p, q) << endl;

Como puede verse en el listado anterior, OGRE incorpora multitud de operadores de alto nivel para sumar, restar, multiplicar y volcar por pantalla los objetos de la clase Vector y Quaternion. Adems, OGRE facilita la creacin de objetos de estos tipos proporcionando diversos constructores. Por ejemplo, en la lnea 7 se emplea un constructor de cuaternio que permite especicar por separado el ngulo de rotacin y el vector. Algunas clases, como la clase Quaternion incorpora funciones auxiliares como el mtodo de interpolacin lineal esfrico SLERP (spherical linear interpolation). En la lnea 26 se emplea para obtener el cuaternio interpolado para t = 0,5. La Figura 2.22 muestra el resultado de este caso de aplicacin concreto. El cuaternio denido en p se corresponde con una rotacin de 90o en Z (del SRU (Sistema de Referencia Universal)), mientras que el cuaternio denido en q equivale a una rotacin de 90o en Y (del SRU). El resultado de ejecutar el cdigo del listado anterior es:
Ejemplo de algunas clases de Math en OGRE ------------------------------------------Vector V1 = Vector3(1, 0, 0) Vector V2 = Vector3(0, 2, 0) Cuaternio P = Quaternion(0.707107, 0, 0, 0.707107) Cuaternio Q = Quaternion(0.707107, 0, 0.707107, 0) --- Algunos operadores de Vectores -----Suma: V1 + V2 = Vector3(1, 2, 0) Producto por escalar: V1 * 7.0 = Vector3(7, 0, 0) Producto escalar: V1 * V2 = 0 Producto vectorial: V1 x V2 = Vector3(0, 0, 2) Modulo: |V1| = 1

2.6. El Mdulo Math en OGRE

[47]

Normalizar: V2n = Vector3(0, 1, 0) Angulo entre V1 y V2 = 90 --- Algunos operadores de Cuaternios ---Suma: P + Q = Quaternion(1.41421, 0, 0.707107, 0.707107) Producto: P * Q = Quaternion(0.5, -0.5, 0.5, 0.5) Producto escalar: P * Q = 0.5 SLERP(p,q,0.5) = Quaternion(0.816497, 0, 0.408248, 0.408248)

Captulo

Grafos de Escena
Carlos Gonzlez Morcillo

omo vimos en el captulo 1, uno de los pilares clave de cualquier motor grco es la organizacin de los elementos que se representarn en la escena. Esta gestin se realiza mediante el denominado Grafo de Escena que debe permitir inserciones, bsquedas y mtodos de ordenacin ecientes. OGRE proporciona una potente aproximacin a la gestin de los Grafos de Escena. En este captulo trabajaremos con los aspectos fundamentales de esta estructura de datos jerrquica.

3.1.

Justicacin

Como seala D. Eberly [10], el motor de despliegue grco debe dar soporte a cuatro caractersticas fundamentales, que se apoyan en el Grafo de Escena :
Test de Visibilidad
La gestin de la visibilidad de los elementos de la escena es una de las tareas tpicas que se encarga de realizar el motor grco empleando el Grafo de Escena.

1. Gestin Datos Eciente. Es necesario eliminar toda la geometra posible antes de enviarla a la GPU (Graphic Processing Unit). Aunque la denicin del Frustum y la etapa de recorte eliminan la geometra que no es visible, ambas etapas requieren tiempo de procesamiento. Es posible utilizar el conocimiento sobre el tipo de escena a representar para optimizar el envo de estas entidades a la GPU. Las relaciones entre los objetos y sus atributos se modelan empleando el Grafo de Escena. 2. Interfaz de Alto Nivel. El Grafo de Escena puede igualmente verse como un interfaz de alto nivel que se encarga de alimentar 49

[50]

CAPTULO 3. GRAFOS DE ESCENA al motor grco de bajo nivel empleando alguna API espe cica. El diseo de este interfaz de alto nivel permite abstraernos de futuros cambios necesarios en las capas dependientes del dispositivo de visualizacin.

3. Facilidad de Uso. Esta caracterstica est directamente relacionada con la anterior. El Grafo de Escena forma parte de la especicacin del middleware de despliegue grco que facilita el uso al programador nal del videojuego. De este modo, el programador se centra en la semntica asociada a la utilizacin del Grafo, dejando de lado los detalles de representacin de bajo nivel. 4. Extensibilidad. En gran cantidad de videojuegos comerciales, los equipos de trabajo de programacin frecuentemente se quejan del cambio en la especicacin de requisitos iniciales por parte del equipo artstico. Esto implica aadir soporte a nuevos tipos de geometra, efectos visuales, etc. El motor debe estar preparado para aadir los nuevos tipos sin necesidad de cambios profundos en la arquitectura. El diseo correcto del Grafo de Escena mitiga los problemas asociados con la extensibilidad y la adaptacin al cambio en los requisitos iniciales. Las estructuras de datos de Grafos de Escena suelen ser grafos que representen las relaciones jerrquicas en el despliegue de objetos compuestos. Esta dependencia espacial se modela empleando nodos que representan agregaciones de elementos (2D o 3D), as como transformaciones, procesos y otras entidades representables (sonidos, vdeos, etc...). El Grafo de Escena puede denirse como un grafo dirigido sin ciclos. Los arcos del grafo denen dependencias del nodo hijo respecto del padre, de modo que la aplicacin de una transformacin en un nodo padre hace que se aplique a todos los nodos hijo del grafo. El nodo raz habitualmente es un nodo abstracto que proporciona un punto de inicio conocido para acceder a la escena. Gracias al grafo, es posible especicar fcilmente el movimiento de escenas complejas de forma relativa a los elementos padre de la jerarqua. En la Figura 3.1, el movimento que se aplique a la Tierra (rotacin, traslacin, escalado) se aplicar a todos los objetos que dependan de ella (como por ejemplo a las Tiritas, o las Llantas de la exacavadora). A su vez, las modicaciones aplicadas sobre la Cabina se aplicarn a todos los nodos que herenden de la jerarqua, pero no al nodo Llantas o al nodo Tierra.
Tierra Tiritas Llantas

Base Codo

Cabina Llantas

Pala

Tierra

Escena

Cielo

Cabina

Base
Figura 3.1: Ejemplo de grafo asociado a la escena de la excavadora. Escena diseada por Manu Jrvinen.

3.1.1. Operaciones a Nivel de Nodo


Como seala Theoharis et al. [30], en trminos funcionales, la principal ventaja asociada a la construccin de un Grafo de Escena es que cada operacin se propaga de forma jerrquica al resto de entidades mediante el recorrido del grafo. Las principales operaciones que se realizan en cada nodo son la inicializacin, simulacin, culling y dibujado. A continuacin estudiaremos qu realiza cada operacin.

3.1. Justicacin

[51] Inicializacin. Este operador establece los valores iniciales asociados a cada entidad de la jerarqua. Es habitual que existan diferentes instancias referenciadas de las entidades asociadas a un nodo. De este modo se separan los datos estticos asociados a las entidades (denicin de la geometra, por ejemplo) y las transformaciones aplicados sobre ellos que se incluyen a nivel de nodo. Simulacin. En esta operacin se determinan los parmetros y las variables asociadas a los tipos de datos existentes en el nodo. En el caso de animaciones, se actualizan los controladores asociados para que reejen el instante de tiempo actual.

Figura 3.2: Ejemplo de estructura de datos para la gestin del culling jerrquico. En el ejemplo, el nodo referente a las Llantas (ver Figura 3.1) debe mantener la informacin de la caja lmite (Bounding Box) de todos los hijos de la jerarqua, remarcada en la imagen de la derecha.

Culling. En esta operacin se estudia la visibilidad de los elementos contenidos en los nodos. Gracias a la especicacin jerrquica del grafo, es posible podar ramas completas de la jerarqua. Para realizar esta operacin, se utilizan estructuras de datos adicionales que mantienen informacin sobre las coordenadas lmite (mximo y mnimo) asociadas a cada objeto. As, consultando estos lmites, si un nodo queda totalmente fuera de la pirmide de visualizacin (Frustum ), implicar que todos sus nodos hijo estn igualmente fuera y no ser necesario su posterior dibujado (ver Figura 3.2). Dibujado. En esta operacin se aplican los algoritmos de rendering a cada nodo de la jerarqua (comenzando por la raz, bajando hasta las hojas). Si un nodo contiene rdenes que cambien el modo de dibujado, se aplicarn igualmente a todos los nodos hijo de la jerarqua. A continuacin estudiaremos el interfaz de alto nivel que proporciona OGRE para la gestin de Grafos de Escena. Veremos las facilidades

[52]

CAPTULO 3. GRAFOS DE ESCENA

de gestin orientada a objetos, as como la abstraccin relativa a los tipos de datos encapsulados en cada nodo.
Tareas del Gestor

3.2.

El Gestor de Escenas de OGRE

Como hemos visto en la seccin anterior, el Gestor de Escenas, apoyado en el Grafo de Escena, permite optimizar los datos que se representarn nalmente, podando parte de la geometra que forma la escena. El Gestor de Escenas en OGRE se encarga de las siguientes tareas: Gestin, creacin y acceso eciente a objetos mviles, luces y cmaras. Carga y ensamblado de la geometra (esttica) del mundo 3D. Implementacin de la operacin de Culling para eliminacin de supercies no visibles. Dibujado de todos los elementos que forman la escena. Gestin y representacin de sombras dinmicas. Interfaz para realizar consultas a la escena. Estas consultas son del tipo: Qu objetos estn contenidos en una determinada regin del espacio 3D?

En este captulo nos centraremos en la parte especca de aplicacin de transformaciones a los objetos. A lo largo del mdulo estudiaremos otros aspectos relacionados con el gestor, como el tratamiento del culling o la gestin de sombras dinmicas.

3.2.1. Creacin de Objetos


La tarea ms ampliamente utilizada del Gestor de Escenas es la creacin de los objetos que formarn la escena: luces, cmaras, sistemas de partculas, etc. Cualquier elemento que forme parte de la escena ser gestionado por el Gestor de Escenas, y formar parte del Grafo de Escena. Esta gestin est directamente relacionada con el ciclo de vida completa de los objetos, desde su creacin hasta su destruccin. Los Nodos del Grafo de Escena se crean empleando el Gestor de Escena. Los nodos del grafo en OGRE tienen asignado un nico nodo padre. Cada nodo padre puede tener cero o ms hijos. Los nodos pueden adjuntarse (attach) o separarse (detach) del grafo en tiempo de ejecucin. El nodo no se destruir hasta que se le indique explcitamente al Gestor de Escenas. En la inicializacin, el Gestor de Escena se encarga de crear al menos un nodo: el Root Node. Este nodo no tiene padre, y es el padre de toda la jerarqua. Aunque es posible aplicar transformaciones a cualquier nodo de la escena (como veremos en la seccin 3.2.2), al nodo Root no se le suele aplicar ninguna transformacin y es un buen punto en el que adjuntar toda la geometra esttica de la escena. Dado el objeto SceneManager, una llamada al mtodo getRootSceneNode() nos devuelve un puntero al Root SceneNode. Este nodo es, en realidad, una variable miembro de la clase SceneManager.
Visibilidad
Si quieres que un nodo no se dibuje, simplemente ejecutas la operacin de detach y no ser renderizado.

Destruccin de nodos
La destruccin de un nodo de la escena no implica la liberacin de la memoria asignada a los objetos adjuntos al nodo. Es responsabilidad del programador liberar la memoria de esos objetos.

3.2. El Gestor de Escenas de OGRE

[53]

Root
Hijo1 Hijo11 Hijo2 Hijo12 Hijo121
Figura 3.3: Ejemplo de grafo de escena vlido en OGRE. Todos los nodos (salvo el Root ) tienen un nodo padre. Cada nodo padre tiene cero o ms hijos.

Los objetos de la escena se pueden adjuntar a cualquier nodo de la misma. En un nodo pueden existir varios objetos. Sin embargo, no es posible adjuntar la misma instancia de un objeto a varios nodos de escena al mismo tiempo. Para realizar esta operacin primero hay que separar (detach) el objeto del nodo, y posteriormente adjuntarlo (attach) a otro nodo distinto. Para crear un nodo en OGRE, se utiliza el mtodo createSceneNode, que puede recibir como parmetro el nombre del nodo. Si no se especica, OGRE internamente le asigna un nombre nico que podr ser accedido posteriormente.
MovableObject

SimpleRenderable

Entity

Light

AnimableObject

ParticleSystem

Rectangle2D

ire!ounding!o"

Frustum

ManualObject

#amera

Figura 3.4: Algunos de los tipos de objetos que pueden ser aadidos a un nodo en OGRE. La clase abstracta MovableObject dene pequeos objetos que sern aadidos (attach) al nodo de la escena.

La operacin de aadir un nodo hijo se realiza mediante la llamada al mtodo addChild(Node *child) que aade el nodo hijo previamente creado al nodo existente. La clase SceneNode es una subclase de la clase abstracta Node, denida para contener informacin sobre las transformaciones que se aplicarn a los nodos hijo. De este modo, la transformacin neta que se aplica a cada hijo es el resultado de componer las de sus padres con las suyas propias. Como hemos visto antes, los nodos de la escena contienen objetos.
OGRE dene una clase abstracta llamada MovableObject para denir

Root
myNode

todos los tipos de objetos que pueden ser aadidos a los nodos de la escena. En la Figura 3.4 se denen algunos de las principales subclases de esta clase abstracta. Para aadir un objeto a un nodo de la escena, se emplea la llamada al mtodo attachObject(MovableObject *obj). La clase Entity se emplea para la gestin de pequeos objetos mviles basados en mallas poligonales. Para la denicin del escenario (habitualmente con gran complejidad poligonal e inmvil) se emplea la clase StaticGeometry. La creacin de entidades se realiza empleando el mtodo createEntity del Gestor de Escena, indicando el nombre del modelo y el nombre que quiere asignarse a la entidad. El cdigo del siguiente listado (modicacin del Hola Mundo del ca ptulo 1) crea un nodo hijo myNode de RootSceneNode en las lneas , 3-4 y aade la entidad myEnt al nodo myChild en la lnea 6 (ver Figura 3.5). A partir de ese punto del cdigo, cualquier transformacin que se aplique sobre el nodo myNode se aplicarn a la entidad myEnt.

myEnt
Figura 3.5: Jerarqua obtenida en el grafo de escena asociado al listado de ejemplo.

[54]

CAPTULO 3. GRAFOS DE ESCENA

Listado 3.1: Creacin de nodos


1 class SimpleExample : public ExampleApplication { 2 public : void createScene() { 3 SceneNode* node = mSceneMgr->createSceneNode("myNode"); 4 mSceneMgr->getRootSceneNode()->addChild(node); 5 Entity *myEnt = mSceneMgr->createEntity("cuboejes", "cuboejes.

mesh");
6 node->attachObject(myEnt); 7 } 8 };

3.2.2. Transformaciones 3D
Las transformaciones 3D se realizan a nivel de nodo de escena, no a nivel de objetos. En realidad en OGRE, los elementos que se mueven son los nodos, no los objetos individuales que han sido aadidos a los nodos. Como vimos en la seccin 2.1, OGRE utiliza el convenio de la mano derecha para especicar su sistema de coordenadas. Las rotaciones positivas se realizan en contra del sentido de giro de las agujas del reloj (ver Figura 2.11). Las transformaciones en el Grafo de Escena de OGRE siguen el convenio general explicado anteriormente en el captulo, de forma que se especican de forma relativa al nodo padre. La traslacin absoluta se realiza mediante la llamada al mtodo
setPosition, que admite un Vector3 o tres argumentos de tipo Real. Traslacin
La traslacin de un nodo que ya ha sido posicionado anteriormente se realiza mediante la llamada a translate.

Esta traslacin se realiza de forma relativa al nodo padre de la jerarqua. Para recuperar la traslacin relativa de un nodo con respecto a su nodo padre se puede emplear la llamada getPosition. La rotacin puede realizarse mediante diversas llamadas a mtodos. Uno de los ms sencillos es empleando las llamadas a pitch, yaw y roll que permiten especicar la rotacin (en radianes) respecto del eje X , Y y Z respectivamente. La forma ms general de aplicar una rotacin es mediante la llamada a rotate que require un eje de rotacin y un ngulo o un cuaternio como parmetro. De igual modo, la llamada a getOrientation nos devuelve la rotacin actual del nodo. El escalado anlogamente se realiza mediante la llamada al mtodo
setScale. Mediante el mtodo getScale obtenemos el factor de escala

aplicado al nodo.

3.2. El Gestor de Escenas de OGRE

[55]

y x z
node2

y x y z node1

y
Root

x z node3

node1 ent1 node3

node2 ent2 node4 ent4

a)

b)

nod e4

ent3

c)

Figura 3.6: Ejemplo de transformaciones empleando el Grafo de Escena de OGRE. a) Resultado de ejecucin del ejemplo. b) Representacin de los nodos asociados a la escena. c) Jerarqua del grafo de escena.

A continuacin veremos un cdigo que utiliza algunas de las llamadas a mtodos estudiadas anteriormente para aplicar transformaciones en 3D. El resultado de la ejecucin de dicho cdigo se muestra en la Figura 3.6.
Listado 3.2: Ejemplo de uso del Grafo de Escena
1 class SimpleExample : public ExampleApplication { 2 public : void createScene() { 3 SceneNode* node1 = mSceneMgr->createSceneNode("Node1"); 4 Entity *ent1 = mSceneMgr->createEntity("ent1", "cuboejes.mesh"); 5 node1->attachObject(ent1); 6 mSceneMgr->getRootSceneNode()->addChild(node1); 7 node1->setPosition(0,0,480); 8 node1->yaw(Degree(-45)); 9 node1->pitch(Radian(Math::PI/4.0)); 10 11 SceneNode* node2 = mSceneMgr->createSceneNode("Node2"); 12 Entity *ent2 = mSceneMgr->createEntity("ent2", "cuboejes.mesh"); 13 node2->attachObject(ent2); 14 mSceneMgr->getRootSceneNode()->addChild(node2); 15 node2->setPosition(-10,0,470); 16 17 SceneNode* node3 = mSceneMgr->createSceneNode("Node3"); 18 Entity *ent3 = mSceneMgr->createEntity("ent3", "cuboejes.mesh"); 19 node3->attachObject(ent3); 20 node1->addChild(node3); 21 node3->setPosition(5,0,0); 22 23 SceneNode* node4 = mSceneMgr->createSceneNode("Node4"); 24 Entity *ent4 = mSceneMgr->createEntity("ent4", "cuboejes.mesh"); 25 node4->attachObject(ent4); 26 node1->addChild(node4); 27 node4->setPosition(0,0,5); 28 node4->yaw(Degree(-90)); 29 } 30 };

En el listado anterior utilizan las funciones de utilidad para con se ), as como algunas constantes matemticas vertir a radianes (lnea 7 (como en la lnea 8 ).

[56]

CAPTULO 3. GRAFOS DE ESCENA

Como se observa en la Figura 3.6, se han creado 4 nodos. La transformacin incial aplicada al node1 es heredada por los nodos 3 y 4. De este modo, basta con aplicar una traslacin de 5 unidades en el eje x al nodo 3 para obtener el resultado mostrado en la Figura 3.6.b). Esta traslacin es relativa al sistema de referencia transformado del nodo padre. No ocurre lo mismo con el nodo 2, cuya posicin se especica de nuevo desde el origen del sistema de referencia universal (del nodo Root ).

Posicin de Root
Aunque es posible aplicar transformaciones al nodo Root, se desaconseja su uso. El nodo Root debe mantenerse esttico, como punto de referencia del SRU.

Los mtodos de trasnformacin de 3D, as como los relativos a la gestin de nodos cuentan con mltiples versiones sobrecargadas. Es conveniente estudiar la documentacin de la API de OGRE para emplear la versin ms interesante en cada momento.

3.2.3. Espacios de transformacin


Las transformaciones estudiadas anteriormente pueden denirse relativas a diferentes espacios de transformacin. Muchos de los mtodos explicados en la seccin anterior admiten un parmetro opcional de tipo TransformSpace que indica el espacio de transformacin relativo de la operacin. OGRE dene tres espacios de trasnformacin como un tipo enumerado Node::TransformSpace: TS_LOCAL. Sistema de coordenadas local del nodo. TS_PARENT. Sistema de coordenadas del nodo padre. TS_WORLD. Sistema de coordenadas universal del mundo. El valor por defecto de este espacio de transformacin depende de la operacin a realizar. Por ejemplo, la rotacin (ya sea mediante la llamada a rotate o a pitch, yaw o roll ) se realiza por defecto con respecto al sistema de local, mientras que la traslacin se realiza por defecto relativa al padre. Veamos en el siguiente listado un ejemplo que ilustre estos conceptos. En el listado se denen tres nodos, en el que node1 es el padre de node2 y node3 . A node 2 se le aplica una rotacin respecto del eje y en la lnea 15 . Como hemos comentado anteriormente, por defecto (si 1 no se le indica ningn parmetro adicional) se realiza sobre TS_LOCAL , que por defecto Posteriormente se aplica una traslacin en la lnea 16 se realiza relativa al sistema de coordenadas del nodo padre. Al node3
1 Especicar el valor por defecto del espacio de transformacin tiene el mismo efecto que no especicarlo. Por ejemplo, cambiar la lnea 15 del ejemplo por node2->yaw(Degree(-90), Node::TS_LOCAL); no tendra ningn efecto diferente sobre el resultado nal.

3.2. El Gestor de Escenas de OGRE

[57]

se el aplican exactamente la misma rotacin y traslacin, pero sta l tima se aplica respecto del sistema de referencia local (lnea 23 ). Como puede verse en la Figura 3.7, la entidad adjunta al node3 se representa trasladada 5 unidades respecto de su sistema de coordenadas local.
a) b)

y x z
node1

x node2

nod e3

Figura 3.7: Ejemplo de trabajo con diferentes espacios de transformacin. a) Resultado de ejecucin del ejemplo. b) Distribucin de los nodos del Grafo de Escena.

Listado 3.3: Uso de diferentes espacios de transformacin


1 class SimpleExample : public ExampleApplication { 2 public : void createScene() { 3 SceneNode* node1 = mSceneMgr->createSceneNode("Node1"); 4 Entity *ent1 = mSceneMgr->createEntity("ent1", "cuboejes.mesh"); 5 node1->attachObject(ent1); 6 mSceneMgr->getRootSceneNode()->addChild(node1); 7 node1->setPosition(0,0,480); 8 node1->yaw(Degree(-45)); // Por defecto es Node::TS_LOCAL 9 node1->pitch(Degree(45)); // Por defecto es Node::TS_LOCAL 10 11 SceneNode* node2 = mSceneMgr->createSceneNode("Node2"); 12 Entity *ent2 = mSceneMgr->createEntity("ent2", "cuboejes.mesh"); 13 node2->attachObject(ent2); 14 node1->addChild(node2); 15 node2->yaw(Degree(-90)); // Por defecto es Node::TS_LOCAL 16 node2->translate(5,0,0); // Por defecto es Node::TS_PARENT 17 18 SceneNode* node3 = mSceneMgr->createSceneNode("Node3"); 19 Entity *ent3 = mSceneMgr->createEntity("ent3", "cuboejes.mesh"); 20 node3->attachObject(ent3); 21 node1->addChild(node3); 22 node3->yaw(Degree(-90)); // Por defecto es Node::TS_LOCAL 23 node3->translate(5,0,0, Node::TS_LOCAL); // Cambiamos a LOCAL! 24 } 25 };

y x z
node1

x node2
node3

Figura 3.8: Tras aplicar la traslacin de la lnea 23, se aplica la rotacin local al node3. Ahora el objeto del node2 y node3 aparecen alineados exactamente en la misma posicin del espacio.

El orden de las operaciones resulta especialmente relevante cuando se trabaja con diferentes espacios de transformacin. Qu ocurrira por ejemplo si invertimos el orde de las lneas 21 y 22 del cdigo anterior?. En ese caso, las entidades relativas al node2 y al node3 aparecern desplegadas exactamente en el mismo lugar, como se muestra en la Figura 3.8.

Captulo

Recursos Grcos y Sistema de Archivos


Javier Alonso Albusac Jimnez Carlos Gonzlez Morcillo

E
4.1.

n este captulo se realizar un anlisis de los recursos que son necesarios en los grcos 3D, centrndose sobre todo en los formatos de especicacin y requisitos de almacenamiento. Adems, se analizarn diversos casos de estudio de formatos populares como MD2, MD3, MD5, Collada y se har especial hincapi en el formato de Ogre 3D.

Formatos de Especicacin

4.1.1. Introduccin
En la actualidad, el desarrollo de videojuegos de ltima generacin implica la manipulacin simultnea de mltiples cheros de diversa naturaleza, como son imgenes estticas (BMP (BitMaP), JPG, TGA (Truevision Graphics Adapter), PNG, ...), cheros de sonido (WAV (WAVeform), OGG, MP3 (MPEG-2 Audio Layer III)), mallas que representan la geometra de los objetos virtuales, o secuencias de vdeo (AVI (Audio Video Interleave), BIK (BINK Video), etc). Una cuestin relevante es cmo se cargan estos cheros y qu recursos son necesarios para su reproduccin, sobre todo teniendo en cuenta que la reproduccin debe realizarse en tiempo real, sin producir ningn tipo de demora que acabara con la paciencia del usuario. A la hora de disear un videojuego es muy importante tener en mente que los recursos hardware no son ilimitados. Las plataformas 59

[60]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

empleadas para su ejecucin poseen diferentes prestaciones de memoria, potencia de procesamiento, tarjeta grca, etc. No todos los usuarios que adquieren un juego estn dispuestos a mejorar las prestaciones de su equipo para poder ejecutarlo con ciertas garantas de calidad [22]. Por todo ello, es fundamental elegir los formatos adecuados para cada tipo de archivo, de tal forma que se optimice en la mayor medida de lo posible los recursos disponibles. El formato empleado para cada tipo de contenido determinar el tamao y este factor afecta directamente a uno de los recursos ms importantes en la ejecucin de un videojuego: la memoria [22]. Independientemente del tamao que pueda tener la memoria de la plataforma donde se ejecuta el videojuego, sta suele estar completa durante la ejecucin. Durante la ejecucin se producen diversos cambios de contexto, en los que se elimina el contenido actual de la memoria para incluir nuevos datos. Por ejemplo, cuando se maneja un personaje en una determinada escena y ste entra en una nueva habitacin o nivel, los datos de las escena anterior son eliminados temporalmente de la memoria para cargar los nuevos datos correspondientes al nuevo lugar en el que se encuentra el personaje protagonista. Es entonces cuando entran en juego los mecanismos que realizan el intercambio de datos y gestionan la memoria. Lgicamente, cuanto menor sea el espacio que ocupan estos datos ms sencillo y ptimo ser el intercambio en memoria. A la hora de elegir formato para cada tipo de chero siempre hay que tratar de encontrar un equilibrio entre calidad y tamao. En la mayora de videojuegos, los bits seleccionados se empaquetan y comprimen para ser ejecutados en el momento actual; a estos archivos se les conoce como cheros de recursos, los cuales contienen una amplia variedad de datos multimedia (imgenes, sonidos, mallas, mapas de nivel, vdeos, etc). Normalmente estos archivos estn asociados a un nivel del juego. En cada uno de estos niveles se denen una serie de entornos, objetos, personajes, objetivos, eventos, etc. Al cambiar de nivel, suele aparecer en la pantalla un mensaje de carga y el usuario debe esperar; el sistema lo que est haciendo en realidad es cargar el contenido de estos cheros que empaquetan diversos recursos. Cada uno de los archivos empaquetados se debe convertir en un formato adecuado que ocupe el menor nmero de recursos posible. Estas conversiones dependen en la mayora de los casos de la plataforma hardware en la que se ejecuta el juego. Por ejemplo, las plataformas PS3 y Xbox360 presentan formatos distintos para el sonido y las texturas de los objetos 3D. En la siguiente seccin se ver con mayor grado de detalle los recursos grcos 3D que son necesarios, centrndonos en los formatos y los requisitos de almacenamiento.

4.1. Formatos de Especicacin

[61]

Figura 4.1: Flujo de datos desde los archivos de recursos hasta los subsistemas que se encargan de la reproduccin de los contenidos [22].

4.1.2. Recursos de grcos 3D: formatos y requerimientos de almacenamiento


Los juegos actuales con al menos una complejidad media-alta suelen ocupar varios GigaBytes de memoria. La mayora de estos juegos constan de un conjunto de cheros cerrados con formato privado que encapsulan mltiples contenidos, los cuales estn distribuidos en varios DVDs (4.7 GB por DVD) o en un simple Blue-Ray ( 25GB) como es en el caso de los juegos vendidos para la plataforma de Sony - PS3. Si tenemos algn juego instalado en un PC, tenemos acceso a los directorios de instalacin y podemos hacernos una idea del gran tamao que ocupan una vez que los juegos han sido instalados. Lo que vamos a intentar en las siguientes secciones es hacernos una idea de cmo estos datos se almacenan, qu formatos utilizan y cmo se pueden comprimir los datos para obtener el producto nal. Por tanto, lo primero que debemos distinguir son los tipos de cheros de datos que normalmente se emplean. La siguiente clasicacin, ofrece una visin general [22]: Objetos y mallas 3D para el modelado de entornos virtuales: para el almacenamiento de este tipo de datos, normalmente son necesarias unas pocas decenas de megabytes para llevar a cabo dicha tarea. En este tipo de cheros se almacena toda la geometra asociada al videojuego.

[62]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS Mallas 3D y datos de animacin: estos datos en realidad no ocupan demasiado espacio pero suele suponer un nmero elevado de cheros, la suma de todos ellos puede ocupar varias decenas de MB tambin. Mapa/ Datos de nivel: en este tipo de archivos se almacenan disparadores de eventos (eventos que se pueden producir en un determinado escenario y asociacin de acciones a realizar una vez que se producen), Tipos de objetos del entorno, scripts, etc. No ocupan demasiado espacio al igual que el caso anterior, y suele ser bastante sencillo compactarlos o comprimirlos. Sprites (personajes) y texturas asociadas a los materiales: suele haber bastante informacin asociada a estos tipos de datos. En un juego medianamente complejo, los cheros de este tipo comienzan enseguida a ocupar bastante espacio, hablamos de cientos de megas. Sonido, msica y dilogos: suelen ser los datos que ocupan mas espacio de todo el juego, sobre todo cuando los juegos relatan una profunda y larga historia. Vdeo y escenas pre-grabadas: Cuando se usa este tipo de recursos suele ocupar la mayora de espacio, por eso se usan con moderacin. Suelen ser la combinacin de personajes animados con archivos de sonido.

En las siguientes secciones se describir con mayor detalle cada uno de los puntos anteriores. Objetos y Mallas 3D Al contrario de lo que normalmente se puede pensar, la geometra de los elementos tridimensionales que se emplean en un videojuego no ocupan demasiado espacio en comparacin con otro tipo de contenidos [22]. Como se coment en las secciones anteriores, los principales consumidores de espacio son los cheros de audio y vdeo. Una malla 3D, independientemente de que corresponda con un personaje, objeto o entorno, es una coleccin de puntos situados en el espacio, con una serie de datos asociados que describen cmo estos puntos estn organizados y forman un conjunto de polgonos y cmo stos deben ser renderizados. Por otro lado, a los puntos situados en el espacio se les llama vrtices y se representan mediante tres puntos pertenecientes a las tres coordenadas espaciales (X,Y,Z), tomando como referencia el punto de origen situado en (0,0,0). Cualquier elemento virtual se modela mediante tringulos que forman la malla, y cada tringulo se dene por medio de tres o mas ndices en una lista de puntos. Aqu se puede mostrar un ejemplo de una malla que representa un cubo. Para representar los tringulos del cubo siguiente, necesitaramos tres vrtices por tringulo y tres coordenadas por cada uno de esos

4.1. Formatos de Especicacin

[63]

vrtices. Existen diferentes formas de ahorrar espacio y optimizar la representacin de tringulos. Si se tiene en cuenta que varios tringulos tienen vrtices en comn, no es necesario representar esos vrtices ms de una vez. El mtodo consiste en representar nicamente los tres ndices del primer tringulo y, para el resto de tringulos, nicamente se aade el vrtice adicional. Esta tcnica sera similar a dibujar el cubo con un lpiz sin separar en ningn momento la punta del lpiz del papel.
Listado 4.1: Representacin de los vrtices de un cubo con respecto al origen de coordenadas
1 Vec3 TestObject::g_SquashedCubeVerts[] = 2 { 3 Vec3( 0.5,0.5,-0.25), // Vertex 0. 4 Vec3(-0.5,0.5,-0.25), // Vertex 1. 5 Vec3(-0.5,0.5,0.5), // And so on. 6 Vec3(0.75,0.5,0.5), 7 Vec3(0.75,-0.5,-0.5), 8 Vec3(-0.5,-0.5,-0.5), 9 Vec3(-0.5,-0.3,0.5), 10 Vec3(0.5,-0.3,0.5) 11 };

Listado 4.2: Representacin de los tringulos de un cubo mediante asociacin de ndices


1 WORD TestObject::g_TestObjectIndices[][3] = 2 { 3 { 0,1,2 }, { 0,2,3 }, { 0,4,5 }, 4 { 0,5,1 }, { 1,5,6 }, { 1,6,2 }, 5 { 2,6,7 }, { 2,7,3 }, { 3,7,4 }, 6 { 3,4,0 }, { 4,7,6 }, { 4,6,5 } 7 };

Con un simple cubo es complicado apreciar los benecios que se pueden obtener con esta tcnica, pero si nos paramos a pensar que un modelo 3D puede tener miles y miles de tringulos, la optimizacin es clara. De esta forma es posible almacenar n tringulos con n+2 ndices, en lugar de n*3 vrtices como sucede en el primer caso. Adems de la informacin relativa a la geometra del objeto, la mayora de formatos soporta la asociacin de informacin adicional sobre el material y textura de cada uno de los polgonos que forman el objeto. El motor de rendering asumir, a menos que se indique lo contrario, que cada grupo de tringulos tiene asociado el mismo material y las mismas texturas. El material dene el color de un objeto y como se reeja la luz en l. El tamao destinado al almacenamiento de la informacin relativa al material puede variar dependiendo del motor de rendering empleado. Si al objeto no le afecta la luz directamente y tiene un color slido, tan slo sern necesarios unos pocos de bytes extra. Pero, por el contrario, si al objeto le afecta directamente la luz y ste tiene una textura asociada, podra suponer casi 100 bytes ms por cada vrtice.

[64]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

De todo esto debemos aprender que la geometra de un objeto puede ocupar mucho menos espacio si se elige un formato adecuado para representar los tringulos que forman el objeto. De cualquier forma, los requisitos de memoria se incrementan notablemente cuando se emplean materiales complejos y se asocian texturas al objeto. Datos de Animacin Una animacin es en realidad la variacin de la posicin y la orientacin de los vrtices que forman un objeto a lo largo del tiempo. Como se coment anteriormente, una forma de representar una posicin o vrtice en el espacio es mediante tres valores reales asociados a las tres coordenadas espaciales X, Y y Z. Estos nmeros se representan siguiendo el estndar IEEE (Institute of Electrical and Electronics Engineers)-754 para la representacin de nmeros reales en coma otante mediante 32 bits (4 bytes). Por tanto, para representar una posicin 3D ser necesario emplear 12 bytes. Adems de la posicin es necesario guardar informacin relativa a la orientacin, y el tamao de las estructuras de datos empleadas para ello suele variar entre 12 y 16 bytes, dependiendo del motor de rendering. Existen diferentes formas de representar la orientacin, el mtodo elegido inuir directamente en la cantidad de bytes necesarios. Dos de los mtodos ms comunes en el desarrollo de videojuegos son los ngulos de Euler y el uso de cuaterniones o tambin llamados cuaternios. Para hacernos una idea del tamao que sera necesario en una sencilla animacin, supongamos que la frecuencia de reproduccin de frames por segundo es de 25. Por otro lado, si tenemos en cuenta que son necesarios 12 bytes por vrtice ms otros 12 (como mnimo) para almacenar la orientacin de cada vrtice, necesitaramos por cada vrtice 12 + 12 = 24 bytes por cada frame. Si en un segundo se reproducen 25 frames, 25 x 24 = 600 bytes por cada vrtice y cada segundo. Ahora supongamos que un objeto consta de 40 partes movibles (normalmente las partes movibles de un personaje las determina el esqueleto y los huesos que lo forman). Si cada parte movible necesita 600 bytes y existen 40 de ellas, se necesitara por cada segundo un total de 24.000 bytes. Naturalmente 24.000 bytes puede ser un tamao excesivo para un solo segundo y existen diferentes formas de optimizar el almacenamiento de los datos de animacin, sobre todo teniendo en cuenta que no todas las partes del objeto se mueven en cada momento y, por tanto, no sera necesario almacenarlas de nuevo. Tampoco es necesario almacenar la posicin de cada parte movible en cada uno de los 25 frames que se reproducen en un segundo. Una solucin elegante es establecer frames claves y calcular las posiciones intermedias de un vrtice desde un frame clave al siguiente mediante interpolacin lineal. Es decir, no es necesario almacenar todas las posiciones (nicamente la de los frames claves) ya que el resto pueden ser calculadas en tiempo de ejecucin.

4.1. Formatos de Especicacin

[65]

Otra posible mejora se podra obtener empleando un menor nmero de bytes para representar la posicin de un vrtice. En muchas ocasiones, el desplazamiento o el cambio de orientacin no son exageradamente elevados y no es necesario emplear 12 bytes. Si los valores no son excesivamente elevados se pueden emplear, por ejemplo, nmeros enteros de 2 bytes. Estas tcnicas de compresin pueden reducir considerablemente el tamao en memoria necesario para almacenar los datos de animacin. Mapas/Datos de Nivel Cada uno de los niveles que forman parte de un juego tiene asociado diferentes elementos como objetos estticos 3D, sonido de ambientacin, dilogos, entornos, etc. Normalmente, todos estos contenidos son empaquetados en un chero binario que suele ser de formato propietario. Una vez que el juego es instalado en nuestro equipo es complicado acceder a estos contenidos de manera individual. En cambio, durante el proceso de desarrollo estos datos se suelen almacenar en otros formatos que s son accesibles por los miembros del equipo como, por ejemplo, en formato XML (eXtensible Markup Language). El formato XML es un formato accesible, interpretable y permite a personas que trabajan con diferentes herramientas y en diferentes mbitos, disponer de un medio para intercambiar informacin de forma sencilla. Texturas Hasta el momento, los datos descritos para el almacenamiento de la geometra de los objetos, animacin y datos de nivel no suponen un porcentaje alto de la capacidad de almacenamiento requerida. Las texturas (en tercer lugar), los cheros de audio y vdeo son los que implican un mayor coste en trminos de memoria. La textura es en realidad una imagen esttica que se utiliza como piel para cubrir la supercie de un objeto virtual. Existen multitud de formatos que permiten obtener imgenes de mayor o menor calidad y, en funcin de esta calidad, de un mayor o menor tamao. Para obtener la mxima calidad, los diseadores grcos preeren formatos no comprimidos de 32 bits como TIF (TIFF) o TGA. Por contra, el tamao de estas imgenes podra ser excesivo e inuir en el tiempo de ejecucin de un videojuego. Por ejemplo, una imagen RAW (imagen sin modicaciones, sin comprimir) de 32 bits con una resolucin de 1024 x 768 pxeles podra alcanzar el tamao de 3MB. Por tanto, una vez ms es necesario encontrar un equilibrio entre calidad y tamao. Cuando se disea un videojuego, una de las principales dicultades que se plantean es la eleccin de un formato adecuado para cada uno de los recursos, tal que se satisfagan las expectativas de calidad y eciencia en tiempo de ejecucin. Uno de los parmetros caractersticos de cualquier formato de imagen es la profundidad del color [22]. La profundidad del color determina la cantidad de bits empleados para representar el color de un

[66]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

pxel en una imagen digital. Si con n bits se pueden representar 2n valores, el uso de n bits por pxel ofrecer la posibilidad de representar 2n colores distintos, es decir, cuando mayor sea el nmero n de bits empleados, mayor ser la paleta de colores disponibles. 32-bits (8888 RGBA (Red Green Blue Alpha)). Las imgenes se representan mediante cuatro canales, R(red), G(green), B(blue), A(alpha), y por cada uno de estos canales se emplean 8 bits. Es la forma menos compacta de representar un mapa de bits y la que proporciona un mayor abanico de colores. Las imgenes representadas de esta forma poseen una calidad alta, pero en muchas ocasiones es innecesaria y otros formatos podran ser ms apropiados considerando que hay que ahorrar el mayor nmero de recursos posibles. 24-bits (888 RGB (Red Green Blue)). Este formato es similar al anterior pero sin canal alpha, de esta forma se ahorran 8 bits y los 24 restantes se dividen en partes iguales para los canales R(red), G(green) y B(blue). Este formato se suele emplear en imgenes de fondo que contienen una gran cantidad de colores que no podran ser representados con 16 u 8 bits. 24-bits (565 RGB, 8A). Este formato busca un equilibrio entre los dos anteriores. Permite almacenar imgenes con una profundidad de color aceptable y un rango amplio de colores y, adems, proporciona un canal alfa que permite incluir porciones de imgenes traslcidas. El canal para el color verde tiene un bit extra debido a que el ojo humano es ms sensible a los cambios con este color. 16-bits (565 RGB). Se trata de un formato compacto que permite almacenar imgenes con diferentes variedades de colores sin canal alfa. El canal para el color verde tambin emplea un bit extra al igual que en el formato anterior. 16-bits (555 RGB, 1 A). Similar al formato anterior, excepto el bit extra del canal verde que, ahora, es destinado al canal alfa. 8-bits indexado. Este formato se suele emplear para representar iconos o imgenes que no necesitan alta calidad, debido a que la paleta o el rango de colores empleado no es demasiado amplio. Sin embargo, son imgenes muy compactas que ahorran mucho espacio en memoria y se transmiten o procesan rpidamente. En este caso, al emplearse 8 bits, la paleta sera de 256 colores y se representa de forma matricial, donde cada color tiene asociado un ndice. Precisamente los ndices son los elementos que permiten asociar el color de cada pxel en la imagen a los colores representados en la paleta de colores.
Figura 4.2: Ejemplo de una imagen RGBA con porciones transparentes (canal alpha).

Figura 4.3: Modelo aditivo de colores rojo, verde y azul.

Figura 4.4: Paleta de 256 colores con 8 bits

4.1. Formatos de Especicacin

[67]

4.1.3. Casos de Estudio


Formato MD2/MD3 El formato MD2 es uno de los ms populares por su simplicidad, sencillez de uso y versatilidad para la creacin de modelos (personajes, entornos, armas, efectos, etc). Fue creado por la compaa id Software y empleado por primera vez en el videojuego Quake II (ver Figura 4.5).

Figura 4.5: Captura del vdeojuego Quake II, desarrollado por la empresa id Software, donde se emple por primera vez el formato MD2

El formato MD2 representa la geometra de los objetos, texturas e informacin sobre la animacin de los personajes en un orden muy concreto, tal como muestra la Figura 4.6 [25]. El primer elemento en la mayora de formatos 3D es la cabecera. La cabecera se sita al comienzo del chero y es realmente til ya que contiene informacin relevante sobre el propio chero sin la necesidad de tener que buscarla a travs de la gran cantidad de datos que vienen a continuacin. Cabecera La cabecera del formato MD2 contiene los siguientes campos:
Listado 4.3: Cabecera del formato MD2
1 struct SMD2Header { 2 int m_iMagicNum; 3 int m_iVersion; 4 int m_iSkinWidthPx;

[68]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 };

int int int int int int int int int int int int int int

m_iSkinHeightPx; m_iFrameSize; m_iNumSkins; m_iNumVertices; m_iNumTexCoords; m_iNumTriangles; m_iNumGLCommands; m_iOffsetSkins; m_iOffsetTexCoords; m_iOffsetTriangles; m_iOffsetFrames; m_iOffsetGlCommands; m_iFileSize; m_iNumFrames;

Figura 4.6: Jerarqua de capas en un chero con formato MD2

El tamao total es de 68 bytes, debido a que cada uno de los enteros se representa haciendo uso de 4 bytes. A continuacin, en el siguiente listado se describir brevemente el signicado de cada uno de estos campos [25]. En primer lugar podemos apreciar un campo que se reere al "nmero mgico". Este nmero sirve para identicar el tipo de archivo y comprobar que en efecto se trata de un chero con formato MD2. Versin del chero. De esta forma se lleva a cabo un control de versiones y se evita el uso de versiones obsoletas del chero.

4.1. Formatos de Especicacin

[69] La siguiente variable hace referencia a la textura que se utiliza para cubrir la supercie del modelo. En este formato, cada modelo MD2 puede utilizar un piel o textura en un instante concreto de tiempo, aunque se podran cargar varias texturas e ir alternndolas a lo largo del tiempo. m_iSkinWidthPx y m_iSkinHeightPx representan la anchura y altura de la textura en pxeles. m_iFrameSize es un entero que representa el tamao en bytes de cada frame clave. Las seis variables siguientes se reeren a cantidades [25]: m_iNumSkins es el nmero de texturas denidas en el chero. Como se coment anteriormente, el formato no soporta la aplicacin simultnea de mltiples texturas, pero s cargar varias texturas y ser aplicadas en diferentes instantes. m_iNumVertices es un entero que representa el nmero de vrtices por frame. m_iNumTexCoords representa el nmero de coordenadas de la textura. El nmero no tiene que coincidir con el nmero de vrtices y se emplea el mismo nmero de coordenadas para todos los frames. m_iNumTriangles es el nmero de tringulos que compone el modelo. En el formato MD2, cualquier objeto est formado mediante la composicin de tringulos, no existe otro tipo de primitiva como, por ejemplo, cuadrilteros. m_iNumGLCommands especica el nmero de comandos especiales para optimizar el renderizado de la malla del objeto. Los comandos GL no tienen por qu cargar el modelo, pero s proporcionan una forma alternativa de renderizarlo. m_iNumFrames representa el nmero de frames en el chero MD2 le. Cada uno de los frames posee informacin completa sobre las posiciones de los vrtices para el proceso de animacin.

Las cinco variables siguientes se emplean para denir el offset o direccin relativa (el nmero de posiciones de memoria que se suman a una direccin base para obtener la direccin absoluta) en bytes de cada una de las partes del chero. Esta informacin es fundamental para facilitar los saltos en las distintas partes o secciones del chero durante el proceso de carga. Por ltimo, la variable m_iFileSize representa el tamao en bytes desde el inicio de la cabecera hasta el nal del chero. Frames y Vrtices A continuacin se muestra la estructura que representa la informacin que se maneja por frame en el formato MD2 [25]:

[70]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Listado 4.4: Informacin empleada en cada frame en el formato MD2


1 struct SMD2Frame { 2 float m_fScale[3]; 3 float m_fTrans[3]; 4 char m_caName[16]; 5 SMD2Vert * m_pVertss 6 7 SMD2Frame() 8 { 9 m_pVerts = 0; 10 } 11 ~SMD2Frame() 12 { 13 if(m_pVerts) delete [] m_pVerts; 14 } 15 };

Como se puede apreciar en la estructura anterior, cada frame comienza con seis nmeros representados en punto otante que representan la escala y traslacin de los vrtices en los ejes X, Y y Z. Posteriormente, se dene una cadena de 16 caracteres que determinan el nombre del frame, que puede resultar de gran utilidad si se quiere hacer referencia a ste en algn momento. Por ltimo se indica la posicin de todos los vrtices en el frame (necesario para animar el modelo 3D). En cada uno de los frames habr tantos vrtices como se indique en la variable de la cabecera m_iNumVerts. En la ltima parte de la estructura se puede diferenciar un constructor y destructor, que son necesarios para reservar y liberar memoria una vez que se ha reproducido el frame, ya que el nmero mximo de vrtices que permite almacenar el formato MD2 por frame es 2048. Si se renderizaran nicamente los vrtices de un objeto, en pantalla tan slo se veran un conjunto de puntos distribuidos en el espacio. El siguiente paso consistir en unir estos puntos para denir los tringulos y dar forma al modelo. Triangularizacin En el formato MD2 los tringulos se representan siguiendo la tcnica descrita en la Seccin 4.1.2. Cada tringulo tiene tres vrtices y varios tringulos tienen ndices en comn [25]. No es necesario representar un vrtice ms de una vez si se representa la relacin que existe entre ellos mediante el uso de ndices en una matriz. Adems, cada tringulo debe tener asociado una textura, o sera ms correcto decir, una parte o fragmento de una imagen que representa una textura. Por tanto, es necesario indicar de algn modo las coordenadas de la textura que corresponden con cada tringulo. Para asociar las coordenadas de una textura a cada tringulo se emplean el mismo nmero de ndices, es decir, cada ndice de un vrtice en el tringulo tiene asociado un ndice en el array de coordenadas de una textura. De esta forma se puede texturizar cualquier objeto fcilmente. A continuacin se muestra la estructura de datos que se poda emplear para representar los tringulos mediante asociacin de ndices en un array y la asociacin de coordenadas de la textura para cada vrtice:
Figura 4.7: Modelado de un objeto tridimensional mediante el uso de tringulos.

4.1. Formatos de Especicacin

[71]

Listado 4.5: Estructura de datos para representar los tringulos y las coordenadas de la textura
1 struct SMD2Tri { 2 unsigned short m_sVertIndices[3]; 3 unsigned short m_sTexIndices[3]; 4 };

Inclusin de Texturas En el formato MD2 existen dos formas de asociar texturas a los objetos. La primera de ellas consiste en incluir el nombre de las texturas embebidos en el chero MD2. El nmero de cheros de texturas y la localizacin, se encuentran en las variables de la cabecera m_iNumSkins y m_iOffsetSkins. Cada nombre de textura ocupa 64 caracteres alfanumricos como mximo. A continuacin se muestra la estructura de datos empleada para denir una textura [25]:
Listado 4.6: Estructura de datos para denir una textura embebida en un chero MD2
1 struct SMD2Skin 2 { 3 char m_caSkin[64]; 4 CImage m_Image; 5 };

Figura 4.8: Ejemplo de textura en la que se establece una correspondencia entre los vrtices del objeto y coordenadas de la imagen.

Tal como se puede apreciar en la estructura anterior, existe una instancia de la clase CImage. Esta clase posee varias funciones para cargar y asociar varias clases de texturas. Existe una textura diferente por cada nombre de chero que aparece en la seccin de texturas dentro del chero MD2. Una segunda alternativa es utilizar la clase CImage y el mtodo SetSkin para cargar una textura y asociarla a un objeto [25]. Si existe una correspondencia por coordenadas entre la textura y el objeto, ser necesario cargar las coordenadas antes de asociar la textura al objeto. El nmero de coordenadas de la textura se puede encontrar en la variable de la cabecera m_iNumTexCoords. La estructura de datos que se utiliza para denir las coordenadas de una textura es la siguiente:
Listado 4.7: Estructura de datos para representar las coordenadas de una textura
1 struct SMD2TexCoord { 2 float m_fTex[2]; 3 };

Cada coordenada de una textura consiste en un par de nmeros de tipo oat de 2 bytes. La primera coordenada de la textura comienza en el cero y naliza en el valor equivalente a la anchura de la imagen; la segunda desde el cero hasta el valor de la altura. En el resto de coordenadas se establecen las correspondencias entre zonas de la imagen de la textura y las supercies del objeto. Finalmente, una vez que se han denido las coordenadas ya se puede asociar la textura al objeto, mediante la funcin Bind de la clase CImage.

[72]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Principales diferencias entre el formato MD2 y MD3 El formato MD3 fue el formato que se emple en el desarrollo del videojuego Quake III y sus derivados (Q3 mods, Return to Castle Wolfenstein, Jedi Knights 2, etc.). MD3 se basa en su predecesor pero aporta mejoras notables en dos aspectos claves: Animacin de personajes. La frecuencia de reproduccin de frames en el formato MD2 est limitada a 10 fps. En el caso del formato MD3 la frecuencia es variable, permitiendo animaciones de vrtices ms complejas. Modelado de objetos 3D. Otra diferencia signicativa entre los formatos MD2 y MD3 es que en este ltimo los objetos se dividen en tres bloques diferenciados, normalmente, cabeza, torso y piernas. Cada uno de estos bloques se tratan de manera independiente y esto implica que cada parte tenga su propio conjunto de texturas y sean renderizados y animados por separado. Formato MD5 El formato MD5 se emple en el desarrollo de los videojuegos Doom III y Quake IV. El formato presenta mejoras signicativas en la animacin de personajes. En el caso de los formatos MD2 y MD3 los movimientos de cada personaje se realizaban mediante animacin de vrtices, es decir, se almacenaba la posicin de los vrtices de un personaje animado en cada frame clave. Tratar de forma individualizada cada vrtice es realmente complejo y animar un personaje siguiendo esta metodologa no es una tarea sencilla. En el formato MD5 es posible denir un esqueleto formado por un conjunto de huesos y asociarlo a un personaje. Cada uno de los huesos tiene a su vez asociado un conjunto de vrtices. La animacin en el formato MD5 se basa en la animacin de los huesos que forman el esqueleto; el grupo de vrtices asociado a un hueso variar su posicin en base al movimiento de ste. Una de las grandes ventajas de la animacin mediante movimiento de huesos de un esqueleto es que sta se puede almacenar y reutilizar para personajes que tengan un esqueleto similar. COLLADA El formato COLLADA (COLLAborative Design Activity) [14] surge ante la necesidad de proponer un formato estndar de cdigo abierto que sirva como medio de intercambio en la distribucin de contenidos. La mayora de empresas utilizan su propio formato de cdigo cerrado y en forma binaria, lo que diculta el acceso a los datos y la reutilizacin de contenidos por medio de otras herramientas que permiten su edicin. Con la elaboracin de COLLADA se pretenden alcanzar una serie de objetivos bsicos [23]: COLLADA no es un formato para motores de videojuegos. En

Figura 4.9: Captura del vdeojuego Quake III.

4.1. Formatos de Especicacin

[73] realidad, COLLADA benecia directamente a los usuarios de herramientas de creacin y distribucin de contenidos. Es decir, COLLADA es un formato que se utiliza en el proceso de produccin como mecanismo de intercambio de informacin entre los miembros del equipo de desarrollo y no como mecanismo nal de produccin. El formato COLLADA debe ser independiente de cualquier plataforma o tecnologa de desarrollo (sistemas operativos, lenguajes de programacin, etc). Ser un formato de cdigo libre, representado en XML para liberar los recursos digitales de formatos binarios propietarios. Proporcionar un formato estndar que pueda ser utilizado por una amplia mayora de herramientas de edicin de modelos tridimensionales. Intentar que sea adoptado por una amplia comunidad de usuarios de contenidos digitales. Proveer un mecanismo sencillo de integracin, tal que toda la informacin posible se encuentre disponible en este formato. Ser la base comn de todas las transferencias de datos entre aplicaciones 3D.

Cualquier chero XML representado en el formato COLLADA est dividido en tres partes principales [23]: COLLADA Core Elements. Donde se dene la geometra de los objetos, informacin sobre la animacin, cmaras, luces, etc. COLLADA Physics. En este apartado es posible asociar propiedades fsicas a los objetos, con el objetivo de reproducir comportamientos lo ms realistas posibles. COLLADA FX. Se establecen las propiedades de los materiales asociados a los objetos e informacin valiosa para el renderizado de la escena. No es nuestro objetivo ver de forma detallada cada uno de estos tres bloques, pero s se realizar una breve descripcin de los principales elementos del ncleo ya que stos componen los elementos bsicos de una escena, los cuales son comunes en la mayora de formatos. COLLADA Core Elements En este bloque se dene la escena (<scene>) donde transcurre una historia y los objetos que participan en ella, mediante la denicin de la geometra y la animacin de los mismos. Adems, se incluye informacin sobre las cmaras empleadas en la escena y la iluminacin. Un documento con formato COLLADA slo puede contener un nodo <scene>, por tanto, ser necesario elaborar varios documentos COLLADA

[74]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

para denir escenas diferentes. La informacin de la escena se representa mediante un grafo acclico y debe estar estructurado de la mejor manera posible para que el procesamiento sea ptimo. A continuacin se muestran los nodos/etiquetas relacionados con la denicin de escenas [23].
Listado 4.8: Nodos empleados en COLLADA para la denicin de escenas
1 2 3 4 5 6 7

<instance_node> <instance_visual_scene> <library_nodes> <library_visual_scenes> <node> <scene> <visual_scene>

Para facilitar el manejo de una escena, COLLADA ofrece la posibilidad de agrupar los elementos en libreras. Un ejemplo sencillo de denicin de una escena podra ser el siguiente: Al igual que en el caso anterior, la denicin de la geometra de un objeto tambin puede ser estructurada y dividida en libreras, muy til sobre todo cuando la geometra de un objeto posee una complejidad considerable. De esta forma los nodos geometry se pueden encapsular dentro de una librera de objetos denominada library_geometrics.
Listado 4.9: Ejemplo de denicin de una escena en el formato COLLADA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

<COLLADA> <library_nodes id="comp"> <node name="earth"> </node> <node name="sky"> </node> </library_nodes> <library_visual_scenes> <visual_scene id="world"> <instance_library_nodes url="#comp"> </visual_scene> </library_visual_scenes> <scene> <instance_visual_scene url="#world"/> </scene> </COLLADA>

El elemento <geometry> permite denir la geometra de un objeto. En el caso de COLLADA (y en la mayora de formatos) la geometra se dene mediante la denicin de una malla que incluye informacin del tipo: cantidad de puntos, posicin, informacin de color, coordenadas de la textura aplicada al objeto, lneas que los conectan, ngulos, supercies, etc. Los nodos que se emplean para denir la geometra de un objeto en COLLADA son los siguientes [23]:

4.1. Formatos de Especicacin

[75]

Listado 4.10: Nodos utilizados para denir la geometra de un objeto en el formato COLLADA
1 2 3 4 5 6 7 8 9 10 11 12

<control_vertices> <geometry> <instance_geometry> <library_geometries> <lines> <linestrips> <mesh> <polygons> <polylist> <spline> <triangles> <trifans>

Un ejemplo de denicin de una malla en el formato COLLADA podra ser el que se muestra en el siguiente listado [23]. Para completar la informacin de la geometra de un objeto es necesario incluir datos sobre la transformacin de los vrtices. Algunas de las operaciones ms comunes son la rotacin (<rotate>), escalado (<scale>) o traslaciones (<translate>).
Listado 4.11: Ejemplo de denicin de una malla en el formato COLLADA
1 <mesh> 2 <source id="position" /> 3 <source id="normal" /> 4 <vertices id="verts"> 5 <input semantic="POSITION" source="#position"/> 6 </vertices> 7 <polygons count="1" material="Bricks"> 8 <input semantic="VERTEX" source="#verts" offset="0"/> 9 <input semantic="NORMAL" source="#normal" offset="1"/> 10 <p>0 0 2 1 3 2 1 3</p> 11 </polygons> 12 </mesh>

En cuanto a la iluminacin, COLLADA soporta la denicin de las siguientes fuentes de luces [23]: Luces ambientales Luces puntuales Luces direccionales Puntos de luz y se utilizan los siguientes nodos o etiquetas:
Listado 4.12: Nodos empleados en COLLADA para la denicin de fuentes de luz
1 <ambient> 2 <color> 3 <directional>

[76]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

4 5 6 7 8

<instance_light> <library_lights> <Light> <point> <spot>

Por otro lado, COLLADA tambin permite la denicin de cmaras. Una cmara declara una vista de la jerarqua del grafo de la escena y contiene informacin sobre la ptica (perspectiva u ortogrca). Los nodos que se utilizan para denir una cmara son los siguientes [23]:
Listado 4.13: Nodos empleados en COLLADA para denir cmaras
1 2 3 4 5 6 7

<camera> <imager> <instance_camera> <library_cameras> <optics> <orthographic> <Perspective>

Un ejemplo de denicin de una cmara podra ser el siguiente [23]:


Listado 4.14: Ejemplo de denicin de una cmara en el formato COLLADA
1 <camera name="eyepoint"> 2 <optics> 3 <technique_common> 4 <perspective> 5 <yfov>45</yfov> 6 <aspect_ratio>1.33333 7 </aspect_ratio> 8 <znear>1.0</znear> 9 <zfar>1000.0</zfar> 10 </perspective> 11 </technique_common> 12 </optics> 13 </camera>

En cuanto a la parte de animacin no entraremos en detalle en esta seccin ya que se ver en captulos posteriores. Simplemente recalcar que COLLADA est preparado para soportar los dos tipos de animacin principales: animacin de vrtices y animacin de esqueletos asociado a objetos. Formato para OGRE 3D Los tres elementos esenciales en el formato de Ogre son los siguientes [16]: Entity o entidad. Una entidad es cualquier elemento que se puede dibujar en pantalla; por tanto, quedan excluidos de esta categora las fuentes de luz y las cmaras. La posicin y la orientacin de una malla no se controla mediante este tipo de objeto pero s el material y la textura asociada.

4.1. Formatos de Especicacin

[77] SceneNode o nodo de la escena. Un nodo se utiliza para manipular las propiedades o principales caractersticas de una entidad (tambin sirven para controlar las propiedades de las fuentes de luz y cmaras). Los nodos de una escena estn organizados de forma jerrquica y la posicin de cada uno de ellos siempre es relativa a la de los nodos padre. SceneManager o controlador de la escena. Es el nodo raz y de l derivan el resto de nodos que se dibujan en la escena. A travs de este nodo es posible acceder a cualquier otro nodo en la jerarqua.

Si analizamos cualquier chero OgreXML podemos apreciar que existe informacin relativa a las mallas de los objetos. Cada malla puede estar formada a su vez por una o varias submallas, que contienen la siguiente informacin: Denicin de caras (<face>). Denicin de vrtices (<vertex>) con su posicin, normal, color y coordenadas UV. Asignacin de vrtices a huesos (<vertexboneassignment>). Enlace a un esqueleto (<skeletonlink>). A su vez cada submalla contiene el nombre del material y el nmero de caras asociada a la misma. Para cada una de las caras se almacenan los vrtices que la componen:
Listado 4.15: Creacin de mallas y submallas con materiales asociados
1 <mesh> 2 <submeshes> 3 <submesh material="blanco_ojo" usesharedvertices="false"> 4 <faces count="700"> 5 <face v1="0" v2="1" v3="2"/> 6 ............................. 7 </faces>

Adems es necesario saber la informacin geomtrica de cada uno de los vrtices, es decir, posicin, normal, coordenada de textura y el nmero de vrtices de la submalla
Listado 4.16: Geometra de un Objeto en OgreXML
1 <geometry vertexcount="3361"> 2 <vertexbuffer positions="true" normals="true" texture_coords="1"> 3 <vertex> 4 <position x="-0.000000" y="0.170180" z="-0.000000"/> 5 <normal x="0.000000" y="1.000000" z="0.000000"/> 6 <texcoord u="0.000000" v="1.000000"/> 7 </vertex>

[78]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Para la asignacin de los huesos se indican los huesos y sus pesos. Como se puede observar, el ndice utilizado para los huesos empieza por el 0.
Listado 4.17: Asignacin de huesos a una malla en OgreXML
1 <boneassignments> 2 <vertexboneassignment vertexindex="0" boneindex="26" weight="

1.000000"/>
3 ............................. 4 </boneassignments> 5 </submesh>

Si la malla o mallas que hemos exportado tienen asociado un esqueleto se mostrar con la etiqueta "skeletonlink". El campo name corresponde con el archivo xml que contiene informacin sobre el esqueleto: <skeletonlink name=uerpo.skeleton/>. En este caso el archivo "name.skeleton.xml"dene el esqueleto exportado, es decir, el conjunto de huesos que componen el esqueleto. El exportador asigna a cada hueso un ndice empezando por el 0 junto con el nombre, la posicin y rotacin del mismo:

Listado 4.18: Denicin de un esqueleto en OgreXML


1 <skeleton> 2 <bones> 3 <bone id="0" name="cerrada"> 4 <position x="5.395440" y="6.817142" z="-0.132860"/> 5 <rotation angle="0.000000"> 6 <axis x="1.000000" y="0.000000" z="0.000000"/> 7 </rotation> 8 </bone> 9 ............................. 10 </bones>

La denicin del esqueleto no estara completa si no se conoce la jerarqua de los huesos, esta informacin se describe indicando cul es el padre de cada uno e los huesos:
Listado 4.19: Denicin de la jerarqua de huesos en un esqueleto en el formato OgreXML
1 <bonehierarchy> 2 <boneparent bone="torso" parent="caderas" /> 3 <boneparent bone="rota_ceja_izquierda" parent="ceja_izquierda"

/>
4 <boneparent bone="rota_ceja_derecha" parent="ceja_derecha" /> 5 <boneparent bone="pecho" parent="torso" /> 6 <boneparent bone="hombro.r" parent="pecho" /> 7 ............................. 8 </bonehierarchy>

Por ltimo, si se han creado animaciones asociadas al esqueleto y han sido exportadas, se mostrar cada una de ellas identicndolas

4.2. Exportacin y Adaptacin de Contenidos

[79]

con el nombre denido previamente en Blender y la longitud de la accin medida en segundos. Cada animacin contendr informacin sobre los huesos que intervienen en el movimiento (traslacin, rotacin y escalado) y el instante de tiempo en el que se ha denido el frame clave:
Listado 4.20: Animacin de los huesos de un esqueleto en OgreXML
1 <animations> 2 <animation name="ascensor" length="2.160000"> 3 <track bone="d1root.l"> 4 <keyframes> 5 <keyframe time="0.000000"> 6 <translate x="-0.000000" y="0.000000" z="0.000000"/> 7 <rotate angle="0.000000"> 8 <axis x="-0.412549" y="0.655310" z="0.632749"/> 9 </rotate> 10 <scale x="1.000000" y="1.000000" z="1.000000"/> 11 </keyframe> 12 13 ............................. 14 <keyframe time="2.160000"> 15 <translate x="0.000000" y="-0.000000" z="0.000000"/> 16 <rotate angle="0.000000"> 17 <axis x="-0.891108" y="0.199133" z="0.407765"/> 18 </rotate> 19 <scale x="1.000000" y="1.000000" z="1.000000"/> 20 </keyframe> 21 </keyframes> 22 ............................. 23 </track>

Otros Formatos A continuacin se incluye una tabla con alguno de los formatos ms comunes para la representacin de objetos 3D, su extensin, editores que lo utilizan y un enlace donde se puede obtener ms informacin sobre el formato (ver Tabla 3.1) [25].

4.2.

Exportacin y Adaptacin de Contenidos

Como se coment en secciones anteriores la mayora de herramientas de creacin de contenidos digitales posee su propio formato privado. Sin embargo, la mayora de estas herramientas permiten la exportacin a otros formatos para facilitar la distribucin de contenidos. En esta seccin nos centraremos en la creacin de un modelo en Blender, la aplicacin de texturas a dicho modelo mediante la tcnica de UV Mapping y su exportacin a los formatos XML y binario de Ogre. Finalmente, cargaremos el objeto exportado en una aplicacin de Ogre 3D.

[80]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

EXT. 3DMF 3DO 3DS ACT ASE ASC

B3D BDF BLEND CAR COB DMO DXF HRC INC KF2 KFS

LWO MB MAX MS3D OBJ PZ3 RAW RDS RIB VRLM X XGL

EDITOR 3D Meta File, QuickDraw3D Jedi Knight 3D Studio Max, formato binario Motor Genesis 3D 3D Studio Max: versin de 3DS basada en texto 3D Studio Max: mnima representacin de datos representada en ASCII Bryce 3D Okino Blender Carrara Calgari TrueSpace Duke Nukem 3D Autodesk Autocad Softimage 3D POV-RAY Animaciones y poses en Max Payne Max Payne: informacin de la malla y los materiales Lightwave Maya 3D Studio Max Milkshape 3D Alias|Wavefront Poser Tringulos RAW Ray Dream Studio Renderman File Lenguaje para el modelado de realidad virtual Formato Microsoft Direct X Formato que utilizan varios programas CAD

Link http://www.apple.com http://www.lucasarts.com http://www.discreet.com http://www.genesis3D.com http://www.discreet.com http://www.discreet.com

http://www.corel.com http://www.okino.com http://www.blender.com http://www.eovia.com/carrara http://www.calgari.com http://www.3drealms.com http://www.autodesk.com http://www.softimage.com http://www.povray.org http://www.maxpayne.com http://www.maxpayne.com

http://www.newtek.com http://www.aliaswavefront.com http://www.discreet.com http://www.swissquake.ch http://aliaswavefront.com http://www.curioslab.com http:// http://www.metacreations.com http://www.renderman.com http://www.web3d.org http://www.microsoft.com http://www.xglspec.com

Cuadro 4.1: Otros formatos para la representacin de objetos en 3D

4.2. Exportacin y Adaptacin de Contenidos

[81]

4.2.1. Instalacin del exportador de Ogre en Blender


En primer lugar es necesario descargar la ltima versin del exportador desde http://code.google.com/p/blender2ogre/. En la seccin downloads estn disponibles las versiones del exportador asociadas a cada versin de blender. En funcin de la versin actual de blender que tengamos instalada, elegimos una u otra. Una vez descargado el archivo, lo descomprimimos y ejecutamos Blender. Posteriormente al men le >user preferences nos dirigimos o bien pulsamos Ctrl + ALT + U . En la ventana para la conguracin de las preferencias del usuario pulsamos sobre el botn addons y en la parte inferior de la ventana pulsamos el botn install addons. A continuacin el asistente nos ofrecer la posibilidad de elegir el script de python con el exportador de Blender a Ogre. Finalmente, el exportador aparecer en el listado de la derecha y marcaremos la casilla de vericacin. Para comprobar que la instalacin es correcta, nos dirigimos al men File >Export y comprobamos que entre las opciones aparece Ogre3D.

4.2.2. Creacin de un modelo en Blender


El objetivo es modelar una caja o cubo y aplicar una textura a cada una de las seis caras. Cuando ejecutamos Blender aparece en la escena un cubo creado por defecto, por tanto, no ser necesario crear ningn modelo adicional para completar este ejercicio. En el caso de que quisiramos aadir algn cubo ms sera sencillo, bastara con dirigirnos al men Add >Mesh >Cube y aparecera un nuevo cubo en la escena. Adems del cubo, Blender crea por defecto una fuente de luz y una cmara. Al igual que sucede con los objetos, es posible aadir fuentes de luz adicionales y nuevas cmaras. Para este ejercicio ser suciente con los elementos creados por defecto.

4.2.3. Aplicacin de texturas mediante UV Mapping


La tcnica de texturizado UV Mapping permite establecer una correspondencia entre los vrtices de un objeto y las coordenadas de una textura. Mediante esta tcnica no es necesario crear un chero o imagen para representar cada una de las texturas que se aplicar a cada una de las supercies que forman un objeto. En otras palabras, en un mismo chero se puede representar la piel que cubrir diferentes regiones de una supercie tridimensional. En est seccin explicaremos como aplicar una textura a cada una de las seis caras del cubo creado en la seccin anterior. La textura que se aplica a cada una de las caras puede aparecer desglosada en una misma imagen tal como muestra la Figura 4.10. Cada uno de los recuadros corresponde a la textura que se aplicar a una de las caras del cubo en el eje indicado. En la Figura 4.11 se

[82]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Figura 4.10: Orientacin de las texturas aplicadas a un cubo

muestra la textura real que se aplicar al modelo; tal como se puede apreciar est organizada de la misma forma que se presenta en la Figura 4.10 (cargar la imagen llamada textura512.jpg que se aporta con el material del curso). Todas las texturas se encuentran en una misma imagen cuya resolucin es 512x512. Los mdulos de memoria de las tarjetas grcas estn optimizados para trabajar con imgenes representadas en matrices cuadradas y con una altura o anchura potencia de dos. Por este motivo, la resolucin de la imagen que contiene las texturas es de 512x512 a pesar de que haya espacios en blanco y se pueda compactar ms reduciendo la altura. Una vez conocida la textura a aplicar sobre el cubo y cmo est estructurada, se describirn los pasos necesarios para aplicar las texturas en las caras del cubo mediante la tcnica UV Mapping. En primer lugar ejecutamos Blender y dividimos la pantalla en dos partes. Para ello situamos el puntero del ratn sobre el marco superior hasta que el cursor cambie de forma a una echa doblemente punteada, pulsamos el botn derecho y elegimos en el men otante la opcin Split Area. En el marco de la derecha pulsamos el men desplegable situado en la esquina inferior izquierda y elegimos la opcin UV/Image Editor. A continuacin cargamos la imagen de la textura (textura512.jpg); para ello pulsamos en el men Image >Open y elegimos la imagen que contiene las texturas. Despus de realizar estos datos la apariencia del editor de Blender debe ser similar a la que aparece en la Figura 4.12 En el marco de la izquierda se pueden visualizar las lneas que delimitan el cubo, coloreadas de color rosa, donde el modo de vista por defecto es Wireframe. Para visualizar por pantalla las texturas en todo momento elegimos el modo de vista Textured en el men situado en el marco inferior Viewport Shading. Otra posibilidad consiste en

4.2. Exportacin y Adaptacin de Contenidos

[83]

Figura 4.11: Imagen con resolucin 512x512 que contiene las texturas que sern aplicadas a un cubo

pulsar las teclas SHIFT + Z . Por otro lado, el cubo situado en la escena tiene asociado un material por defecto, pero ste no tiene asignada ninguna textura (en el caso de que no tenga un material asociado, ser necesario crear uno). Para ello, nos dirigimos al men de materiales situado en la barra de herramientas de la derecha (ver Figura 4.13). En segundo lugar, ser necesario determinar la textura. Al panel de texturas se accede pulsando el icono situado a la derecha de el de materiales (ver Figura 4.14). En el tipo de textura se elige Image y, ms abajo, en el panel de Image pulsamos sobre el botn Open para abrir la imagen de la textura con formato jpg. Por otro lado, en el panel Mapping, ser necesario elegir la opcin UV en el men Generate, para que las coordenadas de la textura se asocien correctamente al objeto en el proceso de renderizado. El siguiente paso consiste en elegir los vrtices de cada una de las caras del cubo y establecer una correspondencia con coordenadas de la textura. Para ello, pulsamos la tecla TAB para visualizar los vrtices y nos aseguramos que todos estn seleccionados (todos deben estar coloreados de amarillo). Para seleccionar o eliminar la seleccin

[84]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Figura 4.12: Editor de Blender con una divisin en dos marcos. En la parte izquierda aparece la gura geomtrica a texturizar y en la parte derecha las texturas que sern aplicadas mediante la tcnica de UV/Mapping

Figura 4.13: Seleccin del material del objeto

. Con todos los vrtices de todos los vrtices basta con pulsar la tecla A del cubo seleccionados, pulsamos la tecla U y en el men UV Mapping elegimos la opcin Cube Projection. En el editor UV de la derecha deben aparecer tres recuadros nuevos de color naranja. Pulsamos A para que ninguno de los vrtices quede seleccionado y, de forma manual, seleccionamos los vrtices de la cara superior (z+). Para seleccionar los vrtices existen dos alternativas; la primera es se leccionar uno a uno manteniendo la tecla SHIFT pulsada y presionar el botn derecho del ratn en cada uno de los vrtices. Una segunda opcin es dibujar un rea que encuadre los vrtices, para ello hay que pulsar primero la tecla B (Pulsa el botn intermedio del ratn y muvelo para cambiar la perspectiva y poder asegurar as que se han elegido los vrtices correctos). En la parte derecha, en el editor UV se puede observar un cuadrado con los bordes de color amarillo y la supercie morada. Este recuadro corresponde con la cara del cubo seleccionada y con el que se pueden establecer correspondencias con coordenadas de la textura. El siguiente paso consistir en adaptar la supercie del recuadro a la imagen que debe aparecer en la parte superior del cubo (z+), tal como indica la Figura 4.10. Para adaptar la supercie existen varias alternativas; una de ellas es escalar el cuadrado con la tecla S y para desplazarlo la tecla G (para hacer zoom sobre la textura se gira la rueda central del ratn). Un segunda opcin es ajustar cada vrtice de forma individual, para ello se selecciona un vrtice con el botn derecho del ratn, pulsamos G y desplazamos el vrtice a la posicin deseada. Las dos alternativas descritas anteriormente no son excluyentes y se pueden combinar, es decir, se podra escalar el recuadro en primer lugar y luego ajustar los vrtices, e incluso escalar de nuevo

4.2. Exportacin y Adaptacin de Contenidos

[85]

Figura 4.14: Denicin de la textura del objeto

si fuera necesario. Los pasos que se han realizo para establecer la textura de la parte superior del cubo deben ser repetidos para el resto de caras del cubo. Si renderizamos la escena pulsando F12 podemos apreciar el resultado nal. Por ltimo vamos a empaquetar el archivo .blend para que sea autocontenido. La textura es un recurso externo; si cargramos el chero .blend en otro ordenador posiblemente no se visualizara debido a que las rutas no coinciden. Si empaquetamos el chero eliminamos este tipo de problemas. Para ello, seleccionamos File >External Data >Pack into .blend le.

4.2.4. Exportacin del objeto en formato Ogre XML


Para exportar la escena de Blender al formato de Ogre seleccionamos File >Export >Ogre 3D. Antes de exportar debemos asegurarnos de que nos encontramos en modo objeto y no en modo de edicin, sino blender no nos permitir exportar el objeto. En la parte izquierda aparecer un nuevo panel con las opciones del exportador tal como muestra la Figura 4.15. Tal como se puede apreciar, el exportador dispone de mltiples opciones encuadradas en dos categoras: exportacin de materiales y exportacin de mallas. Las opciones del exportador son las siguientes: Posibilidad de intercambiar los ejes de coordenadas Separate Materials: Exporta todos los materiales por separado, genera un archivo .material por cada uno de ellos, en lugar de aglomerar todos ellos en un nico archivo. Only Animated Bones: nicamente exporta aquellos huesos que han sido animados y forman parte de frames clave. Export Scene: Exportacin de la escena actual. Export Selected Only: Exporta nicamente los objetos seleccionados. Force Camera: Exporta la cmara que est activa en el momento actual. Force Lamps: Exportacin de todas las luces de la escena. Export Meshes: Exportacin de las mallas de los objetos. Export Meshes (overwrite): Exporta las mallas y las sobreescribe si se han creado con anterioridad.

[86]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Figura 4.15: Exportador de Ogre integrado en Blender

Armature Animation: Exportacin del esqueleto del objeto y la animacin de los huesos. Shape Animation: datos sobre la animacin de personajes. Ofrece la posibilidad de ignorar los huesos cuyo valor esta por debajo del umbral denido en el parmetro Trim Weights. Optimize Arrays: optimiza el array de modicadores como instancias. Export Materials: Exportacin de los materiales y generacin de archivos .material Conversin de la imagen de la textura a otros formatos. Nmero de Mip Maps Nmero de niveles LOD en la malla Valor de incremento para reducir LOD Porcentaje de reduccin LOD Generacin de la lista con las aristas de la geometra del objeto Tangentes en la malla

4.2. Exportacin y Adaptacin de Contenidos Reorganizacin de los buffers de vrtices en la malla Optimizacin de las animaciones de la malla

[87]

4.2.5. Carga del objeto en una aplicacin Ogre


Para cargar el cubo exportado en Ogre vamos a partir de ejemplo visto al comienzo del curso Hello World. Recordemos que la estructura de directorios para la aplicacin en Ogre era la siguiente: Directorios: Include Media Obj Plugins src

Figura 4.16: Sistema de coordenadas utilizado en Ogre.

Ficheros en el directorio raz del proyecto Ogre: ogre.cfg plugins.cfg resources.cfg Una vez que se ha exportado el cubo con las texturas asociadas y se han generado los cheros Cube.mesh, Cube.mesh.xml y Scene.material, los incluimos en el directorio media (tambin incluimos la textura "textura512.jpg"). Los cheros deben incluirse en este directorio porque as est congurado en el chero resources.cfg, si deseramos incluir los recursos en otro directorio deberamos variar la conguracin en dicho chero. En segundo lugar, cambiamos el nombre del ejecutable; para ello, abrimos el archivo makele y en lugar de EXEC := helloWorld, ponemos EXEC:= cubo. Despus es necesario cambiar el cdigo de ejemplo para que cargue nuestro modelo. Abrimos el archivo /src/main.cpp que se encuentra dentro en el directorio /src. El cdigo es el siguiente:
Listado 4.21: Cdigo incluido en el archivo main.cpp
1 #include <ExampleApplication.h> 2 class SimpleExample : public ExampleApplication { 3 public : void createScene() { 4 Ogre::Entity *ent = mSceneMgr->createEntity("Sinbad", " 5 6 7 }; 8 9 int 10 11 12 13 }

Figura 4.17: Sistema de coordenadas utilizado en Blender.

Sinbad.mesh"); mSceneMgr->getRootSceneNode()->attachObject(ent); }

main(void) { SimpleExample example; example.go(); return 0;

[88]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

En nuestro caso la entidad a crear es aquella cuya malla se llama Cube.Mesh, sta ya contiene informacin sobre la geometra de la malla y las coordenadas UV en el caso de utilizacin de texturas. Por lo tanto el cdigo tras la modicacin de la funcin createScene, sera el siguiente:
Listado 4.22: Modicacin del chero main.cpp para cargar el cubo modelado en Blender
1 public : void createScene() { 2 Ogre::Entity *ent = mSceneMgr->createEntity("Caja", "cubo.mesh" 3 4 }

); mSceneMgr->getRootSceneNode()->attachObject(ent);

Al compilar (make) y ejecutar (./Cubo) aceptamos las opciones que vienen por defecto y se puede observar el cubo pero muy lejano. A partir de ahora todas las operaciones que queramos hacer (translacin, escalado, rotacin,...) tendr que ser a travs de cdigo. A continuacin se realiza una operacin de traslacin para acercar el cubo a la cmara:
Listado 4.23: Traslacin del cubo para acercarlo hacia la cmara
1 Entity *ent1 = mSceneMgr->createEntity( "Cubo", "Cube.mesh" ); 2 SceneNode *node1 = mSceneMgr->getRootSceneNode()->

createChildSceneNode( );
3 node1->attachObject( ent1 ); 4 node1->translate(Vector3(0, 0, 490 ));

Figura 4.18: Operaciones de rotacin.

Ejercicio: intentar escalar el cubo y rotarlo en funcin de los ejes usando Pitch, Yaw y Roll.

Listado 4.24: Ejemplo de escalado de un objeto


1 node1->scale( 3, 3, 3 );

Listado 4.25: Ejemplo de rotacin


1 node1->yaw(Ogre::Degree( -90 ) ); 2 node1->pitch(Ogre::Degree( -90 ) ); 3 node1->roll(Ogre::Degree( -90 ) );

4.3. Procesamiento de Recursos Grcos

[89]

4.3.

Procesamiento de Recursos Grcos

En esta seccin estudiaremos cmo adaptar recursos 3D realizados con Blender en Ogre. Tendremos en cuenta aspectos relativos a la escala, posicionamiento de los objetos (respecto de su sistema de referencia local y global) y estudiaremos algunas herramientas disponibles en Blender para el posicionamiento preciso de modelos 3D. Antes de continuar, el lector podra (opcionalmente) completar el estudio del captulo 6, ya que utilizaremos como base el cdigo fuente obtenido en el ltimo ejemplo de dicho captulo, y estudiaremos algunas cuestiones referentes al gestor de recursos. Blender, a diferencia de los sistemas de CAD (Computer Aided Design) (que emplean modelos de CSG (Constructive Solid Geometry), es una herramienta de modelado de contorno B-R EP (Boundary Representation). Esto implica que, a diferencia de los sistemas basados en CSG, trabaja con modelos huecos denidos por vrtices, aristas y caras. Como hemos estudiado en el captulo de introduccin matemtica, las coordenadas de estos modelos se especican de forma relativa a su centro, que dene el origen de su sistema de referencia local.
Figura 4.19: El centro del objeto dene el origen del sistema de referencia local. As, la posicin de los vrtices del cubo se denen segn este sistema local.

En Blender el centro del objeto se representa mediante un punto de color rosa (ver Figura 4.19). Si tenemos activos los manejadores en la cabecera de la ventana 3D , ser el punto de donde comienzan estos elementos de la interfaz. Este centro dene el sistema de referencia local, por lo que resulta crtico poder cambiar el centro del objeto ya que, tras su exportacin, se dibujar a partir de esta posicin. Con el objeto seleccionado en Modo de Objeto se puede indicar a Blender que recalcule el centro geomtrico del objeto en el panel de Object Tools (accesible con la tecla T ), en el botn Origin (ver Figura 4.20). Una vez pulsado Origin, podemos elegir entre Geometry to Origin, que desplaza los vrtices del objeto de modo que se ajustan a la posicin jada del centro geomtrico, Origin to Geometry que realiza la misma operacin de alineacin, pero desplazando el centro en lugar de mover los vrtices, o Origin to 3D Cursor que cambia la posicin del centro del objeto a la localizacin actual del cursor 3D.

Figura 4.20: Botn Origin para elegir el centro del objeto, en el panel Object Tools.

En muchas ocasiones, es necesario situar el centro y los vrtices de un modelo con absoluta precisin. Para realizar esta operacin, , y aparecer el panel de Transformacin basta con pulsar la tecla N Transform a la derecha de la vista 3D (ver Figura 4.21), en el que podremos especicar las coordenadas especcas del centro del objeto. Si estamos en modo edicin, podremos indicar las coordenadas a nivel de vrtice. Es interesante que esas coordenadas se especiquen local mente (botn Local activado), porque el exportador de Ogre trabajar con coordenadas locales relativas a ese centro. El centro del objeto puede igualmente situarse de forma precisa, empleando la posicin del puntero 3D. El puntero 3D puedes situarse en cualquier posicin del espacio con precisin. En el panel Transform comentado anteriormente (accesible mediante la tecla T ) pueden es-

[90]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

b)

a)

c)

d)

Figura 4.22: Aplicacin de transformaciones geomtricas en modo Edicin. a) Situacin inicial del modelo al que le aplicaremos un escalado de 0.5 respecto del eje Z. b) El escalado se aplica en modo Edicin. El campo Vertex Z muestra el valor correcto. c) Si el escalado se aplic en modo objeto, el campo Vertex Z no reeja la geometra real del objeto. Esto puede comprobarse fcilmente si alguno de los campos Scale no son igual a uno, como en d).

pecicarse numricamente las coordenadas 3D (ver Figura 4.23). Pos teriormente, utilizando el botn Origin (ver Figura 4.20), y eligiendo la opcin Origin to 3D Cursor podremos situar el centro del objeto en la posicin del puntero 3D. Es muy importante que las transformaciones de modelado se apliquen nalmente a las coordenadas locales del objeto, para que se apliquen de forma efectiva a las coordenadas de los vrtices. Es decir, si despus de trabajar con el modelo, pulsando la tecla N en modo Objeto, el valor Scale es distinto de 1 en alguno de los ejes, implica que esa transformacin se ha realizado en modo objeto, por lo que los vrtices del mismo no tendrn esas coordenadas asociadas. De igual modo, tambin hay que prestar atencin a la rotacin del objeto (estudiaremos cmo resolver este caso ms adelante). La Figura 4.22 muestra un ejemplo de este problema; el cubo de la izquierda se ha escalado en modo edicin, mientras que el de la derecha se ha escalado en modo objeto. El modelo de la izquierda se exportar correctamente, porque los vrtices tienen asociadas sus coordenadas locales. El modelo de la derecha sin embargo aplica una transformacin a nivel de objeto, y ser exportado como un cubo.
Figura 4.21: Propiedades del panel Transform en modo edicin (tecla T ). Permiten indicar las coordenadas de cada vrtice con respecto del Sistema de Referencia Local y del Sistema de Referencia Universal (Global).

Blender dispone de una orden para aplicar las transformaciones realizadas en modo Objeto al sistema de coordenadas local del objeto. Para ello, bastar con pulsar Control A y elegir Apply/ Rotation & Scale, o bien desde la cabecera de la ventana 3D en Object/ Apply/ Rotation & Scale.

Otra operacin muy interesante consiste en posicionar un objeto con total precisin. Para realizar esta operacin puede ser suciente con situarlo numricamente, como hemos visto anteriormente, acce-

Figura 4.23: Posicionamiento numrico del cursor 3D.

4.3. Procesamiento de Recursos Grcos

[91]

a)

b)

c)

d)

e)

f)
Figura 4.24: Ejemplo de uso del operador Cursor to Selected y Selection to Cursor. a) Posicin inicial de los dos modelos. Queremos llegar a la posicin f). En modo edicin, elegimos un vrtice superior del cubo y posicionamos el puntero 3D ah (empleando Shift S Cursor to Selected ). c) A continuacin modicamos el valor de X e Y de la posicin del cursor numricamente, para que se site en el centro de la cara. d) Elegimos Origin to 3D Cursor entre las opciones disponibles en el botn Origin del panel Object Tools. Ahora el cubo tiene su centro en el punto medio de la cara superior. e) Elegimos el vrtice sealado en la cabeza del mono y posicionamos ah el puntero 3D. Finalmente en f) cambiamos la posicin del cubo de forma que interseca exactamente en ese vrtice (Shift S/ Selection to Cursor ).

diendo al panel de transformacin mediante la tecla N . Sin embargo, otras veces necesitamos situarlo en una posicin relativa a otro objeto; necesitaremos situarlo empleando el cursor 3D. El centro de un objeto puede situarse en la posicin del puntero 3D, y el puntero 3D puede situarse en cualquier posicin del espacio. Podemos, por ejemplo, en modo edicin situar el puntero 3D en la posicin de un vrtice de un modelo, y situar ah el centro del objeto. Desde ese momento, los desplazamientos del modelo se harn tomando como referencia ese punto. Mediante el atajo Shift S Cursor to Selected podemos situar el puntero 3D en la posicin de un elemento seleccionado (por ejemplo, un vrtice, o en el centro de que haya sido seleccionado en mo otro objeto do objeto) y mediante Shift S Selection to Cursor moveremos el objeto seleccionado a la posicin del puntero 3D (ver Figura 4.24). Mediante este sencillo mecanismo de 2 pasos podemos situar los objetos con precisin, y modicar el centro del objeto a cualquier punto de inters.

[92]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

4.3.1. Ejemplo de uso


A continuacin veremos un ejemplo de utilizacin de los operadores comentados anteriormente. Partiremos de un sencillo modelo (de 308 vrtices y 596 caras triangulares) creado en Blender, que se muestra en la Figura 4.25. Al importar el modelo en Ogre, se ha creado un plano manualmente que sirve como base , y que est posicionado en Y = 0 (con vector normal el Y unitario). El siguiente cdigo muestra las lneas ms relevantes relativas a la creacin de la escena.
Listado 4.26: Fragmento de MyApp.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

int MyApp::start() { // ... Carga de configuracion, creacion de window ... Ogre::Camera* cam = _sceneManager->createCamera("MainCamera"); cam->setPosition(Ogre::Vector3(5,20,20)); cam->lookAt(Ogre::Vector3(0,0,0)); cam->setNearClipDistance(5); cam->setFarClipDistance(100); // ... Viewport, y createScene... } void MyApp::createScene() { Ogre::Entity* ent1 = _sceneManager->createEntity("MS.mesh"); Ogre::SceneNode* node1 = _sceneManager->createSceneNode("MS"); node1->attachObject(ent1); node1->translate(0,2,0); _sceneManager->getRootSceneNode()->addChild(node1); Ogre::Entity* ent2 = _sceneManager->createEntity("Mando.mesh"); Ogre::SceneNode* node2 = _sceneManager->createSceneNode("Mando"); node2->attachObject(ent2); node2->translate(0,2,0); node1->addChild(node2); // ... creacion del plano, luces, etc... }

Figura 4.25: Resultado de exportar directamente el modelo de la Master System desde Blender. La imagen superior muestra el modelo en Blender, y las inferior el resultado de desplegar el modelo en Ogre, con proporciones claramente errneas.

El problema viene asociado a que el modelo ha sido construido empleando transformaciones a nivel de objeto. Si accedemos a las pro piedades de transformacin N para cada objeto, obtenemos la informacin mostrada en la Figura 4.26. Como vemos, la escala a nivel de objeto de ambos modelos es distinta de 1.0 para alguno de los ejes, lo que indica que la transformacin se realiz a nivel de objeto. Aplicaremos la escala (y la rotacin, aunque en este caso el objeto no fue rotado) a los vrtices del modelo, eliminando cualquier operacin realizada objeto. Para ello, con cada objeto seleccionado, en modo pulsaremos Control A Apply / Rotation & Scale. Ahora la escala (ver Figura 4.26) debe mostrar un valor de 1.0 en cada eje. Como hemos visto, la eleccin correcta del centro del objeto facilita el cdigo en etapas posteriores. Si el modelo est normalizado (con escala 1.0 en todos los ejes), las coordenadas del espacio 3D de Blender pueden ser fcilmente transformadas a coordenadas de Ogre. En este caso, vamos a situar el centro de cada objeto de la escena de forma que est situado exactamente en = 0. Para ello, con cada obje el Z to seleccionado, pulsaremos en Origin Origin to 3D Cursor (del panel Object Tools).
Figura 4.26: Propiedades de transformacin de los dos objetos del ejemplo.

4.3. Procesamiento de Recursos Grcos

[93]

Figura 4.27: Posicionamiento del puntero 3D en relacin al centro del objeto. En muchas situaciones puede ser conveniente especicar que varios objetos tengan el centro en una misma posicin del espacio (como veremos en la siguiente seccin). Esto puede facilitar la construccin de la aplicacin.

Ahora posicionaremos el cursor 3D en esa posicin Shift S Cursor to Selected y modicaremos numricamente la coordenada del cursor 3D, para que se site en Z = 0 (accediendo al panel de Propiedades N ). El resultado de posicionar el cursor 3D se muestra en la Figura 4.27.

Figura 4.28: Posiconamiento del objeto mando.

Sistemas de Coordenadas: Recordemos que los sistemas de coordenadas de Ogre y Blender siguen convenios diferentes. Si utilizamos la opicin del exportador de Ogre Swap axis por defecto (con valor xz-y), para obtener las coordenadas equivalentes de Ogre desde Blender bastar con aplicar la misma coordenada X, la coordenada Z de Blender utilizarla en Y en Ogre, y la coordenada Y de Blender aplicarla invertida en Z en Ogre.

Ahora podemos exportar el modelo a Ogre, y las proporciones se mantendrn correctamente. Sera conveniente posicionar exactamente el mando en relacin a la consola, tal y como est en el modelo .blend. Para ello, podemos modicar y anotar manualmente la posicin de objeto 3D (en relacin con el SRU). Como el centro de la consola se ha posicionado en el origen del SRU, la posicin del centro del mando ser relativa al centro de la consola. Bastar con consultar estos valores (Location X, Y, Z ) en el panel Transform (ver Figura 4.28) y utilizarlos en Ogre. En el ejemplo de la Figura 4.28, el objeto tiene asociadas en Blender las coordenadas (-1.8, -2.8, 0). Al aplicar la equivalencia aplicada por

[94]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

el exportador (por defecto), obtendramos el equivalente en Ogre de (1.8, 0, 2.8). De este modo, el siguiente fragmento de cdigo muestra la creacin de la escena correcta en Ogre. En este caso ya no es necesario aplicar ninguna traslacin al objeto MS (se posicionar en el origen del SRU). Por su parte, al objeto Mando se aplicar la traslacin indicada , que se corresponde con la obtenida de Blender. en la lnea 9
Automatzate!! Listado 4.27: Fragmento de MyApp.c
1 2 3 4 5 6 7 8 9 10

Ogre::Entity* ent1 = _sceneManager->createEntity("MS.mesh"); Ogre::SceneNode* node1 = _sceneManager->createSceneNode("MS"); node1->attachObject(ent1); _sceneManager->getRootSceneNode()->addChild(node1); Ogre::Entity* ent2 = _sceneManager->createEntity("Mando.mesh"); Ogre::SceneNode* node2 = _sceneManager->createSceneNode("Mando"); node2->attachObject(ent2); node2->translate(-1.8,0,2.8); node1->addChild(node2);

Obviamente, el proceso de exportacin de los datos relativos al posicionamiento de objetos en la escena (junto con otros datos de inters) debern ser automatizados deniendo un formato de escena para Ogre. Este formato tendr la informacin necesaria para cada juego particular.

Por ltimo, sera deseable poder exportar la posicin de las cmara para percibir la escena con la misma conguracin que en Blender. Existen varias formas de congurar el camera pose. Una de las ms cmodas para el diseador es trabajar con la posicin de la cmara y el punto al que sta mira. Esta especicacin es equivalente a indicar la posicin y el puntolook at (en el primer fragmento de cdigo de la seccin, en las lneas 4 y 5 . Para que la cmara apunte hacia un objeto de la escena, puede crearse una restriccin de tipo Track To. Para ello, aadimos un ob jeto vaco a la escena (que no tiene representacin), mediante Shift A Add luego con / Empty. Ahora seleccionamos primero la cmara, y Shift pulsado seleccionamos el Empty y pulsamos Control T Track To Constraint. De este modo, si desplazamos la cmara, obtendremos que siempre est mirando hacia el objeto Empty creado (ver Figura 4.29). Cuando tengamos la fotografa de la escena montada, bastar con consultar el valor de posicin de la cmara y el Empty, y asignar esos valores al cdigo de posicionamiento y look at de la misma (teniendo en cuenta las diferencias entre sistemas de coordenadas de Blender y Ogre). El resultado se encuentra resumido en la Figura 4.30.
Figura 4.29: Track de la cmara al objeto Empty. Blender representa la relacin con una lnea punteada que va de la cmara al objeto Empty.

4.4.

Gestin de Recursos y Escena

En esta seccin estudiaremos un ejemplo que cubre varios aspectos que no han sido tratados en el documento, relativos al uso del gestor de recursos y de escena. Desarrollaremos un demostrador de 3D Picking que gestionar manualmente el puntero del ratn (mediante overlays), gestionar recursos empaquetados en archivos .zip (empleando las facilidades que proporciona Ogre), cargar geometra esttica y utilizar el potente sistema de queries del SceneManager con mscaras. La Figura 4.33 muestra el interfaz del ejemplo desarrollado. Mediante la rueda del ratn es posible desplazar la cmara. Si se pulsa

4.4. Gestin de Recursos y Escena

[95]

cam->setPosition (Vector3(5.7,6.3,7.1));

cam->lookAt (Vector3(0.9,0.2 ,1.1)); cam->set!"V# ("$re%%&e$ree(52));

Figura 4.30: Resultado de aplicar la misma cmara en Blender y Ogre. El campo de visin de la lente puede consultarse en las propiedades especcas de la cmara, indicando que el valor quiere representarse en grados (ver lista desplegable de la derecha)

la rueda, se aplicar un rotacin sobre la misma. Si se pulsa el botn izquierdo del ratn sobre un objeto de colisin del escenario (como el mostrado en la gura), se seleccionar mostrando su caja lmite bounding box. Si se pulsa con el botn izquierdo sobre el suelo de la sala, se aadir aleatoriamente una caja de tipo 1 o 2. Si pinchamos con el botn izquierdo sobre alguna de las cajas creadas, se seleccionar. Mediante el botn derecho nicamente podremos seleccionar cajas creadas (no se aadirn nunca cajas, aunque pulsemos sobre el suelo de la sala). Sobre una caja creada, podemos aplicar tres operaciones: con la tecla Supr eliminamos el objeto. Con la tecla R rotaremos la caja respecto de su eje Y. Finalmente, con la tecla S modicamos su escala. El operador de escala y de rotacin permiten su comportamien invertir to si pulsamos simultneamente la tecla Shift . Veamos a continuacin algunos aspectos relevantes en la construccin de este ejemplo.

4.4.1. Recursos empaquetados


El gestor de recursos de Ogre permite utilizar cheros .zip deniendo en el archivo de conguracin de recursos que el tipo es Zip.
Figura 4.31: Contenido del archivo de conguracin de recursos resource.cfg.

De este modo, el archivo de conguracin de recursos asociado a este ejemplo se muestra en la Figura 4.31. La implementacin del cargador de recursos que estudiamos en el captulo 6 permite su utilizacin directamente.

4.4.2. Gestin del ratn


En el siguiente listado se resume el cdigo necesario para posicionar una imagen usada como puntero del ratn en Ogre. La Figura 4.32 dene el material creado (textura con transparencia) para cargar la imagen que emplearemos como puntero.
Figura 4.32: Material asociado al puntero del ratn.

[96]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Figura 4.33: Ejemplo de aplicacin que desarrollaremos en esta seccin. El interfaz permite seleccionar objetos en el espacio 3D y modicar algunas de sus propiedades (escala y rotacin).

En la lnea 11 se posiciona el elemento del overlay llamado cursor ). En el en la posicin absoluta obtenida del ratn por OIS (lneas 1 y 2 constructor del FrameListener hay que indicar a OIS las dimensiones de la ventana, para que pueda posicionar adecuadamente el ratn (de otra forma, trabajar en un cuadrado de 50 pxeles de ancho y alto). Esta operacin se realiza como se indica en las lneas 14-15 . El desplazamiento de la rueda del ratn se obtiene en la coordena ). Utilizamos esta informacin para da Z con getMouseState (lnea 5 desplazar la cmara relativamente en su eje local Z .
Listado 4.28: Fragmentos de MyFrameListener.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

int posx = _mouse->getMouseState().X.abs; int posy = _mouse->getMouseState().Y.abs;

// Posicion del puntero // en pixeles.

// Si usamos la rueda, desplazamos en Z la camara ----------vt+= Vector3(0,0,-10)*deltaT * _mouse->getMouseState().Z.rel; _camera->moveRelative(vt * deltaT * tSpeed); // Gestion del overlay ----------------------------OverlayElement *oe; oe = _overlayManager->getOverlayElement("cursor"); oe->setLeft(posx); oe->setTop(posy); // En el constructor de MyFrameListener... _mouse->getMouseState().width = _win->getWidth(); _mouse->getMouseState().height = _win->getHeight();

4.4.3. Geometra Esttica


Como hemos estudiado anteriormente, el modelo abstracto de los MovableObject abarca multitud de tipos de objetos en la escena (desde luces, cmaras, entidades, etc...). Uno de los tipos ms empleados son las mallas poligionales, que tienen asociada informacin geomtrica y

4.4. Gestin de Recursos y Escena datos especcos para el posterior uso de materiales.

[97]

La geometra esttica, como su nombre indica, est pensada para elementos grcos que no modican su posicin durante la ejecucin de la aplicacin. Est pensada para enviar pocos paquetes (lotes) grandes de geometra a la GPU en lugar de muchos pequeos. Esto permite optimizar el rendimiento en su posterior despliegue. De este modo, a menor nmero de paquetes enviados a la GPU tendremos mayor rendimiento en la aplicacin.
Sobre eciencia...
Realizar 100 llamadas de 10.000 polgonos a la GPU puede ser un orden de magnitud menos eciente que realizar 10 llamadas de 100.000 polgonos.

El uso de la memoria empleando geometra esttica sin embargo es mayor. Mientras que los MovableObject comparten mallas poligonales (siempre que sean instancias del mismo objeto), empleando geometra esttica se copian los datos para cada instancia de la geometra. Existen algunas caractersticas principales que deben tenerse en cuenta a la hora de trabajar con geometra esttica: Construccin. La geometra esttica debe ser construda previamente a su uso. Esta etapa debe realizarse una nica vez, por lo que puede generarse en la carga del sistema y no supone una carga real en la tasa de refresco interactiva del juego. Gestin de materiales. El nmero de materiales diferentes asociados a la geometra esttica delimita el nmero de lotes (paquetes) que se enviarn a la GPU. De este modo, aunque un bloque de geometra esttica contenga gran cantidad de polgonos, se crearn tantos paquetes como diferentes materiales tenga asociado el bloque. As, existe un compromiso de eciencia relacionado con el nmero de materiales diferentes asociados a cada paquete de geometra esttica. Rendering en grupo. Aunque nicamente una pequea parte de la geometra esttica sea visible en el Frustum todo el paquete ser enviado a la GPU para su representacin. De este modo, es conveniente separar la geometra esttica en diferentes bloques para evitar el despliegue global de todos los elementos.

Figura 4.34: El escenario del ejemplo est realizado en baja poligonalizacin (1616 vrtices y 1003 caras). Aun as, el uso de geometra esttica acelera su despliegue en 3x!.

En el siguiente fragmento de cdigo relativo a MyApp.c se muestra las instrucciones necesarias para denir un paquete de geometra esttica en Ogre. Basta con llamar al SceneManager, e indicarle ). A el nombre del bloque a denir (en este caso SG en la lnea 1 continuacin se aade una entidad cargada desde un archivo .mesh. Finalmente en la lnea 4 se ejecuta la operacin de construccin del bloque de geometra.
Listado 4.29: Fragmento de MyApp.c
1 2 3 4

StaticGeometry* stage = _sceneManager->createStaticGeometry("SG"); Entity* ent1 = _sceneManager->createEntity("Escenario.mesh"); stage->addEntity(ent1, Vector3(0,0,0)); stage->build(); // Operacion para construir la geometria

Otro aspecto importante a tener en cuenta a la hora de trabajar con geometra esttica es que no es tenida en cuenta a la hora de realizar

[98]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

preguntas al gestor de escena. En la siguiente seccin veremos cmo resolver este inconveniente.

4.4.4. Queries
El gestor de escena permite resolver preguntas relativas a la relacin espacial entre los objetos de la escena. Estas preguntas pueden planterase relativas a los objetos mviles MovableObject y a la geometra del mundo WorldFragment. Ogre no gestiona las preguntas relativas a la geometra esttica. Una posible solucin pasa por crear objetos mviles invisibles de baja poligonalizacin que servirn para realizar estas preguntas. Estos objetos estn exportados conservando las mismas dimensiones y rotaciones que el bloque de geometra esttica (ver Figura 4.35). Adems, para evitar tener que cargar manualmente los centros de cada objeto, todos los bloques han redenido su centro en el origen del SRU (que coincide con el centro de la geometra esttica). El siguiente listado muestra la carga de estos elementos en el grafo de escena.
Listado 4.30: Fragmento de MyApp.cpp (Create Scene)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

// Objeto movable "suelo"para consultar al SceneManager SceneNode *nodecol = _sceneManager->createSceneNode("Col_Suelo"); Entity *entcol = _sceneManager->createEntity ("Col_Suelo", "Col_Suelo.mesh"); entcol->setQueryFlags(STAGE); // Usamos flags propios! nodecol->attachObject(entcol); nodecol->setVisible(false); // Objeto oculto _sceneManager->getRootSceneNode()->addChild(nodecol); // Cajas del escenario (baja poligonalizacion) stringstream sauxnode, sauxmesh; string s = "Col_Box"; for (int i=1; i<6; i++) { sauxnode << s << i; sauxmesh << s << i << ".mesh"; SceneNode *nodebox = _sceneManager->createSceneNode (sauxnode.str()); Entity *entboxcol = _sceneManager->createEntity (sauxnode.str(), sauxmesh.str()); entboxcol->setQueryFlags(STAGE); // Escenario nodebox->attachObject(entboxcol); nodebox->setVisible(false); nodecol->addChild(nodebox); sauxnode.str(""); sauxmesh.str(""); // Limpiamos el stream }

destacar el establecimiento de ags propios (en las lneas 5 Cabe y 19 ) que estudiaremos en 4.4.5, as como la propiedad de seccin la ). El bucle denido en 13-23 sirve para visibilidad del nodo (en 7 y 21 cargar las cajas lmite mostradas en la Figura 4.35. Las preguntas que pueden realizarse al gestor de escena se dividen en cuatro categoras principales: 1. Caja lmite, denida mediante dos vrtices opuestos, 2. Esfera, denida por una posicin y un radio, 3. Volumen, denido por un conjunto de tres o ms planos y 4. Rayo, denido por un punto (origen) y una direccin.

4.4. Gestin de Recursos y Escena

[99]

Otras intersecciones
Ogre soporta igualmente realizar consultas sobre cualquier tipo de intersecciones arbitrarias entre objetos de la escena.

En este ejemplo utilizaremos las intersecciones Rayo-Plano. Una vez creado el objeto de tipo RaySceneQuery en el constructor (mediante una llamada a createRayQuery del SceneManager ), que posteriormente ser eliminado en el destructor (mediante una llamada a destroyQuery del SceneManager ), podemos utilizar el objeto para realizar consultas a la escena.

ox4 Col_B

Col_ Box5

Col_ Box1

Box2 Col_ Suelo Col_

Col_ Box3

Figura 4.35: A la izquierda la geometra utilizada para las preguntas al gestor de escena. A la derecha la geometra esttica. El centro de todas las entidades de la izquierda coinciden con el centro del modelo de la derecha. Aunque en la imagen los modelos estn desplazados con respecto del eje X, en realidad ambos estn exactamente en la misma posicin del mundo.

Primera interseccin

rayMouse

origen

En la lnea 20 se utiliza un mtodo auxiliar para crear la Query, indicando las del ratn. Empleando la funcin de utilidad coordenadas , Ogre crea un rayo con origen en la cmara y la direccin de la lnea 2 indicada por las dos coordendas X , Y normalizadas (entre 0.0 y 1.0) que recibe como argumento (ver Figura 4.36). En la lnea 4 se establece ese rayo para la consulta y se indica en la lnea 5 que ordene los resultados por distancia de interseccin. La consulta de tipo rayo devuelve una lista con todos los objetos que han intersecado con el rayo1 . Ordenando el resultado por distancia, tendremos como primer elemento el primer objeto con el que chocado el rayo. La ejecucin ha . de la consulta se realiza en la lnea 21

Figura 4.36: Empleando la llamada a getCameraToViewportRay, el usuario puede obtener un rayo con origen en la posicin de la cmara, y con la direccin denida por la posicin del ratn.

1 El rayo se describe por un punto de origen y una direccin. Desde ese origen, y siguiendo esa direccin, el rayo describe una lnea innita que podr intersecar con innitos objetos

[100]

CAPTULO 4. RECURSOS GRFICOS Y SISTEMA DE ARCHIVOS

Para recuperar los datos de la consulta, se emplea un iterador. En el caso de esta aplicacin, slo nos interesa el primer elemento devuelto por la consulta (el primer punto de interseccin), por lo que en el if de la lnea 25 preguntamos si hay algn elemento devuelto por la consulta.

La creacin de las Queries son costosas computacionalmente (por lo que interesa realizarlas al inicio; en los constructores). Sin embargo su ejecucin puede realizarse sin problema en el bucle principal de dibujado. El rendimiento se ver notablemente afectado si creas y destruyes la query en cada frame.

El iterador obtiene punteros a objetos de tipo RaySceneQueryResultEntry, que cuentan con 3 atributos pblicos. El primero llamado distance es de tipo Real (usado en la lnea 35 ) nos indica la distancia de interseccin desde el origen del rayo. El segundo atributo llamado movable contiene un puntero al MovableObject con el que intersec (si existe). El tercer atributo worldFragment contiene un puntero al objeto de ese tipo (en este ejemplo no utilizamos geometra de esta clase). El test de interseccin rayo-objeto se realiza empleando cajas lmite. Esto resulta muy eciente (ya que nicamente hay que comparar con una caja y no con todos los polgonos que forman la entidad), pero tiene el inconveniente de la prdida de precisin (Figura 4.37). Finalmente, para aadir una caja en el punto de interseccin del rayo con el suelo, tenemos que obtener la posicin en el espacio 3D. Ogre proporciona una funcin de utilidad asociada a los rayos, que permite obtener el punto 3D, indicando una distancia desde el ori). De esta forma, indicando la distancia de interseccin gen (lnea 35 (obtenida en el iterador) en el mtodo getPoint del rayo, obtenemos el Vector3 que usamos directamente para posicionar el nuevo nodo en la escena.
Listado 4.31: Fragmento de MyFrameListener.cpp
1 Ray MyFrameListener::setRayQuery(int posx, int posy, uint32 mask) { 2 Ray rayMouse = _camera->getCameraToViewportRay 3 (posx/float(_win->getWidth()), posy/float(_win->getHeight())); 4 _raySceneQuery->setRay(rayMouse); 5 _raySceneQuery->setSortByDistance(true); 6 _raySceneQuery->setQueryMask(mask); 7 return (rayMouse); 8 } 9 10 bool MyFrameListener::frameStarted(const FrameEvent& evt) { 11 // ... Codigo anterior eliminado... 12 if (mbleft || mbright) { // Boton izquierdo o derecho -----13 if (mbleft) mask = STAGE | CUBE1 | CUBE2; // Todos 14 if (mbright) mask = ~STAGE; // Todo menos el escenario 15 16 if (_selectedNode != NULL) { // Si hay alguno seleccionado... 17 _selectedNode->showBoundingBox(false); _selectedNode = NULL; 18 } 19

Figura 4.37: En el caso de objetos mviles, Ogre emplea una caja lmite (denida por las coordenadas mayor y menor de los vrtices del modelo) para calcular la interseccin rayo-objeto y optimizar as los clculos. Esto implica que, en el caso del test de interseccin de la gura dara que hay colisin entre el rayo y el objeto. No obstante, es posible realizar manualmente un test de colisin con precisin (a nivel de polgono) si el juego lo requiere.

4.4. Gestin de Recursos y Escena

[101]

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

Ray r = setRayQuery(posx, posy, mask); RaySceneQueryResult &result = _raySceneQuery->execute(); RaySceneQueryResult::iterator it; it = result.begin(); if (it != result.end()) { if (mbleft) { if (it->movable->getParentSceneNode()->getName() == "Col_Suelo") { SceneNode *nodeaux = _sceneManager->createSceneNode(); int i = rand() %2; stringstream saux; saux << "Cube" << i+1 << ".mesh"; Entity *entaux=_sceneManager->createEntity(saux.str()); entaux->setQueryFlags(i?CUBE1:CUBE2); nodeaux->attachObject(entaux); nodeaux->translate(r.getPoint(it->distance)); _sceneManager->getRootSceneNode()->addChild(nodeaux); } } _selectedNode = it->movable->getParentSceneNode(); _selectedNode->showBoundingBox(true); } }

4.4.5. Mscaras
Las mscaras permiten restringir el mbito de las consultas rea lizadas al gestor de escena. En el listado anterior, en las lneas 13 y la mscara binaria que utilizaremos en la consulta 14 especicamos ). Para que una mscara sea vlida (y permita realizar opera(lnea 6 ciones lgicas con ella), debe contener un nico uno. As, la forma ms sencilla de denirlas es desplazando el 1 tantas posiciones como se indica tras el operador << como se indica en la Figura 4.38. Como el campo de mscara es de 32 bits, podemos denir 32 mscaras personalizadas para nuestra aplicacin.
Figura 4.38: Mscaras binarias denidas en MyFrameListener.h para el ejemplo.

Si no se especica ninguna mscara en la creacin de la entidad, sta responder a todas las Queries, planteando as un esquema bastante exible. Los operadores lgicos pueden emplearse para combinar varias mscaras, como el uso del AND &&, el OR || o la negacin (ver lneas 13 y 14 del pasado cdigo fuente). En este cdigo fuente, la consulta a STAGE sera equivalente a consultar por CUBE1 | CUBE2. La consulta de la lnea 13 sera equivalente a preguntar por todos los objetos de la escena (no especicar ninguna mscara).

setQueryFlags se podan asociar mscaras a entidades (lneas 5 y 19 ).

En el listado de la seccin 4.4.4, vimos que mediante la llamada a

Captulo

APIS de Grcos 3D
Carlos Gonzlez Morcillo

n este captulo se introducirn los aspectos ms relevantes de OpenGL. Como hemos sealado en el captulo de introudccin, muchas bibliotecas de visualizacin (como OGRE) nos abstraen de los detalles de bajo nivel. Sin embargo, resulta interesante conocer el modelo de estados de este ipo de APIs, por compartir multitud de convenios con las bibliotecas de alto nivel. Entre otros aspectos, en este captulo se estudiar la gestin de pilas de matrices y los diferentes modos de transformacin de la API.

E
5.1.

Introduccin

Actualmente existen en el mercado dos alternativas principales como bibliotecas de representacin 3D a bajo nivel: Direct3D y OpenGL. Estas dos bibliotecas son soportadas por la mayora de los dispositivos hardware de aceleracin grca. Direct3D forma parte del framework DirectX de Microsoft. Es una biblioteca ampliamente extendida, y multitud de motores 3D comerciales estn basados en ella. La principal desventaja del uso de DirectX es la asociacin exclusiva con el sistema operativo Microsoft Windows. Aunque existen formas de ejecutar un programa compilado para esta plataforma en otros sistemas, no es posible crear aplicaciones nativas utilizando DirectX en otros entornos. De este modo, en este primer estudio de las APIs de bajo nivel nos centraremos en la API multiplataforma OpenGL.

103

[104]

CAPTULO 5. APIS DE GRFICOS 3D

OpenGL es, probablemente, la biblioteca de programacin grca ms utilizada del mundo; desde videojuegos, simulacin, CAD, visualizacin cientca, y un largo etectera de mbitos de aplicacin la conguran como la mejor alternativa en multitud de ocasiones. En esta seccin se resumirn los aspectos bsicos ms relevantes para comenzar a utilizar OpenGL. En este breve resumen de OpenGL se dejarn gran cantidad de aspectos sin mencionar. Se recomienda el estudio de la gua ocial de OpenGL [28] (tambin conocido como El Libro Rojo de OpenGL para profundizar en esta potente biblioteca grca. Otra fantstica fuente de informacin, con ediciones anteriores del Libro Rojo es la pgina ocial de la biblioteca1 . El propio nombre OpenGL indica que es una Biblioteca para Grcos Abierta 2 . Una de las caractersticas que ha hecho de OpenGL una biblioteca tan famosa es que es independiente de la plataforma sobre la que se est ejecutando (en trminos software y hardware). Esto implica que alguien tendr que encargarse de abrir una ventana grca sobre la que OpenGL pueda dibujar los preciosos grcos 3D. Para facilitar el desarrollo de aplicaciones con OpenGL sin preocuparse de los detalles especcos de cada sistema operativo (tales como la creacin de ventanas, gestin de eventos, etc...) M. Kilgard cre GLUT (OpenGL Utility Toolkit), una biblioteca independiente de OpenGL (no forma parte de la distribucin ocial de la API) que facilita el desarrollo de pequeos prototipos. Esta biblioteca auxiliar es igualmente multiplataforma. En este captulo trabajaremos con FreeGLUT, la alternativa con licencia GPL totalmente compatible con GLUT. Si se desea mayor control sobre los eventos, y la posibilidad de extender las capacidades de la aplicacin, se recomienda el estudio de otras APIs multiplataforma compatibles con OpenGL, como por ejemplo SDL3 o la que emplearemos con OGRE (OIS). Existen alternativas especcas para sistemas de ventanas concretos (ver Figura 5.2, como GLX para plataformas Unix, AGL para Macintosh o WGL para sistemas Windows. De este modo, el ncleo principal de las biblioteca se encuentra en el mdulo GL (ver Figura 5.2). En el mdulo GLU (OpenGL Utility) se encuentran funciones de uso comn para el dibujo de diversos tipos de supercies (esferas, conos, cilindros, curvas...). Este mdulo es parte ocial de la biblioteca. Uno de los objetivos principales de OpenGL es la representacin de imgenes de alta calidad a alta velocidad. OpenGL est diseado para la realizacin de aplicaciones interactivas, como videojuegos. Gran cantidad de plataformas actuales se basan en esta especicacin para denir sus interfaces de dibujado en grcos 3D.
Figura 5.1: La ltima edicin del libro ocial de OpenGL, la referencia imprescindible de ms de 900 pginas.

Progr ! de U"# rio

Widget Opengl GTKGLExt, Motif, etc...

GLU

GL
Otr " $i%liotec " &oft' re

Figura 5.2: Relacin entre los mdulos principales de OpenGL.

1 http://www.opengl.org/ 2 Las 3 http://www.libsdl.org/

siglas de GL corresponden a Graphics Library

GLUT (FreeGLUT)

GLX, AGL, WGL...

5.2. Modelo Conceptual

[105]

Modelo Conceptual de OpenGL

5.2.

Modelo Conceptual

Dibujar

Cambiar Estado

Primitiva Geomtrica

Las llamadas a funciones de OpenGL estn diseadas para aceptar diversos tipos de datos como entrada. El nombre de la funcin identica adems los argumentos que recibir. Por ejemplo, en la Figura 5.4 se llama a una funcin para especicar un nuevo vrtice en coordenadas homogneas (4 parmetros), con tipo de datos double y en formato vector. Se denen tipos enumerados como redenicin de tipos bsicos (como GLoat, GLint, etc) para facilitar la compatibilidad con otras plataformas. Es buena prctica utilizar estos tipos redenidos si se planea compilar la aplicacin en otros sistemas. El Modelo Conceptual General de OpenGL dene dos operaciones bsicas que el programador puede realizar en cada instante; 1) dibujar algn elemento o 2) cambiar el estado de cmo se dibujan los elementos. La primera operacin de dibujar algn elemento tiene que ser a) una primitiva geomtrica (puntos, lneas o polgonos) o b) una primitiva de imagen.

Primitiva Imagen

Figura 5.3: Modelo conceptual general de OpenGL.

glVertex4dv (v);
Componentes 2 (x,y) 3 (x, y, z) (x, y, z, h) Tipo de Datos b (byte) ub (unsigned byte) s (short) us (unsig. short) i (int) ui (unsigned int) f (float) d (double) Vector (o escalar) v implica vector. Si no aparece, los parmetros son escalares.

Figura 5.4: Prototipo general de llamada a funcin en OpenGL.

La Figura 5.3 resume el modelo conceptual de OpenGL. As, la aplicacin que utilice OpenGL ser simplemente una coleccin de ciclos de cambio de estado y dibujado de elementos.

5.2.1. Cambio de Estado


Cambio de Estado
A modo de curiosidad: OpenGL cuenta con ms de 400 llamadas a funcin que tienen que ver con el cambio del estado interno de la biblioteca.

La operacin de Cambiar el Estado se encarga de inicializar las variables internas de OpenGL que denen cmo se dibujarn las primitivas. Este cambio de estado puede ser de mtiples tipos; desde cambiar el color de los vrtices de la primitiva, establecer la posicin de las luces, etc. Por ejemplo, cuando queremos dibujar el vrtice de un polgono de color rojo, primero cambiamos el color del vrtice con glColor() y despus dibujamos la primitiva en ese nuevo estado con glVertex(). Algunas de las formas ms utilizadas para cambiar el estado de OpenGL son:

[106]

CAPTULO 5. APIS DE GRFICOS 3D

1. Gestin de Vrtices: Algunas llamadas muy utilizadas cuando se trabaja con modelos poligonales son glColor() que utilizaremos en el primer ejemplo del captulo para establecer el color con el que se dibujarn los vrtices4 , glNormal() para especicar las normales que se utilizarn en la iluminacin, o glTexCoord() para indicar coordendas de textura. 2. Activacin de Modos: Mediante las llamadas a glEnable y glDisable se pueden activar o desactivar caractersticas internas de OpenGL. Por ejemplo, en la lnea 3 del primer ejemplo del captulo se activa el Test de Profundidad que utiliza y actualiza el Z-Buffer. Este test se utilizar hasta que de nuevo se cambia el . interruptor desactivando esta funcionalidad en la lnea 17 3. Caractersticas Especiales: Existen multitud de caractersticas particulares de los elementos con los que se est trabajando. OpenGL dene valores por defecto para los elementos con los que se est trabajando, que pueden ser cambiadas empleando llamadas a la API.

5.2.2. Dibujar Primitivas


La operacin de Dibujar Primitivas requiere habitualmente que stas se denan en coordenadas homogneas. Todas las primitivas geomtricas se especican con vrtices. El tipo de primitiva determina cmo se combinarn los vrtices para formar la superce poligional nal. La creacin de primitivas se realiza entre llamadas a glBegin(PRIMITIVA) y glEnd(), siendo PRIMITIVA alguna de las 10 primitivas bsicas soportadas por OpenGL5 . No obstante, el mdulo GLU permite dibujar otras supercies ms complejas (como cilindros, esferas, discos...), y con GLUT es posible dibujar algunos objetos simples. Como se puede ver, OpenGL no dispone de funciones para la carga de modelos poligonales creados con otras aplicaciones (como por ejemplo, en formato OBJ o MD3). Es responsabilidad del programador realizar esta carga y dibujarlos empleando las primitivas bsicas anteriores. Una vez estudiados los cambios de estado y el dibujado de primitivas bsicas, podemos especicar en la funcin display del siguiente listado para que dibuje un cuadrado (primitiva GL_QUADS). Las lneas relativas al despliegue del cuadrado se corresponden con el intervalo . Especicamos la posicin de cada vrtice del cuadrado modi7-17 cando el color (el estado interno). OpenGL se encargar de calcular la transicin de color entre cada punto intermedio del cuadrado.
Figura 5.5: Salida por pantalla del ejemplo.

4 Como veremos a continuacin, los colores en OpenGL se especican en punto otante con valores entre 0 y 1. Las primeras tres componentes se corresponden con los canales RGB, y la cuarta es el valor de transparencia Alpha. 5 Las 10 primitivas bsicas de OpenGL son GL_POINTS, GL_LINE_STRIP, GL_LINES, GL_LINE_LOOP, GL_POLYGON, GL_TRIANGLE_STRIP, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_QUADS y GL_QUAD_STRIP

5.3. Pipeline de OpenGL

[107]

Listado 5.1: Ejemplo de cambio de estado y dibujo de primitivas.


1 void display() { 2 glClear( GL_COLOR_BUFFER_BIT ); 3 glEnable(GL_DEPTH_TEST); 4 glLoadIdentity(); /* Cargamos la matriz identidad 5 glTranslatef( 0.f, 0.f, -4.f ); 6 7 glBegin(GL_QUADS); /* Dibujamos un cuadrado 8 glColor3f(1.0, 0.0, 0.0); /* de dos unidades de lado. 9 glVertex3f(1.0, 1.0, 0.0); /* Especificamos la coorde10 glColor3f(0.0, 1.0, 0.0); /* nada 3D de cada vertice 11 glVertex3f(1.0, -1.0, 0.0); /* y su color asociado. 12 glColor3f(0.0, 0.0, 1.0); 13 glVertex3f(-1.0, -1.0, 0.0); 14 glColor3f(1.0, 1.0, 1.0); 15 glVertex3f(-1.0, 1.0, 0.0); 16 glEnd(); 17 glDisable(GL_DEPTH_TEST); 18 19 glutSwapBuffers(); 20 }

*/ */ */ */ */ */

5.3.

Pipeline de OpenGL

Como vimos en el captulo 1.2, los elementos de la escena sufren diferentes transformaciones en el pipeline de grcos 3D. Algunas de las principales etapas se corresponden con las siguiente operaciones: Transformacin de Modelado: En la que los modelos se posicionan en la escena y se obtienen las Coordenadas Universales. Transformacin de Visualizacin: Donde se especica la posicin de la cmara y se mueven los objetos desde las coordenadas del mundo a las Coordenadas de Visualizacin (o coordenadas de cmara).
+X

+Y
-Z

Transformacin de Proyeccin: Obteniendo Coordenadas Normalizadas en el cubo unitario. Transformacin de Recorte y de Pantalla: Donde se obtienen, tras el recorte (o clipping de la geometra), las coordenadas 2D de la ventana en pantalla. OpenGL combina la Transformacin de Modelado y la de Visualizacin en una Transformacin llamada Modelview. De este modo OpenGL transforma directamente las Coordenadas Universales a Coordenadas de Visualizacin empleando la matriz Modelview. La posicin inicial de la cmara en OpenGL sigue el convenio estudiado en el captulo 2 y que se resume en la Figura 5.6.

-X -Y

+Z

Figura 5.6: Descripcin del sistema de coordenadas de la cmara denida en OpenGL.

5.3.1. Transformacin de Visualizacin


La transformacin de Visualizacin debe especicarse antes que ninguna otra transformacin de Modelado. Esto es debido a que Open-

[108]

CAPTULO 5. APIS DE GRFICOS 3D

GL aplica las transformaciones en orden inverso. De este modo, aplicando en el cdigo las transformaciones de Visualizacin antes que las de Modelado nos aseguramos que ocurrirn despus que las de Modelado. Para comenzar con la denicin de la Transformacin de Visualizacin, es necesario limpiar la matriz de trabajo actual. OpenGL cuenta con una funcin que carga la matriz identidad como matriz actual glLoadIdentity(). Una vez hecho esto, podemos posicionar la cmara virtual de varias formas: 1. glulookat. La primera opcin, y la ms comunmente utilizada es mediante la funcin gluLookAt. Esta funcin recibe como parmetros un punto (eye ) y dos vectores (center y up). El punto eye es el punto donde se encuentra la cmara en el espacio y mediante los vectores libres center y up orientamos hacia dnde mira la cmara (ver Figura 5.7). 2. Traslacin y Rotacin. Otra opcin es especicar manualmente una secuencia de traslaciones y rotaciones para posicionar la cmara (mediante las funciones glTraslate() y glRotate(), que sern estudiadas ms adelante. 3. Carga de Matriz. La ltima opcin, que es la utilizada en aplicaciones de Realidad Aumentada, es la carga de la matriz de Visualizacin calculada externamente. Esta opcin se emplea habitualmente cuando el programador quiere calcular la posicin de la cmara virtual empleando mtodos externos (como por ejemplo, mediante una biblioteca de tracking para aplicaciones de Realidad Aumentada).
Matriz Identidad
La Matriz Identidad es una matriz 4x4 con valor 1 en la diagonal principal, y 0 en el resto de elementos. La multiplicacin de esta matriz I por una matriz M cualquiera siempre obtiene como resultado M . Esto es necesario ya que OpenGL siempre multiplica las matrices que se le indican para modicar su estado interno.

(cx,cy,cz)

center

(ux,uy,uz)

up

(ex,ey,ez)

eye

5.3.2. Transformacin de Modelado


Las transformaciones de modelado nos permiten modicar los objetos de la escena. Existen tres operaciones bsicas de modelado que implementa OpenGL con llamadas a funciones. No obstante, puede especicarse cualquier operacin aplicando una matriz denida por el usuario. Traslacin. El objeto se mueve a lo largo de un vector. Esta operacin se realiza mediante la llamada a glTranslate(x,y,z). Rotacin. El objeto se rota en el eje denido por un vector. Esta operacin se realiza mediante la llamada a glRotate(,x,y,z), siendo el ngulo de rotacin en grados sexagesimales (en sentido contrario a las agujas del reloj). Escalado. El objeto se escala un determinado valor en cada eje. Se realiza mediante glScale(x,y,z).

Figura 5.7: Parmetros de la funcin glulookat.

5.3. Pipeline de OpenGL

[109]

5.3.3. Transformacin de Proyeccin


Como hemos visto, las transformaciones de proyeccin denen el volumen de visualizacin y los planos de recorte. OpenGL soporta dos modelos bsicos de proyeccin; la proyeccin ortogrca y la proyeccin en perspectiva. El ncleo de OpenGL dene una funcin para denir la pirmide de visualizacin (o frustum ) mediante la llamada a glFrustum(). Esta funcin require los seis parmetros (t, b, r, l, f y n) estudiados en la seccin 2.3. Otro modo de especicar la transformacin es mediante la funcin de GLU gluPerspective(fov, aspect, near, far). En esta funcin, far y near son las distancias de los planos de recorte (igual que los parmetros f y n del frustum. fov especica en grados sexagesimales el ngulo en el eje Y de la escena que es visible para el usuario, y aspect indica la relacin de aspecto de la pantalla (ancho/alto).
Sobre el uso de Matrices
Como el convenio en C y C++ de denicin de matrices bidimensionales es ordenados por las, suele ser una fuente de errores habitual denir la matriz como un array bidimensional. As, para acceder al elemento superior derecho de la matriz, tendramos que acceder al matriz[3][0] segn la notacin OpenGL. Para evitar errores, se recomienda denir el array como unidimensional de 16 elementos GLfloat matriz[16].

5.3.4. Matrices
OpenGL utiliza matrices 4x4 para representar todas sus transformaciones geomtricas. Las matrices emplean coordenadas homogneas, como se estudi en la seccin 2.2.1. A diferencia de la notacin matemtica estndar, OpenGL especica por defecto las matrices por columnas, por lo que si queremos cargar nuestras propias matrices de transformacin debemos tener en cuenta que el orden de elementos en OpenGL es el siguiente: m0 m1 m 2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15

(5.1)

OpenGL internamente maneja pilas de matrices, de forma que nicamente la matriz de la cima de cada pila es la que se est utilizando en un momento determinado. Hay cuatro pilas de matrices en OpenGL: 1. Pila Modelview (GL_MODELVIEW). Esta pila contiene las matrices de Transformacin de modelado y visualizacin. Tiene un tamao mnimo de 32 matrices (aunque, dependiendo del sistema puede haber ms disponibles). 2. Pila Projection (GL_PROJECTION). Esta pila contiene las matrices de proyeccin. Tiene un tamao mnimo de 2 elementos. 3. Pila Color (GL_PROJECTION). Utilizada para modicar los colores. 4. Pila Texture (GL_TEXTURE). Estas matrices se emplean para transformar las coordenadas de textura.

[110]

CAPTULO 5. APIS DE GRFICOS 3D

Y' Z'

a) Visto como Sistema de Referencia Universal


X' Y Y Y

osici!n final

Z X

Z X

Z X
Y' X'

osici!n inicial
Siste ma d Re e e ren i Unif" a ersac l

b) Visto como Sistema de Referencia Local


Y Y

Y
Z'

Y' Z' X'

Y' Z'

X'

Dos aproximaciones para ayudar a decidir el orden de las transformaciones en OpenGL: SRU o SRL.

Z X

Z X

Z X

Figura 5.8: Cmo decidir el orden de las operaciones en OpenGL.

Es posible cambiar la pila sobre la que especicaremos las transformaciones empleando la llamada a glMatrixMode(). Por ejemplo, para utilizar la pila de Modelview utilizaramos glMatrixMode(GL_MODELVIEW). El uso de pilas de matrices nos facilita la construccin de modelos jerrquicos, donde es posible utilizar modelos simples y ensamblarlos para construir modelos ms complejos. Por ejemplo, si queremos dibujar un coche, tendramos que dibujar las 4 ruedas con su posicin relativa al chasis del vehculo. As, dibujaramos el chasis, y luego desplazndonos cada vez desde el centro del coche dibujaramos cada una de las ruedas. Esta operacin de volver al centro del coche se realiza fcilmente empleando pilas de matrices. Este concepto est directamente relacionado con el Grafo de Escena que estudiamos en el captulo 3. Recordemos que nicamente trabajamos con la matriz que est en la cima de la pila. La funcin glPushMatrix() aade una copia de la matriz de trabajo actual a la parte superior de la pila. Por su parte, la funcin glPopMatrix() elimina la matriz superior de la pila, descartando su informacin. La siguiente matriz de la pila pasar a ser la matriz activa. El efecto de esta funcin es el de volver al ltimo punto que guardamos en la pila. Supongamos ahora que queremos rotar un objeto 45o respecto del eje Z y trasladarlo 5 unidades respecto del eje X, obteniendo una determinada posicin nal (ver Figura 5.8 izquierda). El objeto inicialmente est en el origen del SRU. En qu orden debemos aplicar las transformaciones de OpenGL? Como la transformacin es de modelo, tendremos que aplicarla sobre la pila de matrices Modelview, con el siguiente cdigo resultante:

5.3. Pipeline de OpenGL

[111]

Listado 5.2: Ejemplo de transformaciones.


1 2 3 4 5

glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(45,0,0,1); glTraslatef(5,0,0); dibujar_objeto();

El cdigo anterior dibuja el objeto en la posicin deseada, pero cmo hemos llegado a ese y no hemos intercambiado las instruc cdigo ciones de las lneas 3 y 4 ?. Existen dos formas de imaginarnos cmo se realiza el dibujado que nos puede ayudar a plantear el cdigo fuente. Ambas formas son nicamente aproximaciones conceptuales, ya que el resultado en cdigo debe ser exactamente el mismo. Idea de Sistema de Referencia Universal Fijo. La composicin de movimientos aparece en orden inverso al que aparece en el cdigo fuente. Esta idea es como ocurre realmente en OpenGL. Las transformaciones se aplican siempre respecto del SRU, y en orden inverso a como se indica en el cdigo fuente. De este modo,la ) primera transformacin que ocurrir ser la traslacin (lnea 4 y despus la rotacin respecto del origen del sistema de referencia universal (lnea 3 ). El resultado puede verse en la secuencia de la Figura 5.8 a). Idea del Sistema de Referencia Local. Tambin podemos imaginar que cada objeto tiene un sistema de referencia local interno al objeto que va cambiando. La composicin se realiza en el mismo orden que aparece en el cdigo fuente, y siempre respecto de ese sistema de referencia local. De esta forma, como se muestra en ) la secuencia de la Figura 5.8 b), el objeto primero rota (lnea 3 por lo que su sistema de referencia local queda rotado respecto del SRU, y respecto de ese sistema de referencia local, posteriormente lo trasladamos 5 unidades respecto del eje X (local). Como hemos visto, es posible adems cargar matrices de transformacin denidas por nuestros propios mtodos (podra ser interesante si empleramos, por ejemplo, algn mtodo para calcular la proyeccin de sombras). Esto se realiza con la llamada a funcin glLoadMatrix(). Cuando se llama a esta funcin se reemplaza la cima de la pila de matrices activa con el contenido de la matriz que se pasa como argumento. Si nos interesa es multiplicar una matriz denida en nuestros mtodos por el contenido de la cima de la pila de matrices, podemos utilizar la funcin glMultMatrix que postmultiplica la matriz que pasamos como argumento por la matriz de la cima de la pila.
Ejemplo Planetario
Ejemplo sencillo para aanzar el orden de las transformaciones.

5.3.5. Dos ejemplos de transformaciones jerrquicas


Veamos a continuacin un ejemplo sencillo que utiliza transformaciones jerrquicas. Deniremos un sistema planetario que inicialmente estar formado por el Sol y la Tierra.

[112]

CAPTULO 5. APIS DE GRFICOS 3D

Listado 5.3: Sistema Planetario


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

// ==== Definicion de constantes y variables globales ============= long hours = 0; // Horas transcurridas (para calculo rotaciones) // ======== display =============================================== void display() { float RotEarthDay=0.0; // Movimiento de rotacion de la tierra float RotEarth=0.0; // Movimiento de traslacion de la tierra glClear( GL_COLOR_BUFFER_BIT ); glPushMatrix(); RotEarthDay = (hours % 24) * (360/24.0); RotEarth = (hours / 24.0) * (360 / 365.0) * 10; // x10 rapido! glColor3ub (255, 186, 0); glutWireSphere (1, 16, 16); // Sol (radio 1 y 16 div) glRotatef (RotEarth, 0.0, 0.0, 1.0); glTranslatef(3, 0.0, 0.0); // Distancia Sol, Tierra glRotatef (RotEarthDay, 0.0, 0.0, 1.0); glColor3ub (0, 0, 255); glutWireSphere (0.5, 8, 8); // Tierra (radio 0.5) glutSwapBuffers(); glPopMatrix(); }

Como puede verse en el listado anterior, se ha incluido una variable global hours que se incrementa cada vez que se llama a la funcin display. En este ejemplo, esta funcin se llama cada vez que se pulsa cualquier tecla. Esa variable modela el paso de las horas, de forma que la traslacin y rotacin de la Tierra a partir del nmero se calcular de horas que han pasado (lneas 11 y 12 ). En la simulacin se ha acelerado 10 veces el movimiento de traslacin para que se vea ms claramente. Empleando la Idea de Sistema de Referencia Local podemos pensar que desplazamos el sistema de referencia para dibujar el sol. En la lnea 15 , para dibujar una esfera almbrica especicamos como primer argumento el radio, y a continuacin el nmero de rebanadas (horizontales y verticales) en que se dibujar la esfera. En ese punto dibujamos la primera esfera correspondiente al Sol. Hecho esto, rotamos los grados correspondientes al movimiento de ) y nos 3 unidades restraslacin de la tierra (lnea 16 desplazamos pecto del eje X local del objeto (lnea 17 ). Antes de dibujar la Tierra tendremos que realizar el movimiento de rotacin de la tierra (lnea 18 ). Finalmente dibujamos la esfera en la lnea . 20 Veamos ahora un segundo ejemplo que utiliza glPushMatrix() y glPopMatrix() para dibujar un brazo robtico sencillo. El ejemplo simplemente emplea dos cubos (convenientemente escalados) para dibujar la estructura jerrquica de la gura 5.10. En este ejemplo, se asocian manejadores de callback para los even ). tos de teclado, que se corresponden con la funcin keyboard (en 8-16 Esta funcin simplemente incrementa o decrementa los ngulos de rotacin de las dos articulaciones del robot, que estn denidas como . variables globales en 2 y 3
Figura 5.9: Salida por pantalla del ejemplo del planetario.

Ejemplo Brazo Robot


Un segundo ejemplo que utiliza las funciones de aadir y quitar elementos de la pila de matrices.

5.3. Pipeline de OpenGL

[113] La parte ms interesante del se encuentra denido en la ejemplo funcin dibujar en las lneas 19-42 .
Listado 5.4: Brazo Robtico
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

Figura 5.10: Salida por pantalla del ejemplo del robot.

// ==== Definicion de constantes y variables globales ============= static int hombro = 15; static int codo = 30; GLfloat matVerde[] = {0.0, 1.0, 0.0, 1.0}; GLfloat matAzul[] = {0.0, 0.0, 1.0, 1.0}; // ==== Funcion de callback del teclado =========================== void teclado(unsigned char key, int x, int y) { switch (key) { case q: hombro = (hombro++) % 360; break; case w: hombro = (hombro--) % 360; break; case a: codo = (codo++) % 360; break; case s: codo = (codo--) % 360; break; } glutPostRedisplay(); } // ==== Funcion de dibujado ======================================= void dibujar() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(0.0, 1.0, 6.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0); glRotatef(hombro, 0.0, 0.0, 1.0); glTranslatef(1.0, 0.0, 0.0); // Nos posicionamos en la mitad glPushMatrix(); // Guardamos la posicion glScalef (2.0, 0.7, 0.1); // Establecemos la escala glMaterialfv(GL_FRONT, GL_DIFFUSE, matVerde); glutSolidCube(1.0); // Dibujamos el ubo" glPopMatrix(); // Recuperamos la posicion glTranslatef(1.0,0.0,0.0); // Continuamos hasta el extremo glRotatef(codo, 0.0, 0.0, 1.0); glTranslatef(1.0,0.0,0.0); // Nos posicionamos en la mitad glPushMatrix(); // Guardamos la posicion glScalef (2.0, 0.7, 0.1); // Establecemos la .escala" glMaterialfv(GL_FRONT, GL_DIFFUSE, matAzul); glutSolidCube(1.0); // Dibujamos el ubo" glPopMatrix(); glutSwapBuffers(); }

Aplicamos de nuevo la idea de trabajar en un sistema de referencia local que se desplaza con los objetos segn los vamos dibujando. De este modo nos posicionaremos en la mitad del trayecto para dibujar el cubo escalado. El cubo siempre se dibuja en el centro del sistema de referencia local (dejando mitad y mitad del cubo en el lado positivo y negativo de cada eje). Por tanto, para que el cubo rote respecto del extremo tenemos que rotar primero (como en la lnea ) y luego des24 25 ), dibujar y recorrer la plazarnos hasta la mitad del trayecto (lnea otra mitad 32 antes de dibujar la segunda parte del robot.

[114]

CAPTULO 5. APIS DE GRFICOS 3D

5.4.

Ejercicios Propuestos

Se recomienda la realizacin de los ejercicios de esta seccin en orden, ya que estn relacionados y su complejidad es ascendente. 1. Modique el ejemplo del listado del planetario para que dibuje una esfera de color blanco que representar a la Luna, de radio 0.2 y separada 1 unidad del centro de la Tierra (ver Figura 5.11). Este objeto tendr una rotacin completa alrededor de la Tierra cada 2.7 das (10 veces ms rpido que la rotacin real de la Luna sobre la Tierra. Supondremos que la luna no cuenta con rotacin interna6 . 2. Modique el ejemplo del listado del brazo robtico para que una base (aadida con un toroide glutSolidTorus) permita rotar el brazo robtico respecto de la base (eje Y ) mediante las teclas 1 y 2. Adems, aada el cdigo para que el extremo cuente con unas pinzas (creadas con glutSolidCone) que se abran y cierren empleando las teclas z y x, tal y como se muestra en la Figura 5.12.
Figura 5.12: Ejemplo de salida del ejercicio del robot.

Figura 5.11: Ejemplo de salida del ejercicio propuesto.

6 Nota:

Para la resolucin de este ejercicio es recomendable utilizar las funciones de

glPushMatrix() y glPopMatrix() para volver al punto donde se dibuj la Tierra


antes de aplicar su rotacin interna.

Captulo

Gestin Manual OGRE 3D


Carlos Gonzlez Morcillo

E
6.1.
Inicio Casi-Manual
En este captulo no describiremos el inicio totalmente manual de Ogre; emplearemos las llamadas de alto nivel para cargar plugins, inicializar ventana, etc...

n las sesiones anteriores hemos delegado la gestin del arranque, incializacin y parada de Ogre en una clase SimpleExample proporcionada junto con el motor grco para facilitar el desarrollo de los primeros ejemplos. En este captulo estudiaremos la gestin semi-automtica de la funcionalidad empleada en los ejemplos anteriores, as como introduciremos nuevas caractersticas, como la creacin manual de entidades, y el uso de Overlays, luces y sombras dinmicas.

Inicializacin Manual

En esta seccin introduciremos un esqueleto de cdigo fuente que emplearemos en el resto del captulo, modicndolo de manera incremental. Trabajaremos con dos clases; MyApp que proporciona el ncleo principal de la aplicacin, y la clase MyFrameListener que es una isntancia de clase que hereda de Ogre::FrameListener, basada en el patrn Observador. Como puede verse en el primer listado, en el chero de cabecera de MyApp.h se declara la clase que contiene tres miembros privados; la instancia de root (que hemos estudiado en captulos anteriores), el gestor de escenas y un puntero a un objeto de la clase propia MySceneManager que deniremos a continuacin.

115

[116]

CAPTULO 6. GESTIN MANUAL OGRE 3D

Listado 6.1: MyApp.h


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

#include <Ogre.h> #include "MyFrameListener.h" class MyApp { private: Ogre::SceneManager* _sceneManager; Ogre::Root* _root; MyFrameListener* _framelistener; public: MyApp(); ~MyApp(); int start(); void loadResources(); void createScene(); };

El programa principal nicamente tendr que crear una instancia de la clase MyApp y ejecutar su mtodo start. La denicin de este . mtodo puede verse en el siguiente listado, en las lneas 13-44

6.1.1. Inicializacin
En la lnea 14 se crea el objeto Root. Esta es la primera operacin que se debe realizar antes de ejecutar cualquier otra operacin con Ogre. El constructor de Root est sobrecargado, y permite que se le pase como parmetros el nombre del archivo de conguracin de plugins (por defecto, buscar plugins.cfg en el mismo directorio donde se encuentra el ejecutable), el de conguracin de vdeo (por defecto ogre.cfg), y de log (por defecto ogre.log ).Si no le indicamos ningn pa), tratar de cargar los cheros rmetro (como en el caso de la lnea 14 con el nombre por defecto.

El comportamiento del constructor de Root es diferente entre no especicar parmetro, o pasar la cadena vaca . En el primer caso se buscarn los archivos con el nombre por defecto. En el segundo caso, indicamos a Ogre que cargaremos manualmente los plugins y la conguracin de vdeo.

En la lnea 16 se intenta cargar la conguracin de vdeo existente en el archivo ogre.cfg. Si el archivo no existe, o no es correcto, podemos abrir el dilogo que empleamos en los ejemplos de las sesiones anteriores (lnea 17 ), y guardar a continuacion los valores elegidos por el usuario (lnea 18 ). Con el objeto creado, podemos pasar a crear la Root ventana. Para ello, en la lnea 21 solicitamos al objeto Root que nalice su inicializacin creando una ventana que utilice la conguracin que eligi el usuario, con el ttulo especicado como segundo parmetro (MyApp en este caso).

6.1. Inicializacin Manual

[117] El primer parmetro booleano del mtodo indica a Ogre que se encarge de crear automticamente la ventana. La llamada a este mtodo nos devuelve un puntero a un objeto RenderWindow, que guardaremos en la variable window. Lo que ser representado en la ventana vendr denido por el volumen de visualizacin de la cmara virtual. Asociado a esta cmara, crearemos una supercie (algo que conceptualmente puede verse como el lienzo, o el plano de imagen ) sobre la que se dibujarn los objetos 3D. Esta supercie se denomina viewport. El Gestor de Escena admite diversos modos de gestin, empleando el patrn de Factora, que son cargados como plugins (y especicados en el archivo plugins.cfg). El parmetro indicado en la llamada de 22 especica el tipo de gestor de escena que utilizaremos ST_GENERIC1 . Esta gestin de escena mnima no est optimizada para ningn tipo de aplicacin en particular, y resulta especialmente adecuada para pequeas aplicaciones, mens de introduccin, etc.
Listado 6.2: MyApp.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

#include "MyApp.h" MyApp::MyApp() { _sceneManager = NULL; _framelistener = NULL; } MyApp::~MyApp() { delete _root; delete _framelistener; } int MyApp::start() { _root = new Ogre::Root(); if(!_root->restoreConfig()) { _root->showConfigDialog(); _root->saveConfig(); }

// Creamos el objeto root // Si no se puede restaurar // Abrimos ventana de config // Guardamos la configuracion

Ogre::RenderWindow* window = _root->initialise(true,"MyApp"); _sceneManager = _root->createSceneManager(Ogre::ST_GENERIC); Ogre::Camera* cam = _sceneManager->createCamera("MainCamera"); cam->setPosition(Ogre::Vector3(5,20,20)); cam->lookAt(Ogre::Vector3(0,0,0)); cam->setNearClipDistance(5); // Establecemos distancia de cam->setFarClipDistance(10000); // planos de recorte Ogre::Viewport* viewport = window->addViewport(cam); viewport->setBackgroundColour(Ogre::ColourValue(0.0,0.0,0.0)); double width = viewport->getActualWidth(); double height = viewport->getActualHeight(); cam->setAspectRatio(width / height); loadResources(); createScene(); // Metodo propio de carga de recursos // Metodo propio de creacion de la escena

1 Existen otros mtodos de gestin, como ST_INTERIOR, ST_EXTERIOR... Estudiaremos en detalle las opciones de estos gestores de escena a lo largo de este mdulo.

[118]

CAPTULO 6. GESTIN MANUAL OGRE 3D

39 _framelistener = new MyFrameListener(); // Clase propia 40 _root->addFrameListener(_framelistener); // Lo anadimos! 41 42 _root->startRendering(); // Gestion del bucle principal 43 return 0; // delegada en OGRE 44 } 45 46 void MyApp::loadResources() { 47 Ogre::ConfigFile cf; 48 cf.load("resources.cfg"); 49 50 Ogre::ConfigFile::SectionIterator sI = cf.getSectionIterator(); 51 Ogre::String sectionstr, typestr, datastr; 52 while (sI.hasMoreElements()) { // Mientras tenga elementos... 53 sectionstr = sI.peekNextKey(); 54 Ogre::ConfigFile::SettingsMultiMap *settings = sI.getNext(); 55 Ogre::ConfigFile::SettingsMultiMap::iterator i; 56 for (i = settings->begin(); i != settings->end(); ++i) { 57 typestr = i->first; datastr = i->second; 58 Ogre::ResourceGroupManager::getSingleton().

addResourceLocation(datastr, typestr, sectionstr);


59 60 61

} } Ogre::ResourceGroupManager::getSingleton(). initialiseAllResourceGroups();

62 } 63 64 void MyApp::createScene() { 65 Ogre::Entity* ent = _sceneManager->createEntity("Sinbad.mesh"); 66 _sceneManager->getRootSceneNode()->attachObject(ent); 67 }

El gestor de escena es el encargado de crear las cmaras virtuales. En realidad el gestor de escena trabaja como una factora de dife rentes tipos de objetos que crearemos en la escena. En la lnea 24 obtenemos un puntero a una cmara que llamaremos MainCamera .A continuacin establecemos la posicin de la cmara virtual (lnea ), 25 ). En las lneas 27-28 y el punto hacia el que mira del SRU (lnea 26 establecemos la distancia con los planos de recorte cercano y lejano (ver Seccin 2.3). En la lnea 34 se establece la relacin de aspecto de la cmara. Esta relacin de aspecto se calcula como el nmero de pxeles en horizontal con respecto del nmero de pxeles en vertical. Resoluciones de 4/3 (como 800x600, o 1024x768) tendrn asociado un valor de ratio de 1.3333, mientras que resoluciones panormicas de 16/9 tendrn un valor de 1.77, etc. Para calcular el aspect ratio de la cmara, creamos un viewport asociado a esa cmara y establecemos el color de fondo como negro (lneas 30-31 ). A continuacin en las lneas 36-37 se ejecutan mtodos propios de la clase para cargar los recursos y crear la escena. La carga de recursos manual la estudiaremos en la seccin 6.1.2. La creacin de ), se realiza aadiendo la entidad directamente la escena (lneas 64-67 al nodo Root. Las lneas 39-40 crean un objeto de tipo FrameListener. Una clase FrameListener es cualquier clase que implemente el interfaz de FrameListener, permitiendo que Ogre llame a ciertos mtodos al inicio y al nal del dibujado de cada frame empleando el patrn Observer. VeViewports...
Una cmara puede tener cero o ms Viewports. Un uso comn de los viewports es la generacin de imgenes dentro de otros viewports. Veremos un uso de esta caracterstica en prximos captulos del mdulo.

6.1. Inicializacin Manual

[119] remos en detalle cmo se puede implementar esta clase en la seccin 6.1.3. Al nalizar la inicializacin, llamamos al mtodo startRendering de ), que inicia el bucle principal de rendering. Esto hace Root (lnea 42 que Ogre entre en un bucle innito, ejecutando los mtodos asociados a los FrameListener que hayan sido aadidos anteriormente.

En muchas ocasiones, no es conveniente delegar en Ogre la gestin del bucle principal de dibujado. Por ejemplo, si queremos atender peticiones de networking, o actualizar estados internos del juego. Adems, si queremos integrar la ventana de visualizacin de Ogre como un widget dentro de un entorno de ventanas, es posible que ste no nos deje utilizar nuestro propio bucle pricipal de dibujado. En este caso, como veremos en sucesivos ejemplos, puede ser conveniente emplear la llamada a renderOneFrame() y gestionar manualmente el bucle de rendering.

6.1.2. Carga de Recursos


. El chero de denicin de recursos se especica en la lnea 48 Este archivo est formado de diferentes secciones, que contienen pares de clave y valor. En el sencillo ejemplo que vamos a denir en este captulo, tendremos el contenido denido en la Figura 6.1.
Figura 6.1: Contenido del archivo resources.cfg del ejemplo.

Como puede verse, la nica seccin del archivo se denomina General. Crearemos un iterador que permita cargar cada una de las secciones y, dentro de cada una, obtendremos los elementos que la denen. La lnea 50 crea el SectionIterator asociado al chero de conguracin. Mientras existan elementos que procesar por el iterador (bucle while de las lneas 52-60 ), obtiene la clave del primer elemento de la coleccin (lnea 53 ) sin avanzar al siguiente (en el caso del ejemplo, obtiene la seccin General ). A continuacin, obtiene en settings un puntero al valor del elemento actual de la coleccin, avanzando al siguiente. Este valor en realidad otro mapa. Emplearemos un segundo ) para recuperar los nombres y valores de cada iterador (lneas 56-69 entrada de la seccin. En el chero de ejemplo, nicamente iteraremos una vez dentro del segundo iterador, para obtener en typestr la entrada a FileSystem, y en datastr el valor del directorio media. Finalmente la llamada al ResourceGroupManager (lnea 61 ) solicita que se inicialicen todos los grupos de recursos que han sido aadidos . en el iterador anterior, en la lnea 58

6.1.3. FrameListener
Como hemos comentado anteriormente, el uso de FrameListener se basa en el patrn Observador. Aadimos instancias de esta clase

[120]

CAPTULO 6. GESTIN MANUAL OGRE 3D

al mtodo Root de forma que ser noticada cuando ocurran ciertos eventos. Antes de representar un frame, Ogre itera sobre todos los FrameListener aadidos, ejecutando el mtodo frameStarted de cada uno de ellos. Cuando el frame ha sido dibujado, Ogre ejecutar igualmente el mtodo frameEnded asociado a cada FrameListener. En el siguiente listado se declara la clase MyFrameListener.
FrameStarted Listado 6.3: MyFrameListener.h
1 2 3 4 5 6 7

#include <OgreFrameListener.h> class MyFrameListener : public Ogre::FrameListener { public: bool frameStarted(const Ogre::FrameEvent& evt); bool frameEnded(const Ogre::FrameEvent& evt); };

Si delegamos la gestin de bucle de dibujado a Ogre, la gestin de los eventos de teclado, ratn y joystick se realiza en FrameStarted, de modo que se atienden las peticiones antes del dibujado del frame.

Vemos que en esta sencilla implementacin de la clase MyFrameListener no es necesario tener ninguna variable miembro especca, ni denir ningn constructor o destructor particular asociado a la clase. Veremos en las siguientes secciones cmo se complica la implementacin de la misma segn necesitamos aadir nueva funcionalidad. La denicin de la clase es igualmente sencilla. Los mtodos frameStarted o frameEnded devolvern false cuando queramos nalizar la aplicacin. En este ejemplo, tras llamar la primera vez a frameStarted, se enviar al terminal la cadena Frame Started y Ogre nalizar. De este modo, no se llegar a imprimir la cadena asociada a frameEnded (ni se representar el primer frame de la escena!). Si modicamos la implementacin del mtodo frameStarted, devolviendo true, se dibujar el primer frame y al ejecutar el mtodo frameEnded (devolviendo false ), Ogre nalizar el bucle principal de dibujado. Habitualmente el mtodo frameEnded se dene pocas veces. nicamente si necesitamos liberar memoria, o actualizar algn valor tras dibujar el frame, se realizar una implementacin especca de este mtodo. En los prximos ejemplos, nicamente deniremos el mtodo frameStarted.
Listado 6.4: MyFrameListener.cpp
1 2 3 4 5 6 7 8 9 10 11

#include "MyFrameListener.h" bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { std::cout << "Frame started" << std::endl; return false; } bool MyFrameListener::frameEnded(const Ogre::FrameEvent& evt) std::cout << "Frame ended" << std::endl; return false; } {

6.2. Uso de OIS

[121]

6.2.
Sobre OIS
Recordemos que OIS no forma parte de la distribucin de Ogre. Es posible utilizar cualquier biblioteca para la gestin de eventos.

Uso de OIS

A continuacin utilizaremos OIS para aadir un soporte de tecla do mnimo, de forma que cuando se pulse la tecla ESC , se cierre la aplicacin. Bastar con devolver false en el mtodo frameStarted del FrameListener cuando esto ocurra. Como vemos en el siguiente lista ) un puntero do, es necesario aadir al constructor de la clase (lnea 11 a la RenderWindow.
Listado 6.5: MyFrameListener.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14

#include <OgreFrameListener.h> #include <OgreRenderWindow.h> #include <OIS/OIS.h> class MyFrameListener : public Ogre::FrameListener { private: OIS::InputManager* _inputManager; OIS::Keyboard* _keyboard; public: MyFrameListener(Ogre::RenderWindow* win); ~MyFrameListener(); bool frameStarted(const Ogre::FrameEvent& evt); };

Esta ventana se necesita para obtener el manejador de la ventana. Este manejador es un identicador nico que mantiene el sistema operativo para cada ventana. Cada sistema operativo mantiene una lista de atributos diferente. Ogre abstrae del sistema operativo subyacente empleando una funcin genrica, que admite como primer parmetro el tipo de elemento que queremos obtener, y como segundo un puntero al tipo de datos que vamos a recibir. En el caso de la llamada de , obtenemos el manejador de la ventana (el tipo asociado al la lnea 7 manejador se especica mediante la cadena WINDOW). En las lneas 8-9 convertimos el manejador a cadena, y aadimos el par de objetos (empleando la plantilla pair de std) como parmetros de OIS. Como puede verse el convenio de Ogre y de OIS es similar a la hora de nombrar el manejador de la ventana (salvo por el hecho de que OIS requiere que se especique como cadena, y Ogre lo devuelve como un entero). , que Con este parmetro, creamos un InputManager de OIS en 11 nos permitir crear diferentes interfaces para trabajar con eventos de teclado, ratn, etc. As, en las lneas 12-13 creamos un objeto de tipo OIS::Keyboard, que nos permitir obtenerlas pulsaciones de tecla del usuario. El segundo parmetro de la lnea 13 permite indicarle a OIS si queremos que almacene en un buffer los eventos de ese objeto. En este caso, la entrada por teclado se consume directamente sin almacenarla en un buffer intermedio. Tanto el InputManager como el ojbeto de teclado deben ser eliminados explcitamente en el destructor de nuestro FrameListener. Ogre se encarga de liberar los recursos asociados a todos sus Gestores. Como Ogre es independiente de OIS, no tiene constancia de su uso y

[122]

CAPTULO 6. GESTIN MANUAL OGRE 3D

es responsabilidad del programador liberar los objetos de entrada de eventos, as como el propio gestor InputManager.
Listado 6.6: MyFrameListener.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

#include "MyFrameListener.h" MyFrameListener::MyFrameListener(Ogre::RenderWindow* win) { OIS::ParamList param; unsigned int windowHandle; std::ostringstream wHandleStr; win->getCustomAttribute("WINDOW", &windowHandle); wHandleStr << windowHandle; param.insert(std::make_pair("WINDOW", wHandleStr.str())); _inputManager = OIS::InputManager::createInputSystem(param); _keyboard = static_cast<OIS::Keyboard*> (_inputManager->createInputObject(OIS::OISKeyboard, false)); } MyFrameListener::~MyFrameListener() { _inputManager->destroyInputObject(_keyboard); OIS::InputManager::destroyInputSystem(_inputManager); } bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { _keyboard->capture(); if(_keyboard->isKeyDown(OIS::KC_ESCAPE)) return false; return true; }

Laimplementacin del mtodo frameStarted es muy sencilla. En la hubo alguna pulsacin de tecla. Si se presion la lnea 22 se obtiene si tecla Escape (lnea 23 ), se devuelve false de modo que Ogre nalizar el bucle principal de dibujado y liberar todos los recursos que se estn empleando. Hasta ahora, la escena es totalmente esttica. La Figura 6.2 muestra el resultado de ejecutar el ejemplo (hasta que el usuario presiona ). A continuacin veremos cmo modicar la posicin de la tecla ESC los elementos de la escena, deniendo un interfaz para el manejo del ratn.
Figura 6.2: Resultado de ejecucin del ejemplo bsico con OIS.

6.2.1. Uso de Teclado y Ratn


En el ejemplo de esta seccin desplazaremos la cmara y rotaremos el modelo empleando el teclado y el ratn. Como en el diseo actual de nuestra apliacin el despliegue se gestiona ntegramente en la clase MyFrameListener, ser necesario que esta clase conozca los nuevos ), la cmara (deobjetos sobre los que va a trabajar: el ratn (lnea 8 clarada igualmente como variable miembro privada en 9 ), y el nodo (que contendr las entidades que queremos mover en 10 ). En estos primeros ejemplos nos centraremos en el aspecto funcional de los mismos. En sucesivos captulos estudiaremos otras aproximaciones de diseo para la gestin de eventos.

6.2. Uso de OIS

[123]

Listado 6.7: MyFrameListener.h


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

#include <Ogre.h> #include <OIS/OIS.h> class MyFrameListener : public Ogre::FrameListener { private: OIS::InputManager* _inputManager; OIS::Keyboard* _keyboard; OIS::Mouse* _mouse; Ogre::Camera* _camera; Ogre::SceneNode *_node; public: MyFrameListener(Ogre::RenderWindow* win, Ogre::Camera* cam, Ogre::SceneNode* node); ~MyFrameListener(); bool frameStarted(const Ogre::FrameEvent& evt); };

Listado 6.8: MyFrameListener.cpp


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

#include "MyFrameListener.h" MyFrameListener::MyFrameListener(Ogre::RenderWindow* win, Ogre::Camera* cam, Ogre::SceneNode *node) { OIS::ParamList param; size_t windowHandle; std::ostringstream wHandleStr; _camera = cam; _node = node;

win->getCustomAttribute("WINDOW", &windowHandle); wHandleStr << windowHandle; param.insert(std::make_pair("WINDOW", wHandleStr.str())); _inputManager = OIS::InputManager::createInputSystem(param); _keyboard = static_cast<OIS::Keyboard*> (_inputManager->createInputObject(OIS::OISKeyboard, false)); _mouse = static_cast<OIS::Mouse*> (_inputManager->createInputObject(OIS::OISMouse, false)); } MyFrameListener::~MyFrameListener() { _inputManager->destroyInputObject(_keyboard); _inputManager->destroyInputObject(_mouse); OIS::InputManager::destroyInputSystem(_inputManager); } bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { Ogre::Vector3 vt(0,0,0); Ogre::Real tSpeed = 20.0; Ogre::Real r = 0; Ogre::Real deltaT = evt.timeSinceLastFrame; _keyboard->capture(); if(_keyboard->isKeyDown(OIS::KC_ESCAPE)) return false; if(_keyboard->isKeyDown(OIS::KC_UP)) vt+=Ogre::Vector3(0,0,-1); if(_keyboard->isKeyDown(OIS::KC_DOWN)) vt+=Ogre::Vector3(0,0,1); if(_keyboard->isKeyDown(OIS::KC_LEFT)) vt+=Ogre::Vector3(-1,0,0); if(_keyboard->isKeyDown(OIS::KC_RIGHT))vt+=Ogre::Vector3(1,0,0); _camera->moveRelative(vt * deltaT * tSpeed); if(_keyboard->isKeyDown(OIS::KC_R)) r+=180; _node->yaw(Ogre::Degree(r * deltaT)); _mouse->capture();

[124]

CAPTULO 6. GESTIN MANUAL OGRE 3D

Tiempo (Frames)

44 45 46 47 48 49 50 }

float rotx = _mouse->getMouseState().X.rel * deltaT * -1; float roty = _mouse->getMouseState().Y.rel * deltaT * -1; _camera->yaw(Ogre::Radian(rotx)); _camera->pitch(Ogre::Radian(roty)); return true;

a)

Tiempo (Segundos) Tiempo (Segundos)

La implementacin de la clase MyFrameListener requiere asignar en el constructor los punteros de la cmara y del nodo de escena a las ). De forma variables miembro privadas (lnea 8 anloga, crearemos un InputObject para el ratn en las lneas 17-18 (que eliminaremos en ). el destructor en 23 El mtodo frameStarted es algo ms complejo que el estudiado en el ejemplo anterior. En esta ocasin, se denen en las lneas 28-30 una serie de variables que comentaremos a continuacin. En vt almacenaremos el vector de traslacin relativo que aplicaremos a la cmara, dependiendo de la pulsacin de teclas del usuario. La variable r almacenar la rotacin que aplicaremos al nodo de la escena (pasado como tercer argumento al constructor). En deltaT guardaremos el nmero de segundos transcurridos desde el despliegue del ltimo frame. Finalmente la variable tSpeed servir para indicar la traslacin (distancia en unidades del mundo) que queremos recorrer con la cmara en un segundo. La necesidad de medir el tiempo transcurrido desde el despliegue del ltimo frame es imprescindible si queremos que las unidades del espacio recorridas por el modelo (o la cmara en este caso) sean dependientes del tiempo e independientes de las capacidades de representacin grcas de la mquina sobre la que se estn ejecutando. Si aplicamos directamente un incremento del espacio sin tener en cuenta el tiempo, como se muestra en la Figura 6.3, el resultado del espacio recorrido depender de la velocidad de despliegue (ordenadores ms potentes avanzarn ms espacio). La solucin es aplicar incrementos en la distancia dependientes del tiempo. De este modo, aplicamos un movimiento relativo a la cmara (en funcin de sus ejes locales), multiplicando el vector de traslacin (que ha sido denido dependiendo de la pulsacin de teclas del usuario en ), por deltaT y por la velocidad de traslacin (de modo las lneas 34-37 que avanzar 20 unidades por segundo). , se rotar el De forma similar, cuando el usuario pulse la tecla R modelorespecto de su eje Y local a una velocidad de 180o por segundo (lneas 40-41 ). Finalmente, se aplicar una rotacin a la cmara respecto de sus ejes Y y Z locales empelando el movimiento del ratn. Para relativo ello, se obtiene el estado del ratn (lneas 44-45 ), obteniendo el incremento relativo en pxeles desde la ltima captura (mediante el atributo abs se puede obtener el valor absoluto del incremento).

Espacio Tiempo (Frames)


b)

Espacio
c)

Espacio
d)

Espacio

Figura 6.3: Comparacin entre animacin basada en frames y animacin basada en tiempo. El eje de abcisas representa el espacio recorrido en una trayectoria, mientras que el eje de ordenadas representa el tiempo. En las grcas a) y b) el tiempo se especica en frames. En las grcas c) y d) el tiempo se especica en segundos. Las grcas a) y c) se corresponden con los rsultados obtenidos en un computador con bajo rendimiento grco (en el mismo tiempo presenta una baja tasa de frames por segundo). Las grcas b) y d) se corresponden a un computador con el doble de frames por segundo.

6.3. Creacin manual de Entidades

[125]

6.3.

Creacin manual de Entidades

Ogre soporta la creacin manual de multitud de entidades y objetos. Veremos a continuacin cmo se pueden aadir planos y fuentes de luz a la escena. La creacin manual del plano se realiza en las lneas 8-11 del si guiente listado. En la lnea 8 se especica que el plano tendr como vector normal, el vector unitario en Y , y que estar situado a -5 unidades respecto del vector normal. Esta denicin se corresponde con un plano innito (descripcin matemtica abstracta). Si queremos representar el plano, tendremos que indicar a Ogre el tamao (nito) del mismo, as como la resolucin que queremos aplicarle (nmero de divisiones y verticales). Estas operaciones se indican en las horizontales lneas 9-11 .
Listado 6.9: Denicin de createScene (MyApp.cpp)
1 void MyApp::createScene() { 2 Ogre::Entity* ent1 = _sceneManager->createEntity("Sinbad.mesh"); 3 Ogre::SceneNode* node1 = 4 _sceneManager->createSceneNode("SinbadNode"); 5 node1->attachObject(ent1); 6 _sceneManager->getRootSceneNode()->addChild(node1); 7 8 Ogre::Plane pl1(Ogre::Vector3::UNIT_Y, -5); 9 Ogre::MeshManager::getSingleton().createPlane("pl1", 10 Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 11 pl1,200,200,1,1,true,1,20,20,Ogre::Vector3::UNIT_Z); 12 13 Ogre::SceneNode* node2 = _sceneManager->createSceneNode("node2"); 14 Ogre::Entity* grEnt = _sceneManager->createEntity("pEnt", "pl1"); 15 grEnt->setMaterialName("Ground"); 16 node2->attachObject(grEnt); 17 18 _sceneManager->setShadowTechnique(Ogre:: 19 20 21 22 23 24 25 }

SHADOWTYPE_STENCIL_ADDITIVE); Ogre::Light* light = _sceneManager->createLight("Light1"); light->setType(Ogre::Light::LT_DIRECTIONAL); light->setDirection(Ogre::Vector3(1,-1,0)); node2->attachObject(light); _sceneManager->getRootSceneNode()->addChild(node2);

Figura 6.4: Nmero de segmentos de denicin del plano. La imagen superior implica un segmento en X y un segmento en Y (valores por defecto). La imagen central se corresponde con una denicin de 2 segmentos en ambos planos, y la inferior de 4 segmentos.

El uso del MeshManager nos permite la creacin de planos, skyboxes, supercies de Bezier, y un largo etctera. En el caso de este ejemplo, se utiliza la llamada a createPlane que recibe los siguientes parmetros indicados en orden: el primer parmetro es el nombre de la malla resultante, a continuacin el nombre del grupo de mallas (emplearemos el grupo por defecto). El tercer parmetro es el objeto denicin del plano innito (creado en la lnea 8 ). Los siguientes dos parmetros indican el ancho y alto del plano en coordenadas del mundo (200x200 en este caso). Los siguientes dos parmetros se corresponden con el nmero de segmentos empleados para denir el plano (1x1 en este caso), como se indica en la Figura 6.4. Estos parmetros sirven para especicar la resolucin geomtrica del plano creado (por

[126]

CAPTULO 6. GESTIN MANUAL OGRE 3D

si posteriormente queremos realizar operaciones de distorsin a nivel de vrtice, por ejemplo). El siguiente parmetro booleano indica (si es cierto) que los vectores normales se calcularn perpendiculares al plano. El siguiente parmetro (por defecto, 1) indica el conjunto de coordenadas de textura que sern creadas. A continuacin se indica el nmero de repeticin (uTile y vTile ) de la textura (ver Figura 6.6). El ltimo parmetro indica la direccin del vector Up del plano. A continuacin en la lnea 15 asignamos al plano el material Ground . Este material est denido en un archivo en el directorio media que ha sido cargado empleando el cargador de recursos explicado en la seccin 6.1.2. Este material permite la recepcin de sombras, tiene componente de brillo difuso y especular, y una textura de imagen basada en el archivo ground.jpg. Estudiaremos en detalle la asignacin de materiales en el prximo captulo del documento. Finalmente las lneas 18-22 se encargan de denir una fuente de luz 2 dinmica direccional y habilitar el clculo de sombras. Ogre soporta 3 tipos bsicos de fuentes de luz y 11 modos de clculo de sombras dinmicas, que sern estudiados en detalle en prximos captulos.

Figura 6.5: Fichero de denicin del material Ground.material.

6.4.

Uso de Overlays

En el ltimo ejemplo del captulo deniremos superposiciones (Overlays) para desplegar en 2D elementos de informacin (tales como marcadores, botones, logotipos, etc...). La gestin de los Overlays en Ogre se realiza mediante el gestor de recursos llamado OverlayManager, que se encarga de cargar los scripts de denicin de los Overlays. En un overlay pueden existir objetos de dos tipos: los contenedores y los elementos. Los elementos pueden ser de tres tipos bsicos: TextArea empleado para incluir texto, Panel empleado como elemento que puede agrupar otros elementos con un fondo jo y BorderPanel que es igual que Panel pero permite que la textura de fondo se repita y denir un borde independiente del fondo. La denicin del Overlay del ejemplo de esta seccin se muestra en la Figura 6.8. En el caso de utilizar un TextArea, ser necesario especicar la carga de una fuente de texto. Ogre soporta texturas basadas en imagen o truetype. La denicin de las fuentes se realiza empleando un chero de extensin .fontdef (ver Figura 6.7). En el listado de la Figura 6.8 se muestra la denicin de los elementos y contendores del Overlay, as como los cheros de material (extensin .material) asociados al mismo. En el siguiente captulo estudiaremos en detalle la denicin de materiales en Ogre, aunque un simple vistazo al chero de materiales nos adelanta que estamos creando dos materiales, uno llamado panelInfoM, y otro matUCLM. Ambos utilizan texturas de imagen. El primero de ellos utiliza una tcnica de mezclado que tiene en cuenta la componente de opacidad de la pasada.
2 Este tipo de fuentes de luz nicamente tienen direccin. Denen rayos de luz paralelos de una fuente distante. Es el equivalente al tipo de fuente Sun de Blender.

Figura 6.6: Valores de repeticin en la textura. La imagen superior se corresponde con valores de uT ile = 1, vT ile = 1. La imagen inferior implica un valor de 2 en ambos parmetros (repitiendo la textura 2x2 veces en el plano).

Figura 6.7: Fichero de denicin de la fuente Blue.fontdef.

6.4. Uso de Overlays

[127]

Figura 6.8: Denicin de los Overlays empleando cheros externos. En este chero se describen dos paneles contenedores; uno para la zona inferior izquierda que contiene cuatro reas de texto, y uno para la zona superior derecha que representar el logotipo de la UCLM.

[128] Atributo metrics_mode

CAPTULO 6. GESTIN MANUAL OGRE 3D Descripcin Puede ser relative (valor entre 0.0 y 1.0), o pixels (valor en pxeles). Por defecto es relative. En coordenadas relativas, la coordenada superior izquierda es la (0,0) y la inferior derecha la (1,1). Puede ser left (por defecto), center o right. Puede ser top (por defecto), center o bottom. Posicin con respecto al extremo izquierdo. Por defecto 0. Si el valor es negativo, se interpreta como espacio desde el extremo derecho (con alineacin right ). Posicin con respecto al extremo superior. Por defecto 0. Si el valor es negativo, se interpreta como espacio desde el extremo inferior (con alineacin vertical bottom ). Ancho. Por defecto 1 (en relative ). Alto. Por defecto 1 (en relative ). Nombre del material asociado (por defecto Ninguno). Etiqueta de texto asociada al elemento (por defecto Ninguna). ngulo de rotacin del elemento (por defecto sin rotacin).

horz_align vert_align left top width height material caption rotation

Cuadro 6.1: Atributos generales de Elementos y Contenedores de Overlays.

El primer contenedor de tipo Panel (llamado PanelInfo ), contiene cuatro TextArea en su interior. El posicionamiento de estos elementos se realiza de forma relativa al posicionamiento del contenedor. De este modo, se establece una relacin de jerarqua implcita entre el contenedor y los objetos contenidos. El segundo elemento contenedor (llamado logoUCLM ) no tiene ningn elemento asociado en su interior. La Tabla 6.1 describe los principales atributos de los contenedores y elementos de los overlays. Estas propiedades pueden ser igualmente modicadas en tiempo de ejecucin, por lo que son animables. Por ejemplo, es posible modicar la rotacin de un elemento del Overlay consiguiendo bonitos efectos en los mens del juego. El sistema de scripting de Overlays de Ogre permite denir plantillas de estilo que pueden utilizar los elementos y contenedores. En este ejemplo se han denido dos plantillas, una para texto genrico (de nombre MyTemplates/Text ), y otra para texto pequeo (MyTemplates/SmallText). Para aplicar estas plantillas a un elemento del Overlay, basta con indicar seguido de dos puntos el nombre de la plantilla a continuacin del elemento (ver Figura 6.8). En el listado del Overlay denido, se ha trabajado con el modo de especicacin del tamao en pxeles. La alineacin de los elementos se realiza a nivel de pxel (en lugar de ser relativo a la resolucin de la pantalla), obteniendo un resultado como se muestra en la Figura 6.8. El uso de valores negativos en los campos de alineacin permite posicionar con exactitud los paneles alineados a la derecha y en el borde inferior. Por ejemplo, en el caso del panel logoUCLM, de tamao (150x120), la alineacin horizontal se realiza a la derecha. El valor de -180 en el campo left indica que queremos que quede un margen de 30 pxeles entre el lado derecho de la ventana y el extremo del logo.

6.4. Uso de Overlays

[129]

1024x768

1280x800

800x600

Figura 6.9: Resultado de ejecucin del ejemplo de uso de Overlays, combinado con los resultados parciales de las secciones anteriores. La imagen ha sido generada con 3 conguraciones de resolucin diferentes (incluso con diferente relacin de aspecto): 1280x800, 1024x768 y 800x600.

Los Overlays tienen asociada una profundidad, denida en el campo zorder (ver Figura 6.8), en el rango de 0 a 650. Overlays con menor valor de este campo sern dibujados encima del resto. Esto nos permite denir diferentes niveles de despliegue de elementos 2D. Para nalizar estudiaremos la modicacin en el cdigo de MyApp y MyFrameListener. En el siguiente listado se muestra que el constructor del FrameListener (lnea 7 ) necesita conocer el OverlayManager, cuya referencia se obtiene en la lnea 14 . En realidad no sera necesario pasar el puntero al constructor, pero evitamos de esta forma que el FrameListener tenga que solicitar la referencia. , obtenemos el Overlay llamado Info (denido en En las lneas 15-16 el listado de la Figura 6.8), y lo mostramos. nalizar, el cdigo del FrameListener denido en las lneas Para 6-16 del siguiente listado parcial, modica el valor del texto asociado a los elementos de tipo TextArea. Hacemos uso de la clase auxiliar Ogre::StringConverter que facilita la conversin a String de ciertos tipos de datos (vectores, cuaternios...).

[130]

CAPTULO 6. GESTIN MANUAL OGRE 3D

Listado 6.10: Modicacin en MyApp.cpp


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

int MyApp::start() { ... loadResources(); createScene(); createOverlay(); // Metodo propio para crear el overlay ... _framelistener = new MyFrameListener(window, cam, node, _overlayManager); _root->addFrameListener(_framelistener); ... } void MyApp::createOverlay() { _overlayManager = Ogre::OverlayManager::getSingletonPtr(); Ogre::Overlay *overlay = _overlayManager->getByName("Info"); overlay->show(); }

Listado 6.11: Modicacin en MyFrameListener.cpp


1 bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { 2 ... 3 _camera->yaw(Ogre::Radian(rotx)); 4 _camera->pitch(Ogre::Radian(roty)); 5 6 Ogre::OverlayElement *oe; 7 oe = _overlayManager->getOverlayElement("fpsInfo"); 8 oe->setCaption(Ogre::StringConverter::toString(fps)); 9 oe = _overlayManager->getOverlayElement("camPosInfo"); 10 oe->setCaption(Ogre::StringConverter::toString(_camera-> 11 12

13 14 15 16 17 18 return true; 19 }

getPosition())); oe = _overlayManager->getOverlayElement("camRotInfo"); oe->setCaption(Ogre::StringConverter::toString(_camera-> getDirection())); oe = _overlayManager->getOverlayElement("modRotInfo"); Ogre::Quaternion q = _node->getOrientation(); oe->setCaption(Ogre::String("RotZ: ") + Ogre::StringConverter::toString(q.getYaw()));

Captulo

Interaccin y Widgets
Csar Mora Castro

omo se ha visto a lo largo del curso, el desarrollo de un videojuego requiere tener en cuenta una gran variedad de disciplinas y aspectos: grcos 3D o 2D, msica, simulacin fsica, efectos de sonido, jugabilidad, eciencia, etc. Uno de los aspectos a los que se les suele dar menos importancia, pero que juegan un papel fundamental a la hora de que un juego tenga xito o fracase, es la interfaz de usuario. Sin embargo, el mayor inconveniente es que la mayora de los motores grcos no dan soporte para la gestin de Widgets, y realizarlos desde cero es un trabajo ms costoso de lo que pueda parecer. En este captulo se describe de forma general la estructura y las guas que hay que tener en cuenta a la hora de disear y desarrollar una interfaz de usuario. Adems, se explicar el uso de CEGUI, una biblioteca de gestin de Widgets para integrarlos en motores grcos.
Eciencia y diseo
Para desarrollar un videojuego, tan importante es cuidar la eciencia y optimizarlo, como que tenga un diseo visualmente atractivo.

7.1.

Interfaces de usuario en videojuegos

Las interfaces de usuario especcas de los videojuegos deben tener el objetivo de crear una sensacin positiva, que consiga la mayor inmersin del usuario posible. Estas interfaces deben tener lo que se denomina ow. El ow[18] es la capacidad de atraer la atencin del usuario, manteniendo su concentracin, la inmersin dentro de la trama del videojuego, y que consiga producir una experiencia satisfactoria.

131

[132]

CAPTULO 7. INTERACCIN Y WIDGETS

Cada vez se realizan estudios ms serios sobre cmo desarrollar interfaces que tengan ow, y sean capaces de brindar una mejor experiencia al usuario. La principal diferencia con las interfaces de usuario de aplicaciones no orientadas al ocio, es que estas centran su diseo en la usabilidad y la eciencia, no en el impacto sensorial. Si un videojuego no consigue atraer y provocar sensaciones positivas al usuario, este posiblemente no triunfar, por muy eciente que sea, o por muy original o interesante que sea su trama. A continuacin se detalla una lista de aspectos a tener en cuenta que son recomendables para aumentar el ow de un videojuego, aunque tradicionalmente se han considerado perjudiciales a la hora de disear interfaces tradicionales segn las reglas de interaccin persona-computador: Mostrar la menor cantidad de informacin posible : durante el transcurso del juego, es mejor no sobrecargar la interfaz con una gran cantidad de informacin. En la gran mayora de videojuegos, toda esta conguracin se establece antes de comenzar el juego (por ejemplo, en el Men ), por lo que la interfaz queda menos sobrecargada y distrae menos al usuario. Incluso el usuario puede tener la opcin de mostrar menos informacin an si lo desea. Inconsistencia de acciones: en algunos casos, es posible que se den inconsistencias en las acciones dependiendo del contexto del personaje. Por ejemplo, el botn de saltar cuando el personaje est en tierra puede ser el de nadar si de repente salta al agua. Es importante mantener un nmero reducido de teclas (tanto si es por limitaciones de la plataforma, como una videoconsola, como para hacer la usabilidad ms sencilla al usuario). Por lo tanto, hay que conseguir agrupar las acciones en los botones segn su naturaleza. Por ejemplo, un botn lleva a cabo acciones con objetos y peronajes (hablar, abrir una puerta), y otro movimientos de desplazamiento (saltar, escalar). Esto aumentar la intuitividad y la usabilidad del videojuego, y por lo tanto, su ow. Dicultar los objetivos al usuario: una de las reglas de oro de la interaccin persona-computador es prevenir al usuario de cometer errores. Sin embargo, en los videojuegos esta regla puede volverse contradictoria, pues en la mayora de los casos el usuario busca en los videojuegos un sentimiento de satisfaccin que se logra por medio de la superacin de obstculos y desafos. Por lo tanto, es tambin de vital importancia conseguir un equilibrio en la dicultad del juego, que no sea tan difcil como para frustrar al usuario, pero no tan fcil como para que resulte aburrido. En este aspecto la interfaz juega un papel de mucho peso. Se ha visto cmo el caso particular de las interfaces de los videojuegos puede contradecir reglas que se aplican en el diseo de interfaces de usuario clsicas en el campo de la interaccin persona-computador. Sin embargo, existen muchas recomendaciones que son aplicables a ambos tipos de interfaces. A continuacin se explican algunas:

7.1. Interfaces de usuario en videojuegos

[133]

Mantener una organizacin intuitiva: es importante que el diseo de los mens sean intuitivos. En muchos casos, esta falta de organizacin crea confusin innecesaria al usuario. Ofrecer una legibilidad adecuada: en algunos casos, darle demasiada importancia a la esttica puede implicar que la legibilidad del texto de las opciones o botones se vea drsticamente reducida. Es importante mantener la funcionalidad bsica. Esperas innecesarias: en multitud de videojuegos, el usuario se ve forzado a esperar a que una determinada pelcula o animacin se reproduzca de forma completa, sin poder omitirla. Incluso en el caso en que pueda omitirse, el usuario ha debido esperar previamente a la carga del clip de vdeo para despus poder omitirla. Este tipo de inconvenientes reduce notablemente el ow de la aplicacin. Existen multitud de formas en las que el usuario realiza esperas innecesarias, y que aumenta su frustracin. Por ejemplo, si quiere volver a repetir una accin, tiene que volver a conrmar uno por uno todos los parmetros, aunque estos no cambien. Este es el caso de los juegos de carreras, en el que para volver a repetir una carrera es necesario presionar multitud botones e incluso esperar varios minutos. Ayuda en lnea: muchas veces el usuario necesita consultar el manual durante el juego para entender alguna caracterstica de l. Sin embargo, este manual es documentacin extensa que no rompe con la inmersin del videojuego. Es conveniente que se proporcione una versin suave, acorde con la esttica y que muestre la informacin estrictamente necesaria. En general, es importante tener en cuenta cuatro puntos importantes: 1. Intuitividad: cun fcil es aprender a usar una interfaz de un videojuego. 2. Eciencia: cun rpido se puede realizar una tarea, sobretodo si es muy repetitiva. 3. Simplicidad: mantener los controles y la informacin lo ms minimalista posible. 4. Esttica: cun sensorialmente atractiva es la interfaz. Una vez vistas algunas guas para desarrollar interfaces de usuario de videojuegos atractivas y con ow, se va a describir la estructura bsica que deben tener. Existe una estructura bsica que un videojuego debe seguir. No es buena prctica comenzar el juego directamente en el terreno de juego o campo de batalla. La estructura tpica que debe seguir la interfaz de un videojuego es la siguiente:

[134]

CAPTULO 7. INTERACCIN Y WIDGETS

Figura 7.2: Extracto del men de conguracin de Nexuiz (izquierda ), e interfaz de ScummVM (derecha ).

En primer lugar, es buena prctica mostrar una splash screen. Este tipo de pantallas se muestran al ejecutar el juego, o mientras se carga algn recurso que puede durar un tiempo considerable, y pueden ser usadas para mostrar informacin sobre el juego o sobre sus desarrolladores. Suelen mostrarse a pantalla completa, o de menor tamao pero centradas. La Figura 7.1 muestra la splash screen del juego free orion. Las otros dos elementos de la esctructura de un videojuego son el Men y el HUD. Suponen una parte muy importante de la interfaz de un juego, y es muy comn utilizar Widgets en ellos. A continuacion se analizarn ms en detalle y se mostrarn algunos ejemplos.
Figura 7.1: Ejemplo de Splash Screen durante la carga del juego FreeOrion.

7.1.1. Men
Todos los videojuegos deben tener un Men desde el cual poder elegir los modos de juego, congurar opciones, mostrar informacin adicional y otras caractersticas. Dentro de estos mens, es muy frecuente el uso de Widgets como botones, barras deslizantes (por ejemplo, para congurar la resolucin de pantalla), listas desplegables (para elegir idioma), o check buttons (para activar o desactivar opciones). Por eso es importante disponer de un buen repertorio de Widgets, y que sea altamente personalizable para poder adaptarlos al estilo visual del videojuego. En la Figura 7.2 se puede apreciar ejemplos de interfaces de dos conocidos juegos open-source. La interfaz de la izquierda, correspondiente al juego Nexuiz, muestra un trozo de su dialogo de conguracin, mientras que la de la derecha corresponde a la interfaz de ScummVM. En estos pequeos ejemplos se muestra un nmero considerable de Widgets, cuyo uso es muy comn: Pestaas: para dividir las opciones por categoras. Barras de desplazamiento: para congurar opciones que pueden tomar valores muy numerosos. Radio buttons: parmetros que pueden tomar valores excluyentes

7.2. Introduccin CEGUI

[135]

Figura 7.3: Screenshot del HUD del juego FreeOrion.

entre ellos. Check buttons: activan o desactivan una opcin.

7.1.2. HUD
En relacin a las interfaces de los videojuegos, concretamente se denomina HUD (del ingls, Head-Up Display), a la informacin y elementos de interaccin mostrados durante el propio transcurso de la partida. La informacin que suelen proporcionar son la vida de los personajes, mapas, velocidad de los vehculos, etc. En la Figura 7.3 se muestra una parte de la interfaz del juego de estrategia ambientada en el espacio FreeOrion. La interfaz utiliza elementos para mostrar los parmetros del juego, y tambin utiliza Widgets para interactuar con l. Como se puede intuir, el uso de estos Widgets es muy comn en cualquier videojuego, independientemente de su complejidad. Sin embargo, crear desde cero un conjunto medianamente funcional de estos es una tarea nada trivial, y que roba mucho tiempo de la lnea principal de trabajo, que es el desarrollo del propio videojuego. Una vez que se ha dado unas guas de estilo y la estructura bsicas para cualquier videojuego, y se ha mostrado la importancia de los Widgets en ejemplos reales, se va a estudiar el uso de una potente biblioteca que proporciona estos mismos elementos para distintos motores grcos, para que el desarrollo de Widgets para videojuegos sea lo menos problemtico posible.
CEGUIs mission
Como dice en su pgina web, CEGUI est dirigido a desarrolladores de videojuegos que deben invertir su tiempo en desarrollar buenos juegos, no creando subsistemas de interfaces de usuario.

7.2.

Introduccin CEGUI

CEGUI (Crazy Eddies GUI)[1] (Crazy Eddies GUI ) es una biblioteca open source multiplataforma que proporciona entorno de ventanas y Widgets para motores grcos, en los cuales no se da soporte nativo, o es muy deciente. Es orientada a objetos y est escrita en C++.

[136]

CAPTULO 7. INTERACCIN Y WIDGETS

CEGUI es una biblioteca muy potente en pleno desarrollo, por lo que est sujeta a continuos cambios. Todas las caractersticas y ejemplos descritos a lo largo de este captulo se han creado utilizando la versin actualmente estable, la 0.7.x. No se asegura el correcto funcionamiento en versiones anteriores o posteriores.

CEGUI es muy potente y exible. Es compatible con los motores grcos OpenGL, Direct3D, Irrlicht y Ogre3D. De la misma forma que Ogre3D es nicamente un motor de rendering, CEGUI es slo un motor de de gestin de Widgets, por lo que el renderizado y la gestin de eventos de entrada deben ser realizadas por bibliotecas externas. En sucesivas secciones se explicar cmo integrar CEGUI con las aplicaciones de este curso que hacen uso de Ogre3D y OIS. Adems se mostrarn ejemplos prcticos de las caractersticas ms importantes que ofrece.

CEGUI y Ogre3D
A lo largo de estos captulos, se utilizar la frmula CEGUI/Ogre3D/OIS para proveer interfaz grca, motor de rendering y gestin de eventos a los videojuegos, aunque tambin es posible utilizarlo con otras bibliotecas (ver documentacin de CEGUI).

7.2.1. Instalacin
En las distribuciones actuales ms comunes de GNU/Linux (Debian, Ubuntu), est disponible los paquetes de CEGUI para descargar, sin embargo estos dependen de la versin 1.7 de Ogre, por lo que de momento no es posible utilizar la combinacin CEGUI+OGRE 1.8 desde los respositorios. Para ello, es necesario descargarse el cdigo fuente de la ltima versin de CEGUI y compilarla. A continuacin se muestran los pasos. Descargar la ltima versin estable (0.7.7) desde la pgina web (www.cegui.org.uk ), ir a la seccin Downloads (columna de la izquierda). Pinchar sobre la versin 0.7.7, y en la seccin CEGUI 0.7.7 Library Source Downloads descargar la versin para GNU/Linux. Una vez descomprimido el cdigo fuente, para compilar e instalar la biblioteca se ejecutan los siguientes comandos:
./configure cegui_enable_ogre=yes make && sudo make install

Despus de ejecutar el ./configure, es importante asegurarse de que en el resumen se muestre, bajo la seccin Renderer Modules, la opcin Building Ogre Renderer: yes.

7.2. Introduccin CEGUI

[137]

Estos pasos instalarn CEGUI bajo el directorio /usr/local/, por lo que es importante indicar en el Makele que las cabeceras las busque en el directorio /usr/local/include/CEGUI. Adems, algunos sistemas operativos no buscan las bibliotecas de enlazado dinmico en /usr/local/lib por defecto. Esto produce un error al ejecutar la aplicacin indicando que no puede encontrar las bibliotecas libCEGUI*. Para solucionarlo, se puede editar como superusuario el chero /etc/ld.so.conf, y aadir la lnea include /usr/local/lib. Para que los cambios surtan efecto, ejecutar sudo ldconfig.

7.2.2. Inicializacin
La arquitectura de CEGUI es muy parecida a la de Ogre3D, por lo que su uso es similar. Est muy orientado al uso de scripts, y hace uso del patrn Singleton para implementar los diferentes subsistemas. Los ms importantes son: CEGUI::System: gestiona los parmetros y componentes ms importantes de la biblioteca. CEGUI::WindowManager: se encarga de la creacin y gestin de las windows de CEGUI. CEGUI::SchemeManager: gestiona los diferentes esquemas que utilizar la interfaz grca. CEGUI::FontManager: gestiona los distintos tipos de fuentes de la interfaz. Estos subsistemas ofrecen funciones para poder gestionar los diferentes recursos que utiliza CEGUI. A continuacin se listan estos tipos de recursos: Schemes: tienen la extensin .scheme. Denen el repertorio (o esquema) de Widgets que se utilizarn. Tambin indica qu scripts utilizar de otros tipos, como por ejemplo el ImageSet, las Fonts o el LookNFeel. Imageset: tienen la extensin .imageset. Dene cules sern la imgenes de los elementos de la interfaz (punteros, barras, botones, etc). LookNFeel: tienen la extensin .looknfeel. Dene el comportamiento visual de cada uno de los Widgets para distintas acciones, por ejemplo, cmo se muestran cuando se pasa el puntero del ratn o cuando se presionan, Fonts: tienen la extensin .font. Cada uno de los scripts dene un tipo de fuente junto con propiedades especcas como su tamao.

[138]

CAPTULO 7. INTERACCIN Y WIDGETS

Layouts: tienen la extensin .layout. Cada script dene clases de ventanas concretas, con cada uno de sus elementos. Por ejemplo, una ventana de chat o una consola. Segn se avance en el captulo se ir estudiando ms en profundidad cul es el funcionamiento y la estructura de estos recursos. En el siguiente cdigo se muestran los primeros pasos para poder integrar CEGUI con Ogre3D, y de qu forma se inicializa.
Listado 7.1: Inicializacn de CEGUI para su uso con Ogre3D
0 #include <CEGUI.h> 1 #include <RendererModules/Ogre/CEGUIOgreRenderer.h> 2 3 CEGUI::OgreRenderer* renderer = &CEGUI::OgreRenderer::

bootstrapSystem();
4 5 6 7 8 9

CEGUI::Scheme::setDefaultResourceGroup("Schemes"); CEGUI::Imageset::setDefaultResourceGroup("Imagesets"); CEGUI::Font::setDefaultResourceGroup("Fonts"); CEGUI::WindowManager::setDefaultResourceGroup("Layouts"); CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel");

Este mtodo de inicializar el renderer utilizando el bootstrapSystem fue introducido a partir de la versin 0.7.1. Para inicializar CEGUI en versiones anteriores, es necesario referirse a su documentacion.

En las lneas 1 y 2 se insertan las cabeceras necesarias. La primera incluye la biblioteca general, y en la segunda se indica de forma concreta que se va a utilizar el motor grco Ogre3D. En la lnea 4 se inicializa CEGUI para ser utilizado con Ogre3D. Adems es necesario indicar dnde estarn los recursos que utilizar la interfaz grca, tanto los scripts que utiliza, como las fuentes o las imgenes. Dependiendo de la distribucin que se utilice, estos recursos pueden venir con el paquete del repositorio o no. En este ejemplo vamos a considerar que debemos descargarlos aparte. Se pueden conseguir directamente descargando el cdigo fuente de CEGUI desde su pgina[1]. Las distribuciones que los proporcionan, suelen situarlos en /usr/share/CEGUI/ o /usr/local/share/CEGUI/ Para que CEGUI pueda encontrar los recursos, es necesario aadir estos grupos al chero resources.cfg de Ogre.
Listado 7.2: Contenido del chero resources.cfg.
0 1 2 3 4 5

[General] FileSystem=media [Schemes] FileSystem=media/schemes [Imagesets] FileSystem=media/imagesets

7.2. Introduccin CEGUI

[139]

6 7 8 9 10 11

[Fonts] FileSystem=media/fonts [Layouts] FileSystem=media/layouts [LookNFeel] FileSystem=media/looknfeel

Y las opciones que hay que aadir al Makele para compilar son:
Listado 7.3: Flags de compilacin y de enlazado de CEGUI.
0 1 2 3 4 5

#Flags de compilado CXXFLAGS += pkg-config --cflags CEGUI-OGRE #Flags de enlazado LDFLAGS += pkg-config --libs-only-L CEGUI-OGRE LDLIBS += pkg-config --libs-only-l CEGUI-OGRE

Es importante incluir los ags de compilado, en la lnea 2, para que encuentre las cabeceras segn se han indicado en el ejemplo de inicializacin. Esto es slo el cdigo que inicializa la biblioteca en la aplicacin para que pueda comenzar a utilizar CEGUI como interfaz grca, todava no tiene ninguna funcionalidad. Pero antes de empezar a aadir Widgets, es necesario conocer otros conceptos primordiales.

7.2.3. El Sistema de Dimensin Unicado


El posicionamiento y tamao de los distintos Widgets no es tan trivial como indicar los valores absolutos. Puede ser deseable que un Widget se reposicione y redimensione si el Widget al que pertenece se redimensiona, por ejemplo.

(left, top)

CEGUI utiliza lo que denomina el Sistema de Dimensin Unicado (Unied Dimension System ). El elemento principal de este sistema es:

Widget

CEGUI::UDim(scale, offset) Indica la posicin en una dimensin. El primer parmetro indica la posicin relativa, que toma un valor entre 0 y 1, mientras que el segundo indica un desplazamiento absoluto en pxeles. Por ejemplo, supongamos que posicionamos un Widget con UDim 0.5,20 en la dimensin x. Si el ancho de la pantalla fuese 640, la posicin sera 0.5*640+20 = 340, mientras que si el ancho fuese 800, la posicin seri 0.5*800+20 = 420. En la Figura 7.5 se aprecian los dos ejemplos de forma grca. De esta forma, si la resolucin de la pantalla cambia, por ejemplo, el Widget se reposicionar y se redimensionar de forma automtica. Teniendo en cuenta cmo expresar el posicionamiento en una nica dimensin utilizando UDim, se denen dos elementoss ms.

(right, bottom)
Figura 7.4: rea rectangular denida por URect.

[140]

CAPTULO 7. INTERACCIN Y WIDGETS

0.5

20 px

0.5

20 px

640x480

800x600

Coordenada x
Figura 7.5: Ejemplo del funcionamiento de UDim.

Para denir un punto o el tamao de un Widget se usa: CEGUI::UVector2(UDim x, UDim y) que est compuesto por dos UDim, uno para la coordenada x, y otro para la y, o para el ancho y el alto, dependiendo de su uso. El segundo elemento, se utiliza para denir un rea rectangular: CEGUI::URect(UDim left, UDim top, UDim right, UDIM bottom) Como muestra la Figura 7.4, los dos primeros denen la esquina superior izquierda, y los dos ltimos la esquina inferior derecha.

7.2.4. Deteccin de eventos de entrada


Puesto que CEGUI es nicamente un motor de gestin de Widgets, tampoco incorpora la deteccin de eventos de entrada, por lo que es necesario inyectrselos desde otra biblioteca. En este caso, se aprovechar la que ya se ha estudiado: OIS. Considerando que se utiliza OIS mediante callbacks (en modo buffered ), hay que aadir las siguientes lneas para enviar a CEGUI la pulsacin y liberacin de teclas y de los botones del ratn.
Listado 7.4: Inyeccin de eventos de pulsacin y liberacin de teclas a CEGUI.
0 bool MyFrameListener::keyPressed(const OIS::KeyEvent& evt) 1 { 2 CEGUI::System::getSingleton().injectKeyDown(evt.key); 3 CEGUI::System::getSingleton().injectChar(evt.text); 4 5 return true; 6 }

7.2. Introduccin CEGUI

[141]

7 8 9 10 11 12 13 14 15 16 17

bool MyFrameListener::keyReleased(const OIS::KeyEvent& evt) { CEGUI::System::getSingleton().injectKeyUp(evt.key); return true; } bool MyFrameListener::mousePressed(const OIS::MouseEvent& evt, OIS ::MouseButtonID id) { CEGUI::System::getSingleton().injectMouseButtonDown( convertMouseButton(id)); return true; }

18 19 20 21 bool MyFrameListener::mouseReleased(const OIS::MouseEvent& evt, OIS

::MouseButtonID id)
22 { 23 CEGUI::System::getSingleton().injectMouseButtonUp(

convertMouseButton(id));
24 return true; 25 }

Adems, es necesario convertir la forma en que identica OIS los botones del ratn, a la que utiliza CEGUI, puesto que no es la misma, al contrario que sucede con las teclas del teclado. Para ello se ha escrito la funcin convertMouseButton():
Listado 7.5: Funcin de conversin entre identicador de botones de ratn de OIS y CEGUI.
0 CEGUI::MouseButton MyFrameListener::convertMouseButton(OIS::

MouseButtonID id)
1 { 2 CEGUI::MouseButton ceguiId; 3 switch(id) 4 { 5 case OIS::MB_Left: 6 ceguiId = CEGUI::LeftButton; 7 break; 8 case OIS::MB_Right: 9 ceguiId = CEGUI::RightButton; 10 break; 11 case OIS::MB_Middle: 12 ceguiId = CEGUI::MiddleButton; 13 break; 14 default: 15 ceguiId = CEGUI::LeftButton; 16 } 17 return ceguiId; 18 }

Por otro lado, tambin es necesario decir a CEGUI cunto tiempo ha pasado desde la deteccin del ltimo evento, por lo que hay que aadir la siguiente lnea a la funcin frameStarted():

[142]

CAPTULO 7. INTERACCIN Y WIDGETS

Listado 7.6: Orden que indica a CEGUI el tiempo transcurrido entre eventos.
0 CEGUI::System::getSingleton().injectTimePulse(evt.

timeSinceLastFrame)

Hasta ahora se ha visto el funcionamiento bsico de CEGUI, los tipos bsicos de scripts que dene, la inicializacin, el sistema de posicionamiento y dimensionado que utiliza e incluso como enviarle eventos de entrada. Una vez adquiridos estos conocimientos, es momento de crear la primera aplicacin de Ogre que muestre un Widget con funcionalidad, como se describir en la siguiente seccin.

7.3.

Primera aplicacin

En esta seccin se van a poner en prctica los primeros conceptos descritos para crear una primera aplicacin. Esta aplicacin tendr toda la funcionalidad de Ogre (mostrando a Sinbad), y sobre l un botn para salir de la aplicacin.

Es importante tener en cuenta que en CEGUI, todos los elementos son Windows . Cada uno de los Windows puede contener a su vez otros Windows. De este modo, pueden darse situaciones raras como que un botn contenga a otro botn, pero que en la prctica no suceden.

Listado 7.7: Cdigo de la funcin createGUI().


0 void MyApp::createGUI() 1 { 2 renderer = &CEGUI::OgreRenderer::bootstrapSystem(); 3 CEGUI::Scheme::setDefaultResourceGroup("Schemes"); 4 CEGUI::Imageset::setDefaultResourceGroup("Imagesets"); 5 CEGUI::Font::setDefaultResourceGroup("Fonts"); 6 CEGUI::WindowManager::setDefaultResourceGroup("Layouts"); 7 CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel"); 8 9 CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme") 10 11 12 13 14 15 16 17 18 19

; CEGUI::System::getSingleton().setDefaultFont("DejaVuSans-10"); CEGUI::System::getSingleton().setDefaultMouseCursor("TaharezLook" ,"MouseArrow"); //Creating GUI Sheet CEGUI::Window* sheet = CEGUI::WindowManager::getSingleton(). createWindow("DefaultWindow","Ex1/Sheet"); //Creating quit button CEGUI::Window* quitButton = CEGUI::WindowManager::getSingleton(). createWindow("TaharezLook/Button","Ex1/QuitButton"); quitButton->setText("Quit"); quitButton->setSize(CEGUI::UVector2(CEGUI::UDim(0.15,0),CEGUI:: UDim(0.05,0)));

7.3. Primera aplicacin

[143]

20 21 22 23 24 25 26 }

quitButton->setPosition(CEGUI::UVector2(CEGUI::UDim(0.5-0.15/2,0) ,CEGUI::UDim(0.2,0))); quitButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&MyFrameListener::quit, _framelistener)); sheet->addChildWindow(quitButton); CEGUI::System::getSingleton().setGUISheet(sheet);

La funcin createGUI() se encarga de la inicializacin de la interfaz grca y de la creacin de los elementos que contendr. Como se explic en la Seccin 7.2.2, de las lneas 3-8 se indica que se quiere utilizar Ogre3D como motor de rendering, y se indica a CEGUI dnde estn los distintos recursos. En la lnea 10 se crea el esquema que se va a utilizar. Se recuerda que un esquema dena el conjunto de Widgets que se podrn utilizar en la aplicacin, junto a los tipos de letras, apariencia o comportamiento visual. Es como la eleccin del tema de la interfaz. El chero de script TaharezLook.scheme debe de encontrarse en algn lugar del que CEGUI tenga constancia. Como se ha denido en el chero resources.cfg, los esquemas (Schemes) deben estar en media/schemes. Desde su pgina web se pueden descargar otros ejemplos, como el esquema Vanilla. Ms adelante se analizar brevemente el contenido de estos scripts, para poder ajustar la interfaz grca a la esttica del videojuego. En las lneas 11 y 12 se denen algunos parmetros por defecto. En el primer caso, el tipo de letra predeterminada, y en el segundo el cursor, ambos elementos denidos en TaharezLook.scheme.
Convenio de nombrado
CEGUI no exige que se siga ningn convenio de nombrado para sus elementos. Sin embargo, es altamente recomendable utilizar un convenio jerrquico, utilizando la barra / como separador.

Los Widgets de la interfaz grca se organizan de forma jerrquica, de forma anloga al grafo de escena Ogre. Cada Widget (o Window) debe pertenecer a otro que lo contenga. De este modo, debe de haber un Widget padre o raz. Este Widget se conoce en CEGUI como Sheet (del ingls, hoja, rerindose a la hoja en blanco que contiene todos los elementos). Esta se crea en la lnea 15. El primer parmetro indica el tipo del Window, que ser un tipo genrico, DefaultWindow. El segundo es el nombre que se le da a ese elemento. Con Ex1 se hace referencia a que es el primer ejemplo (Example1), y el segundo es el nombre del elemento. El siguiente paso es crear el botn. En la lnea 18 se llama al WindowManager para crear un Window (hay que recordar que en CEGUI todo es un Window). El primer parmetro indica el tipo, denido en el esquema escogido, en este caso un botn. El segundo es el nombre del elemento, para el cual se sigue el mismo convenio de nombrado que para el Sheet. Despus se indican algunos parmetros del botn. En la lnea 19 se indica el texto del botn, utilizando la fuente predeterminada del sistema que se indic en la inicializacin.

[144]

CAPTULO 7. INTERACCIN Y WIDGETS

En la lnea 20 se indica el tamao. Como se explic en la Seccin 7.2.3, para el tamao se utiliza un UVector2, que contiene dos valores, ancho y alto. Por lo tanto, el ancho de este botn siempre ser 0.15 del ancho del Sheet, y el alto ser 0.05. Para indicar la posicin del Widget, se opta por centrarlo horizontalmente. Como se puede ver en la lnea 21, para la posicin en la dimensin x se indica la mitad del ancho del Sheet, 0.5, menos la mitad del ancho del Widget, es decir, 0.15/2 (el tamao se acaba de indicar en la lnea 20). Esto se debe a que el posicionamiento toma como punto de referencia la esquina superior izquierda del Widget. Para la posicin en el eje y se ha optado por un 0.2 del alto del Sheet. Hasta el momento se ha creado el Sheet que contendr todo el conjunto de Widgets, un botn con el texto Quit, y con un tamao y apariencia determinado. Ahora se le va a asociar un comportamiento para cuando se pulse. Para asociar comportamientos, es necesario suscribir las funciones que implementan el comportamiento a los elementos. En la lnea 22 se asocia ese comportamiento. El primer parmetro indica a qu tipo de accin se asocia el comportamiento, y en el segundo qu funcin se ejecuta. Existen una extensa lista de acciones a las que se pueden asociar comportamientos, como por ejemplo: MouseClicked MouseEnters MouseLeaves EventActivated EventTextChanged EventAlphaChanged EventSized Como se ha estudiado anteriormente, al igual que pasa con el grafo de escena de Ogre3D, cada Window de CEGUI debe tener un padre. En la lnea 25 se asocia el botn al Sheet, y por ltimo, en la lnea 26 se indica a CEGUI cul es el Sheet que debe mostrar. A continuacin se muestra la denicin de la funcin que implementa el comportamiento. Como se puede apreciar, simplemente cambia el valor de una variable booleana que controla la salida de la aplicacin. Es importante tener en cuenta que no todas las funciones pueden ser utilizadas para implementar el comportamiento de los elementos. En su signatura, deben de tener como valor de retorno bool, y aceptar un nico parmetro del tipo const CEGUI::EventArgs& e
Figura 7.6: Screenshot de la primera aplicacin de ejemplo.

7.4. Tipos de Widgets

[145]
Listado 7.8: Funcin que implementa el comportamiento del botn al ser pulsado.
0 bool MyFrameListener::quit(const CEGUI::EventArgs &e) 1 { 2 _quit = true; 3 return true; 4 }

En la Figura 7.6 se puede ver una captura de esta primera aplicacin. Ya que se ha visto cmo inicializar CEGUI y cul es su funcionamiento bsico, es momento de comenzar a crear interfaces ms complejas, tiles, y atractivas.

7.4.

Tipos de Widgets

Para comenzar a desarrollar una interfaz grca con CEGUI para un videojuego, primero es necesario saber cul es exactamente el repertorio de Widgets disponible. Como se ha estudiado en secciones anteriores, el repertorio como tal est denido en el esquema escogido. Para los sucesivos ejemplos, vamos a utilizar el esquema TaharezLook, utilizado tambin en la primera aplicacin de inicializacin. CEGUI proporciona otros esquemas que ofrecen otros repertorios de Widgets, aunque los ms comunes suelen estar implementados en todos ellos. Otros esquemas que proporciona CEGUI son OgreTray, VanillaSkin y WindowsLook. El script del esquema dene adems la apariencia y el comportamiento visual de los Widgets. Para cambiar la apariencia visual, no es necesario crear un chero esquema desde cero (lo que sera una ardua tarea). Basta con cambiar el script de los ImageSet y de los Fonts. Esto se estudiar con ms profundidad en la Seccin 7.8. A continuacin se muestra una pequea lista de los Widgets ms importantes denidos en el esquema TaharezLook : Button Check Box Combo Box Frame Window List Box Progress Bar Slider Static Text etc

[146]

CAPTULO 7. INTERACCIN Y WIDGETS

El siguiente paso en el aprendizaje de CEGUI es crear una interfaz que bien podra servir para un juego, aprovechando las ventajas que proporcionan los scripts.

7.5. Layouts
Los scripts de layouts especican qu Widgets habr y su organizacin para una ventana especca. Por ejemplo, un layout llamado chatBox.layout puede contener la estructura de una ventana con un editBox para insertar texto, un textBox para mostrar la conversacin, y un button para enviar el mensaje. De cada layout se pueden crear tantas instancias como se desee. No hay que olvidar que estos cheros son xml, por lo que deben seguir su estructura. La siguiente es la organizacin genrica de un recurso layout :
Listado 7.9: Estructura de un script layout.
0 <?xml version="1.0" encoding="UTF-8"?> 1 <GUILayout> 2 <Window Type="WindowType" Name="Window1"> 3 <Property Name="Property1" Value="Property1Value"/> 4 <Property Name="Property2" Value="Property2Value"/> 5 <!-- This is a comment --> 6 <Window Type="WindowType" Name="Window1/Window2"> 7 <Property Name="Property1" Value="Property1Value"/> 8 <Property Name="Property2" Value="Property2Value"/> 9 </Window> 10 <!-- ... --!> 11 </Window> 12 </GUILayout>

En la lnea 1 se escribe la cabecera del archivo xml, lo cual no tiene nada que ver con CEGUI. En la lnea 2 se abre la etiqueta GUILayout, para indicar el tipo de script y se cierra en la lnea 13. A partir de aqu, se denen los Windows que contendr la interfaz (en CEGUI todo es un Window!). Para declarar uno, se indica el tipo de Window y el nombre, como se puede ver en la lnea 3. Dentro de l, se especican sus propiedades (lneas 4 y 5). Estas propiedades pueden indicar el tamao, la posicin, el texto, la transparencia, etc. Los tipos de Widgets y sus propiedades se denan en el esquema escogido, por lo que es necesario consultar su documentacin especca. En la Seccin 7.6 se ver un ejemplo concreto. En la lnea 6 se muestra un comentario en xml. Despus de la denicin de las propiedades de un Window, se pueden denir ms Windows que pertenecern al primero, ya que los Widgets siguen una estructura jerrquica.

7.6. Ejemplo de interfaz

[147]

7.6.

Ejemplo de interfaz

El siguiente es el cdigo de un script layout que dene una ventana de conguracin, con distintos Widgets para personalizar el volumen, la resolucin, o el puerto para utilizar en modo multiplayer. Adems incorpora un botn para aplicar los cambios y otro para salir de la aplicacin. En la Figura 7.7 se muestra el resultado nal.
Figura 7.7: Resultado de la ventana de conguracin del ejemplo.

Listado 7.10: Ejemplo de layout para crear una ventana de conguracin.


0 <?xml version="1.0" encoding="UTF-8"?> 1 <GUILayout > 2 <Window Type="TaharezLook/FrameWindow" Name="Cfg" > 3 <Property Name="Text" Value="Cfguration Window" /> 4 <Property Name="TitlebarFont" Value="DejaVuSans-10" /> 5 <Property Name="TitlebarEnabled" Value="True" /> 6 <Property Name="UnifiedAreaRect" Value=" 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

{{0.133,0},{0.027,0},{0.320,300},{0.127,300}}" /> <!-- Sonud parameter --> <Window Type="TaharezLook/StaticText" Name="Cfg/SndText" > <Property Name="Text" Value="Sonud Volume" /> <Property Name="UnifiedAreaRect" Value=" {{0.385,0},{0.0316,0},{0.965,0},{0.174,0}}" /> </Window> <Window Type="TaharezLook/Spinner" Name="Cfg/SndVolume" > <Property Name="Text" Value="Sonud Volume" /> <Property Name="StepSize" Value="1" /> <Property Name="CurrentValue" Value="75" /> <Property Name="MaximumValue" Value="100" /> <Property Name="MinimumValue" Value="0" /> <Property Name="UnifiedAreaRect" Value=" {{0.0598,0},{0.046,0},{0.355,0},{0.166,0}}" /> </Window> <!-- Fullscreen parameter --> <Window Type="TaharezLook/StaticText" Name="Cfg/FullScrText" > <Property Name="Text" Value="Fullscreen" /> <Property Name="UnifiedAreaRect" Value=" {{0.385,0},{0.226,0},{0.965,0},{0.367,0}}" /> </Window> <Window Type="TaharezLook/Checkbox" Name="Cfg/FullscrCheckbox" > <Property Name="UnifiedAreaRect" Value=" {{0.179,0},{0.244,0},{0.231,0},{0.370,0}}" /> </Window> <!-- Port parameter --> <Window Type="TaharezLook/StaticText" Name="Cfg/PortText" > <Property Name="Text" Value="Port" /> <Property Name="UnifiedAreaRect" Value=" {{0.385,0},{0.420,0},{0.9656,0},{0.551,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Cfg/PortEditbox" > <Property Name="Text" Value="1234" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedAreaRect" Value=" {{0.0541,0},{0.417,0},{0.341,0},{0.548,0}}" /> <Property Name="TextParsingEnabled" Value="False" /> </Window> <!-- Resolution parameter --> <Window Type="TaharezLook/StaticText" Name="Cfg/ResText" > <Property Name="Text" Value="Resolution" />

[148]

CAPTULO 7. INTERACCIN Y WIDGETS

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

<Property Name="UnifiedAreaRect" Value=" {{0.385,0},{0.60,0},{0.965,0},{0.750,0}}" /> </Window> <Window Type="TaharezLook/ItemListbox" Name="Cfg/ResListbox" > <Property Name="UnifiedAreaRect" Value=" {{0.0530,0},{0.613,0},{0.341,0},{0.7904,0}}" /> <Window Type="TaharezLook/ListboxItem" Name="Cfg/Res/Item1"> <Property Name="Text" Value="1024x768"/> </Window> <Window Type="TaharezLook/ListboxItem" Name="Cfg/Res/Item2"> <Property Name="Text" Value="800x600"/> </Window> </Window> <!-- Exit button --> <Window Type="TaharezLook/Button" Name="Cfg/ExitButton" > <Property Name="Text" Value="Exit" /> <Property Name="UnifiedAreaRect" Value=" {{0.784,0},{0.825,0},{0.968,0},{0.966,0}}" /> </Window> <!-- Apply button --> <Window Type="TaharezLook/Button" Name="Cfg/ApplyButton" > <Property Name="Text" Value="Apply" /> <Property Name="UnifiedAreaRect" Value=" {{0.583,0},{0.825,0},{0.768,0},{0.969,0}}" /> </Window> </Window> </GUILayout>

Para comenzar, la lnea 2 dene el tipo de script, como se ha explicado en la Seccin anterior. El tipo de Window que contendr al resto es un TaharezLook/FrameWindow, y se le ha puesto el nombre Cfg. Es importante que el tipo del Window indique el esquema al que pertenece, por eso se antepone TaharezLook/. A partir de aqu se aaden el resto de Widgets. En total se han aadido 10 Widgets ms a la ventana Cfg: Una etiqueta (StaticText ) con el texto Sound Volume (llamada Cfg/SndText - lnea 9) y un Spinner para indicar el valor (llamado Cfg/SndVolume - lnea 13). Una etiqueta con el texto Fullscreen (lnea 22) y un Checkbox para activarlo y desactivarlo (lnea 26). Una etiqueta con el texto Port(lnea 30) y un EditBox para indicar el nmero de puerto (lnea 34). Una etiqueta con el texto Resolution (lnea 41) y un ItemListBox para elegir entre varias opciones (45). Un botn (Button ) con el texto Exit para terminar la aplicacin (lnea 55). Un botn con el texto Apply para aplicar los cambios (lnea 60). Cada uno de los Windows tiene unas propiedades para personalizarlos. En la documentacin se explican todas y cada una de las opciones de los Window en funcin del esquema que se utilice.

7.7. Editores de layouts grcos

[149]

Para indicar el valor de una propiedad en un chero de script cualquiera de CEGUI, se indica en el campo Value, y siempre entre comillas, ya sea un nmero, una cadena o una palabra reservada.

Estas son algunas de las propiedades utilizadas: Text: indica el texto del Widget. Por ejemplo, la etiqueta de un botn o el ttulo de una ventana. UniedAreaRect: es uno de los ms importantes. Indica la posicin y el tamao, mediante un objeto URect, de un Window relativo a su padre. Como se indic en secciones anteriores, se trata de cuatro UDim s (cada uno de ellos con un factor de escala relativo y un offset), para indicar la esquina superior izquierda del rectngulo (los dos primeros UDim s), y la inferior derecha. Es importante tener en cuenta que si al Widget hijo se le indique que ocupe todo el espacio (con el valor para la propiedad de {{0,0},{0,0},{1,0},{1,0}}), ocupar todo el espacio del Window al que pertenezca, no necesariamente toda la pantalla. TitlebarFont: indica el tipo de fuente utilizado en el ttulo de la barra de una FrameWindow. TitlebarEnabled: activa o desactiva la barra de ttulo de una FrameWindow. CurrentValue: valor actual de un Widget al que haya que indicrselo, como el Spinner. MaximumValue y MinimumValue : acota el rango de valores que puede tomar un Widget. Cada Widget tiene sus propiedades y uso especial. Por ejemplo, el Widget utilizado para escoger la resolucin (un ItemListBox ), contiene a su vez otros dos Window del tipo ListBoxItem, que representan cada una de las opciones (lneas 47 y 50). Para poder aadir funcionalidad a estos Widgets (ya sea asociar una accin o utilizar valores, por ejemplo), se deben recuperar desde cdigo mediante el WindowManager, con el mismo nombre que se ha especicado en el layout. Este script por tanto se utiliza nicamente para cambiar la organizacin y apariencia de la interfaz, pero no su funcionalidad. En este ejemplo concreto, slo se ha aadido una accin al botn con la etiqueta Exit para cerrar la aplicacin.

7.7.

Editores de layouts grcos

Este mtodo para disear interfaces de usuario directamente modicando los cheros xml .layout puede ser muy costoso. Existen un

[150]

CAPTULO 7. INTERACCIN Y WIDGETS

Figura 7.8: Interfaz de CEGUI Layout Editor II.

par de aplicaciones grcas para el diseo de las interfaces. La primera CEGUI Layout Editor es muy avanzada, pero se ha abandonado. Actualmente se est desarrollando un editor nuevo y actualizado, CEGUI Unied Editor, pero todava no se considera estable. Para compilar el editor, es necesario recompilar CEGUI con soporte para Python, pues es necesaria la biblioteca PyCEGUI. Para compilarla en Ubuntu 11.04 y 11.10 se puede seguir un tutorial disponible en la web de CEGUI[1], en el apartado HowTo, el tutorial Build PyCEGUI from source for Linux. Se puede encontrar un tutorial completo de cmo instalar el editor

en:

www.cegui.org.uk/wiki/index.php/CEED

Al tratarse de una versin inestable, es mejor consultar este tutorial para mantener los pasos actualizados de acuerdo a la ltima versin en desarrollo.

7.8.

Scripts en detalle

En esta Seccin se va a ver la estructura del resto de scripts que se utilizan para construir la interfaz. Es importante conocerlos para poder cambiar la apariencia y poder adaptarlas a las necesidades artsticas del proyecto.

7.8.1. Scheme
Los esquemas contienen toda la informacin para ofrecer Widgets a una interfaz, su apariencia, su comportamiento visual o su tipo de letra.

7.8. Scripts en detalle

[151]

Listado 7.11: Estructura de un script scheme.


0 <?xml version="1.0" ?> 1 <GUIScheme Name="TaharezLook"> 2 <Imageset Filename="TaharezLook.imageset" /> 3 <Font Filename="DejaVuSans-10.font" /> 4 <LookNFeel Filename="TaharezLook.looknfeel" /> 5 <WindowRendererSet Filename="CEGUIFalagardWRBase" /> 6 <FalagardMapping WindowType="TaharezLook/Button"

TargetType="CEGUI/PushButton" Renderer="Falagard/Button" LookNFeel="TaharezLook/Button" /> 7 <FalagardMapping WindowType="TaharezLook/Checkbox" TargetType="CEGUI/Checkbox" Renderer="Falagard/ ToggleButton" LookNFeel="TaharezLook/Checkbox" /> 8 </GUIScheme>

Al igual que suceda con los layout, comienzan con una etiqueta que identican el tipo de script. Esta etiqueta es GUIScheme, en la lnea 2. De las lneas 3-6 se indican los scripts que utilizar el esquema de los otros tipos. Qu conjunto de imgenes para los botones, cursores y otro tipo de Widgets mediante el Imageset (lnea 3), qu fuentes utilizar mediante un Font (lnea 4), y el comportamiento visual de los Widgets a travs del LookNFeel (lnea 5). Adems se indica qu sistema de renderizado de skin utilizar (lnea 6). CEGUI utiliza Falagard. El resto se dedica a declarar el conjunto de Widgets. Para ello realiza un mapeado entre el Widget que habr disponible en el esquema (por ejemplo, TaharezLook/Button, en la lnea 7), y los que ofrece CEGUI. Adems, por cada uno se indican varios parmetros. De este script usualmente se suele cambiar los Imageset y los Font para cambiar la apariencia de la interfaz, y suministrar los desarrollados de forma propia.

7.8.2. Font
Describen los tipos de fuente que se utilizarn en la interfaz.
Listado 7.12: Estructura de un script font.
0 <?xml version="1.0" ?> 1 <Font Name="DejaVuSans-10" Filename="DejaVuSans.ttf" Type="FreeType

" Size="10" NativeHorzRes="800" NativeVertRes="600" AutoScaled= "true"/>

En este ejemplo, slo se dene un tipo de fuente, en la lnea 2. Adems de asignarle un nombre para poder usarla con CEGUI, se indica cul es el chero ttf que contiene la fuente, y otras propiedades como el tamao o la resolucin. Dentro de este chero se puede aadir ms de una fuente, aadiendo ms etiquetas del tipo Font.

[152]

CAPTULO 7. INTERACCIN Y WIDGETS

7.8.3. Imageset
Contiene las verdaderas imgenes que compondrn la interfaz. Este recurso es, junto al de las fuentes, los que ms sujetos a cambio estn para poder adaptar la apariencia de la interfaz a la del videojuego.
Listado 7.13: Estructura de un script imageset.
0 <?xml version="1.0" ?> 1 <Imageset Name="TaharezLook" Imagefile="TaharezLook.tga"

NativeHorzRes="800" NativeVertRes="600" AutoScaled="true"> <Image Name="MouseArrow" XPos="138" YPos="127" Width="31" Height="25" XOffset="0" YOffset="0" /> 3 </Imageset>
2

CEGUI almacena las imgenes que componen la interfaz como un conjunto de imgenes. De este modo, CEGUI slo trabaja con un archivo de imagen, y dentro de ella debe saber qu porcin corresponde a cada elemento. En la Figura 7.9 podemos ver el archivo de imagen que contiene toda la apariencia del esquema TaharezLook y OgreTray.

En la lnea 2 del script, se indica el nombre del conjunto de imgenes y cul es el archivo de imagen que las contendr, en este caso, TaharezLook.tga. A partir de ese archivo, se dene cada uno de los elementos indicando en qu regin de TaharezLook.tga se encuentra. En la lnea 3 se indica que el cursor del ratn (MouseArrow) se encuentra en el rectngulo denido por la esquina superior izquierda en la posicin (138, 127), y con unas dimensiones de 31x25. De esta forma, se puede disear toda la interfaz con un programa de dibujo, unirlos todos en un archivo, e indicar en el script imageset dnde se encuentra cada una. Para ver a qu ms elementos se les puede aadir una imagen, consultar la referencia, o estudiar los imageset proporcionados por CEGUI.

Figura 7.9: Matriz de imgenes que componen la interfaz del esquema TaharezLook (arriba), y OgreTray (abajo).

7.8.4. LookNFeel
Estos tipos de scripts son mucho ms complejos, y los que CEGUI proporciona suelen ser ms que suciente para cualquier interfaz. An as, en la documentacin se puede consultar su estructura y contenido.

7.9.

Cmara de Ogre en un Window

Una caracterstica muy interesante que se puede realizar con CEGUI es mostrar lo que capta una cmara de Ogre en un Widget. Puede ser interesante para mostrar mapas o la vista trasera de un coche de carreras, por ejemplo. Como se aprecia en la Figura 7.10, la aplicacin mostrar a Sinbad de la forma habitual, pero adems habr una ventana que muestra
Figura 7.10: Screenshot de la aplicacin de ejemplo.

7.9. Cmara de Ogre en un Window

[153]

otra vista distinta, y sta a su vez contendr un botn para salir de la aplicacin. A continuacin se muestra el chero del layout. Despus de haber visto en la Seccin 7.5 cmo funcionan los layouts, este no tiene ninguna complicacin. Se trata de una nica FrameWindow (lnea 3) llamada CamWin, con el ttulo Back Camera y una posicin y tamao determinados. Esta a su vez contiene dos Windows ms: uno del tipo StaticImage (lnea 8), que servir para mostrar la imagen de la textura generada a partir de una cmara secundaria de Ogre, para tener ese segundo punto de vista; y uno del tipo Button (lnea 11), con el texto Exit. El nico aspecto resaltable de este cdigo es que el Widget que muestra la imagen (CamWin/RTTWindow) ocupa todo el area de su padre (su propiedad UniedAreaRect vale {{0,0},{0,0,},{1,0},{1,0}}. Esto quiere decir que ocupar toda la ventana CamWin, que no toda la pantalla.
Listado 7.14: Layout del ejemplo.
0 <?xml version="1.0" encoding="UTF-8"?> 1 <GUILayout> 2 <Window Type="TaharezLook/FrameWindow" Name="CamWin" > 3 <Property Name="Text" Value="Back Camera" /> 4 <Property Name="TitlebarFont" Value="DejaVuSans-10" /> 5 <Property Name="TitlebarEnabled" Value="True" /> 6 <Property Name="UnifiedAreaRect" Value=" 7 8 9 10 11 12 13 14 15

{{0.6,0},{0.6,0},{0.99,0},{0.99,0}}" /> <Window Type="TaharezLook/StaticImage" Name="CamWin/RTTWindow" > <Property Name="UnifiedAreaRect" Value=" {{0,0},{0,0},{1,0},{1,0}}" /> </Window> <Window Type="TaharezLook/Button" Name="ExitButton" > <Property Name="Text" Value="Exit" /> <Property Name="UnifiedAreaRect" Value=" {{0.01,0},{0.01,0},{0.25,0},{0.15,0}}" /> </Window> </Window> </GUILayout>

Una vez tenemos la organizacin de la interfaz, es necesario dotarla de funcionalidad. A continuacin se muestran las modicaciones que hay que aadir para que se pueda renderizar una cmara de Ogre en el Widget.
Listado 7.15: Inicializacin de la textura y del Widget que la mostraOgre::Camera* _camBack = _sceneManager->createCamera("BackCamera"); _camBack->setPosition(Ogre::Vector3(-5,-20,20)); _camBack->lookAt(Ogre::Vector3(0,0,0)); _camBack->setNearClipDistance(5); _camBack->setFarClipDistance(10000); _camBack->setAspectRatio(width / height); Ogre::TexturePtr tex = _root->getTextureManager()->createManual( "RTT",

r.
0 1 2 3 4 5 6 7 8

[154]

CAPTULO 7. INTERACCIN Y WIDGETS

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

Ogre::ResourceGroupManager:: DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); Ogre::RenderTexture* rtex = tex->getBuffer()->getRenderTarget(); Ogre::Viewport* v = rtex->addViewport(_camBack); v->setOverlaysEnabled(false); v->setClearEveryFrame(true); v->setBackgroundColour(Ogre::ColourValue::Black); CEGUI::Texture& guiTex = renderer->createTexture(tex); CEGUI::Imageset& imageSet = CEGUI::ImagesetManager::getSingleton(). create("RTTImageset", guiTex); imageSet.defineImage("RTTImage", CEGUI::Point(0.0f,0.0f), CEGUI::Size(guiTex.getSize().d_width, guiTex.getSize() .d_height), CEGUI::Point(0.0f,0.0f));

30 31 32 CEGUI::Window* ex1 = CEGUI::WindowManager::getSingleton().

loadWindowLayout("render.layout");
33 34 CEGUI::Window* RTTWindow = CEGUI::WindowManager::getSingleton().

getWindow("CamWin/RTTWindow");
35 36 RTTWindow->setProperty("Image",CEGUI::PropertyHelper::imageToString

(&imageSet.getImage("RTTImage")));
37 38 //Exit button 39 CEGUI::Window* exitButton = CEGUI::WindowManager::getSingleton(). 40 41 42 43 44 45

getWindow("ExitButton"); exitButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&MyFrameListener::quit, _framelistener)); //Attaching layout sheet->addChildWindow(ex1); CEGUI::System::getSingleton().setGUISheet(sheet);

Esta parte supone ms cdigo de Ogre que de CEGUI. Puesto que el objetivo es mostrar en un Widget lo que est capturando una cmara, el primer paso es crearla. De las lneas 1 a las 6 se crea una Ogre::Camera de forma convencional. Se indica la posicin, hacia dnde mira, los planos de corte Near y Far, y el aspect ratio. Por otro lado, hay que crear la textura en la que se volcar la imagen de la cmara. Para ello se utiliza la funcin createManual() de TexureManager, en las lneas 8 a la 16. La textura se llama RTT, tendr un tamao de 512x512, y ser del tipo Ogre::TU_RENDERTARGET, para que pueda albergar la imagen de una cmara. El siguiente paso es crear el ViewPort. En la lnea 18 se obtiene el objeto RenderTexture a partir de la textura manual creada. En la lnea 20 se obtiene el objeto ViewPort a partir del RenderTexture y utilizando la cmara que se quiere mostrar. En este caso, _camBack. A

7.10. Formateo de texto

[155] este ViewPort se le indica que no dibuje los Overlays (lnea 21), aunque podra hacerlo sin problemas, y que se actualice en cada frame (lnea 22). Adems se establece el color de fondo en negro (lnea 23). Hasta ahora se ha creado la textura tex de Ogre que es capaz de actualizarse con la imagen capturada por una cmara, tambin de Ogre, para tal efecto. El siguiente paso es preparar CEGUI para mostrar imagen en uno de sus Widgets, y que adems esa imagen la obtenga de la textura de Ogre. En la lnea 25 se crea la textura guiTex de CEGUI. El objeto renderer especco para Ogre proporciona la funcin createTexture(), que la crea a partir de una de Ogre. Como se vio en la Seccin 7.8.3, CEGUI est diseado para tratar las distintas imgenes como porciones de un array de imgenes (ver Figura 7.9). De este modo, primeramente hay que crear un Imageset a partir de la textura que devuelve Ogre (ya en formato de CEGUI) en la lnea 27. A este conjunto de imgenes se le ha llamado RTTImageset. Despus, hay que identicar qu porcin corresponde a la textura de la cmara de ese Imageset. En este caso, es la textura completa, por lo que en la lnea 28 se dene la imagen con el nombre RTTImage. El primer parmetro es el nombre, el segundo la esquina superior izquierda de la porcin que dene la imagen (se indica el 0,0), el tercero el tamao de la porcin, que corresponde al tamao de la textura, y el cuarto un offset. Ya se ha conseguido obtener una imagen de CEGUI que se actualizar cada frame con lo que capturar la cmara. Lo nico que falta es recuperar los Window denidos en el layout e indicar que el Widget CamWin/RTTWindow muestre dicha textura. En la lnea 33 se carga el layout como se hizo en anteriores ejemplos. Es importante hacerlo antes de comenzar a recuperar los Windows denidos en el layout, porque de lo contrario no los encontrar. Se recupera el Window que mostrar la imagen (del tipo StaticImage ), llamado CamWin/RTTWindow, en la lnea 35. En la siguiente lnea, la 37, se indica en la propiedad Image de dicho Window que utilice la imagen RTTImage del conjunto de imagenes. Con esto ya es suciente para mostrar en el Widget la imagen de la cmara. Por ltimo se aade la funcionalidad al botn de salida, en las lneas 40 y 41, como en anteriores ejemplos, y se aade el layout al Sheet (lnea 45) y se establece dicho Sheet por defecto (lnea 46).

7.10.

Formateo de texto

Una caracterstica muy verstil que ofrece CEGUI es la de proporcionar formato a las cadenas de texto mediante el uso de tags (etiquetas). Este formato permite cambiar el color, tamao, alineacin o incluso insertar imgenes. A continuacin se describe el funcionamiento de estas etiquetas.

[156]

CAPTULO 7. INTERACCIN Y WIDGETS

7.10.1.

Introduccin

El formato de las etiquetas utilizadas son el siguiente:


[tag-name=value]

Estas etiquetas se insertan directamente en las cadenas de texto, y funcionan como estados. Es decir, si se activa una etiqueta con un determinado color, se aplicar a todo el texto que le preceda a no ser que se cambie explcitamente con otra etiqueta. A continuacin se muestran los diferentes aspectos que se pueden personalizar con esta tcnica. Al nal se muestra una aplicacin de ejemplo que implementa su funcionamiento.

Si se quiere mostrar como texto la cadena [Texto] sin que lo interprete como una etiqueta, es necesario utilizar un carcter de escape. En el caso concreto de C++ se debe anteponer \\ nicamente a la primera llave, de la forma \\[Texto]

7.10.2.

Color

Para cambiar el color del texto, se utiliza la etiqueta colour, usada de la siguiente forma:
[colour=FFFF0000]

Esta etiqueta colorea el texto que la siguiese de color rojo. El formato en el que se expresa el color es ARGB de 8 bits, es decir AARRGGBB. El primer parmetro expresa la componente de transparencia alpha, y el resto la componente RGB.

7.10.3.

Formato

Para cambiar el formato de la fuente (tipo de letra, negrita o cursiva, por ejemplo) es ms complejo ya que se necesitan los propios cheros que denan ese tipo de fuente, y adems deben estar denidos en el script Font. Estando seguro de tener los archivos .font y de tenerlos incluidos dentro del chero del esquema, se puede cambiar el formato utilizando la etiqueta:
[font=Arial-Bold-10]

Esta en concreto corresponde al formato en negrita del tipo de letra Arial, de tamao 10. El nombre que se le indica a la etiqueta es el que se especic en el .scheme.

7.10. Formateo de texto

[157]

7.10.4. Insertar imgenes


Insertar una imagen dentro de una cadena, al estilo de los emoticonos, es sencillo. La estructura de la etiqueta es la siguiente:
[imageset=set:<imageset> image:<image>]

Una vez ms, CEGUI trata las imgenes individuales como parte de un Imageset, por lo que hay que indicarle el conjunto, y la imagen. Aprovechando el Imageset que utiliza la interfaz, TaharezLook, se va a mostrar una de ellas, por ejemplo la equis para cerrar la ventana. Echando un vistazo al xml, se puede identicar que la imagen que se corresponde con la equis se llama CloseButtonNormal. La etiqueta que habra que utilizar sera la siguiente:
[image=set:TaharezLook image=CloseButtonNormal]

Adems, existe otra etiqueta poder cambiar el tamao de las imgenes insertadas. El formato de la etiqueta es el siguiente:
[image-size=w:<width_value> h:<height_value>]

El valor del ancho y del alto se da en pxeles, y debe ponerse antes de la etiqueta que inserta la imagen. Para mostrar las imgenes en su tamao original, se deben poner los valores de width y height a cero.

7.10.5. Alineamiento vertical


Cuando un texto contiene distintos tamaos de letra, es posible congurar el alineamiento vertical de cada parte. El alto de una lnea concreta vendr denido por el alto del texto con mayor tamao. El resto de texto, con menor tamao, podr alinearse verticalmente dentro de ese espacio. Los tipos de alineamiento vertical disponibles son: top: lo alinea hacia arriba. bottom : lo alinea hacia abajo. center : lo centra verticalmente. strecth : lo estira verticalmente para ocupar todo el alto. El formato de la etiqueta es:
[vert-alignment=<tipo_de_alineamiento>]

7.10.6. Padding
El padding consiste en reservar un espacio alrededor del texto que se desee. Para denirlo, se indican los pxeles para el padding izquierdo, derecho, superior e inferior. As, adems de el espacio que ocupe

[158]

CAPTULO 7. INTERACCIN Y WIDGETS

Figura 7.11: Ejemplos de uso del formateo de cadenas.

una determinada cadena, se reservar como un margen el espacio indicado en el padding. Viendo la aplicacin de ejemplo se puede apreciar mejor este concepto. El formato de la etiqueta es:
[padding=l:<left_padding> t:<top_padding> r:<right_padding> b:< bottom_padding>]

Para eliminar el padding, utilizar la etiqueta con los valores a 0.

7.10.7.

Ejemplo de texto formateado

El siguiente es un ejemplo que muestra algunas de las caractersticas que se han descrito. En la Figura 7.11 se aprecia el acabado nal. El siguiente es el layout utilizado:
Listado 7.16: Layout de la aplicacin.
0 <?xml version="1.0" encoding="UTF-8"?> 1 <GUILayout> 2 <Window Type="TaharezLook/FrameWindow" Name="FormatWin"> 3 <Property Name="Text" Value="Format String Window"/> 4 <Property Name="TitlebarEnabled" Value="True"/> 5 <Property Name="UnifiedAreaRect" Value=" 6 7 8 9 10 11

{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}"/> <!-- Static Text --> <Window Type="TaharezLook/StaticText" Name="FormatWin/Text1"> <Property Name="UnifiedAreaRect" Value=" {{0.05,0},{0.05,0},{0.95,0},{0.15,0}}"/> </Window> <!-- Other Static Text ... --> <!-- Exit Button -->

7.11. Caractersticas avanzadas

[159]

<Window Type="TaharezLook/Button" Name="FormatWin/ExitButton"> <Property Name="Text" Value="Exit" /> <Property Name="UnifiedAreaRect" Value=" {{0,0},{0.95,0},{1,0},{1,0}}"/> 15 </Window> 16 </Window> 17 </GUILayout>
12 13 14

Y el siguiente listado muestra cada una de las cadenas que se han utilizado, junto a las etiquetas:
Listado 7.17: Cdigo con los tags de formateo.
0 "Este color es [colour=FFFF0000] AZUL, mientras que [colour=

FF00FF00] este es ROJO [colour=FF0000FF] y este VERDE!"


1 2 "El tipo de letra puede [font=Batang-26]cambiar de un momento a

otro, [font=fkp-16]y sin previo aviso!"


3 4 "Si pulsas aqui [image-size=w:40 h:55][image=set:TaharezLook

image:CloseButtonNormal] no pasara nada :("


5 6 "[font=Batang-26] Soy GRANDE,

[font=DejaVuSans-10][vertalignment=top] puedo ir arriba, [vert-alignment=bottom]o abajo, [vert-alignment=centre]al centro..."

7 8 "En un lugar de la [padding=l:20 t:15 r:20 b:15]Mancha[padding=l

:0 t:0 r:0 b:0], de cuyo nombre no quiero acordarme, no ha mucho..."

La primera cadena (lnea 1) utiliza las etiquetas del tipo colour para cambiar el color del texto escrito a partir de ella. Se utilizan los colores rojo, verde y azul, en ese orden. La segunda (lnea 3) muestra cmo se pueden utilizar las etiquetas para cambiar totalmente el tipo de fuente, siempre y cuando estn denidos los recursos .font y estos estn reejados dentro el .scheme. La tercera (lnea 5) muestra una imagen insertada en medio del texto, y adems redimensionada. Para ello se utiliza la etiqueta de redimensionado para cambiar el tamao a 40x55, y despus inserta la imagen CloseButtonNormal, del conjunto TaharezLook La cuarta (lnea 7) muestra una cadena con un texto (Soy GRANDE) de un tipo de fuente con un tamao 30, y el resto con un tamao 10. Para el resto del texto, sobra espacio vertical, por lo que se utiliza la etiqueta vertical-alignment para indicar dnde posicionarlo. Por ltimo, la quinta cadena (lnea 9), utiliza padding para la palabra Mancha. A esta palabra se le reserva un margen izquierdo y derecho de 20 pxeles, y un superior e inferior de 15.

7.11.

Caractersticas avanzadas

CEGUI es una biblioteca muy potente y exible que puede ser utilizada junto a muchas otras para crear efectos visualmente muy impactantes. Algunas caractersticas avanzadas que se han implementado

[160]

CAPTULO 7. INTERACCIN Y WIDGETS

son efectos de ventanas, como transparencia y aspecto gelatinoso, o incluso incrustar un navegador dentro de una ventana. Para aprender estas caractersticas y ms, en su pgina existen muchos manuales, y dispone de una muy buena documentacin [1].

Captulo

Materiales y Texturas
Carlos Gonzlez Morcillo

Iluminacin Local L
Punto Vista

E
8.1.

n este captulo estudiaremos los conceptos fundamentales con la denicin de materiales y texturas. Introduciremos la relacin entre los modos de sombreado y la interaccin con las fuentes de luz, describiendo los modelos bsicos soportados en aplicaciones interactivas. Para nalizar, estudiaremos la potente aproximacin de Ogre para la denicin de materiales, basndose en los conceptos de tcnicas y pasadas.

Introduccin

Iluminacin Global L
Punto Vista

Los materiales describen las propiedades fsicas de los objetos relativas a cmo reejan la luz incidente. Obviamente, el aspecto nal obtenido ser dependiente tanto de las propiedades del material, como de la propia denicin de las fuentes de luz. De este modo, materiales e iluminacin estn ntimamente relacionados. Desde los inicios del estudio de la ptica, investigadores del campo de la fsica han desarrollado modelos matemticos para estudiar la interaccin de la luz en las supercies. Con la aparicin del microprocesador, los ordenadores tuvieron suciente potencia como para poder simular estas complejas interacciones.

Figura 8.1: Diferencias entre los modelos de iluminacin local y global.

As, usando un ordenador y partiendo de las propiedades geomtricas y de materiales especicadas numricamente es posible simular la reexin y propagacin de la luz en una escena. A mayor precisin, mayor nivel de realismo en la imagen resultado.

161

[162]

CAPTULO 8. MATERIALES Y TEXTURAS

a)
Figura 8.2: Ejemplo de resultado utilizando un modelo de iluminacin local y un modelo de iluminacin global con la misma conguracin de fuentes de luz y propiedades de materiales. a) En el modelo de iluminacin local, si no existen fuentes de luz en el interior de la habitacin, los objetos aparecern totalmente a oscuras, ya que no se calculan los rebotes de luz indirectos. b) Los modelos de iluminacin global tienen en cuenta esas contribuciones relativas a los rebotes de luz indirectos.

b)

Esta conexin entre la simulacin del comportamiento de la luz y el nivel de realismo queda patente en las aproximaciones existentes de diferentes mtodos de render. Una ecuacin que modela el comportamiento fsico de la luz, ampliamente aceptada por la comunidad, es la propuesta por Kajiya en 1986. De forma general podemos decir que a mayor simplicacin en la resolucin de los trminos de esta ecuacin tendremos mtodos menos realistas (y computacionalmente menos costosos). A un alto nivel de abstraccin, podemos realizar una primera taxonoma de mtodos de render entre aquellos que realizan una simulacin de iluminacin local, teniendo en cuenta nicamente una interaccin de la luz con las supercies, o los mtodos de iluminacin global que tratan de calcular todas 1 las interacciones de la luz con las supercies de la escena. La Figura 8.2 muestra el resultado de renderizar la misma escena con un mtodo de iluminacin local y uno global. Los modelos de iluminacin global incorporan la iluminacin directa que proviene de la primera interaccin de las supercies con las fuentes de luz, as como la iluminacin indirecta reejada por otras supercies existentes en la escena. La potencia de clculo actual hace inviable el uso de mtodos de iluminacin global. Se emplean aproximaciones de preclculo de la iluminacin, que sern estudiadas en el captulo de iluminacin. As, en los motores grcos actuales como Ogre, los materiales denen cmo se reeja la luz en los objetos (pero no su contribucin con otros objetos), empleando un esquema de iluminacin local.

1 Debido a que es imposible calcular las innitas interacciones de los rayos de luz con todos los objetos de la escena, las aproximaciones de iluminacin global se ocuparn de calcular algunas de estas interacciones, tratando de minimizar el error de muestreo.

8.2. Modelos de Sombreado

[163]

8.2.
L

Modelos de Sombreado

n l

Como hemos comentado anteriormente, es habitual en grcos por computador interactivos (y en el caso de videojuegos especialmente) emplear modelos de iluminacin local. En cierto modo, el sombrado es equivalente a pintar con luz. En este apartado estudiaremos los modelos de sombreado ms ampliamente utilizados en grcos interactivos, que fueron inicialmente desarrollados en los aos 70. Sombreado difuso. Muchos objetos del mundo real tienen una acabado eminentemente mate (sin brillo). Por ejemplo, el papel o una tiza pueden ser supercies con sombreado principalmente difuso. Este tipo de materiales reejan la luz en todas las direcciones, debido principalmente a las rugosidades microscpicas del material. Como efecto visual, el resultado de la iluminacin es mayor cuando la luz incide perpendicularmente en la supercie. La intensidad nal viene determinada por el ngulo que forma la luz y la supercie (es independiente del punto de vista del observador). En su expresin ms simple, el modelo de reexin difuso de Lambert dice que el color de una supercie es proporcional al coseno del ngulo formado entre la normal de la supercie y el vector de direccin de la fuente de luz (ver Figura 8.3). Sombreado especular. Es el empleado para simular los brillos de algunas supercies, como materiales pulidos, pintura plstica, etc. Una caracterstica principal del sombreado especular es que el brillo se mueve con el observador. Esto implica que es necesario tener en cuenta el vector del observador. La dureza del brillo (la cantidad de reejo del mismo) viene determinada por un parmetro h. A mayor valor del parmetro h, ms concentrado ser el brillo. El comportamiento de este modelo de sombreado est representado en la Figura 8.4, donde r es el vector reejado del l (forma el mismo ngulo con n) y e es el vector que se dirige del punto de sombreado al observador. De esta forma, el color nal de la supercie es proporcional al ngulo . Sombreado ambiental. Esta componente bsica permite aadir una aproximacin a la iluminacin global de la escena. Simplemente aade un color base independiente de la posicin del observador y de la fuente de luz. De esta forma se evitan los tonos absolutamente negros debidos a la falta de iluminacin global, aadiendo este trmino constante. En la Figura 8.5 se puede ver la componente ambiental de un objeto sencillo. Sombreado de emisin. Finalmente este trmino permite aadir una simulacin de la iluminacin propia del objeto. No obstante, debido a la falta de interaccin con otras supercies (incluso con las caras poligonales del propio objeto), suele emplearse como una alternativa al sombreado ambiental a nivel local. El efecto es como tener un objeto que emite luz pero cuyos rayos no interactan con ninguna supercie de la escena (ver Figura 8.5).

Figura 8.3: Modelo de sombreado difuso bsico de Lambert en el que el color c se dene como c n l. Los vectores n y l deben estar normalizados.

n l

r e

Figura 8.4: En el modelo de sombreado especular, el color c se obtiene como c (r e)h . Los vectores r y e deben estar normalizados.

[164]

CAPTULO 8. MATERIALES Y TEXTURAS

Sombreado Ambiental

Sombreado Difuso

Sombreado Especular

Sombreado de Emisin

Sombreado Final

Figura 8.5: Modos bsicos de sombreado de iluminacin local.

El sombreado nal de la supercie se obtiene como combinacin de los cuatro modos de sombreado anteriores (ver Figura 8.5). Esta aproximacin es una simplicacin del modelo de reexin fsicamente correcto denido por la Funcin de Distribucin de Reactancia Bidireccional BRDF (Bidirectional Reactance Distribution Function). Esta funcin dene cmo se reeja la luz en cualquier supercie opaca, y es empleada en motores de rendering fotorrealistas.

8.3.

Mapeado de Texturas

Los materiales denen propiedades que son constantes a lo largo de la supercie. Hasta ahora, hemos hablado de materiales bsicos en las supercies, con propiedades (como el color) constantes. Las texturas permiten variar estas propiedades, determinando en cada punto cmo cambian concretamente estas propiedades. Bsicamente podemos distinguir dos tipos de texturas: Texturas Procedurales. Su valor se determina mediante una ecuacin. Estas texturas se calculan rpidamente y no tienen requisitos de espacio en disco, por lo que son ampliamente utilizadas en sntesis de imagen realista para simular ciertos patrones existentes en la naturaleza (madera, mrmol, nubes, etc). La Figura 8.6 muestra un ejemplo de este tipo de texturas. En videojuegos sin embargo, se emplean en menor medida, ya que resulta habitualmente ms interesante emplear texturas de imagen con una resolucin controlada. Texturas de Imagen. Almacenan los valores en una imagen, tpicamente bidimensional.

Figura 8.6: Denicin de una sencilla textura procedural que dene bandas de color dependiendo del valor de coordenada Z del punto 3D.

8.3. Mapeado de Texturas

[165] Las texturas procedurales obtienen valores habitualmente en el espacio 3D, por lo que no es necesaria ninguna funcin de proyeccin de estas texturas sobre el objeto. Sin embargo, para utilizar las texturas de imagen es necesario indicar cmo queremos aplicar esa textura (2D) a la geometra del modelo 3D. Es decir, debemos espeicifcar cmo se recubrir el objeto con ese mapa de textura. Existen varias alternativas para realizar este mapeado. Empleando proyecciones ortogonales es posible describir esta correspondencia. Se emplean cuatro modos bsicos de proyeccin (ver Figura 8.8). Estos modos de proyeccin utilizas las coordenadas del objeto 3D normalizadas en el interior de una caja unitaria.

u=0.35

Asociacin de coordendas de textura UV a cada vrtice de cada cara del modelo.

v=0.71

Resultado final del modelo texturizado


Figura 8.7: Asignacin de coordenadas UV a un modelo poligonal. Esta operacin suele realizarse con el soporte de alguna herramienta de edicin 3D.

Una de las caractersticas interesantes de los modelos de mapeado de texturas (tanto ortogonales como mediante mapas paramtricos UV) es la independencia de la resolucin de la imagen. De este modo es posible tener texturas de diferentes tamaos y emplearlas aplicando tcnicas de nivel de detalle (LOD ). As, si un objeto se muestra a una gran distancia de la cmara es posible cargar texturas de menor resolucin que requieran menor cantidad de memoria de la GPU.

Como hemos visto en captulos anteriores, un mtodo de proyeccin de texturas de imagen muy empleado en videojuegos es el mapeado paramtrico, tambin denominado mapeado UV. En este mtodo se denen dos coordenadas paramtricas (entre 0 y 1) para cada vrtice de cada cara del modelo (ver Figura 8.7). Estas coordenadas son independientes de la resolucin de la imagen, por lo que permite cambiar en tiempo de ejecucin la textura teniendo en cuenta ciertos factores de distancia, importancia del objeto, etc. El mapeado UV permite pegar la textura al modelo de una forma muy precisa. Incluso si se aplica sobre el modelo deformacin de vrtices (vertex blending), el mapa se-

[166]

CAPTULO 8. MATERIALES Y TEXTURAS

Textura a Mapear

Proyeccin Plana

Proyeccin Cbica

Proyeccin Cilndrica

Proyeccin Esfrica

Figura 8.8: Mtodos bsicos de mapeado ortogonal sobre una esfera. Los bordes marcados con lneas de colores en la textura a mapear en la izquierda se proyectan de forma distinta empleado diversos mtodos de proyeccin.

guir aplicndose correctamente. Por esta razn y su alta eciencia es una tcnica ampliamente utilizada en grcos por computador.
Shading programable

8.4.

Materiales en Ogre

El despliegue de entidades en Ogre se realiza en paquetes, de modo que existe una relacin directa entre el nmero de materiales y el nmero de paquetes que Ogre enviar a la tarjeta grca. Por ejemplo, si 10 elementos comparten el mismo material, podrn ser enviados en un nico paquete a la GPU (en lugar de en 10 paquetes por separado), de modo que podrn compartir el mismo estado interno. Con la idea de realizar estas optimizaciones, Ogre dene que por defecto los materiales son compartidos entre objetos. Esto implica que el mismo puntero que referencia a un material es compartido por todos los objetos que utilizan ese material. De este modo, si queremos cambiar la propiedad de un material de modo que nicamente afecte a un objeto es necesario clonar este material para que los cambios no se propaguen al resto de objetos. Los materiales de Ogre se denen empleando tcnicas y esquemas. Una Tcnica puede denirse como cada uno de los modos alternativos en los que puede renderizarse un material. De este modo, es posible tener, por ejemplo, diferentes niveles de detalle asociados a un material. Los esquemas agrupan tcnicas, permitiendo denir nombres y grupos que identiquen esas tcnicas como alto nivel de detalle, medio rendimiento, etc.

En esta seccin estudiaremos nicamente lo que se conoce como shading jo (xed shading). En captulos posteriores del documento estudiaremos cmo aplicar shaders programando la GPU (en pixel shading o fragment shading).

8.4. Materiales en Ogre

[167]

Material
Technique 1
Pass 1 Pass 2

Technique 2
Pass 1 Pass 2

Technique N
Pass 1

... ...

Pass 2

...
Pass i Pass j

...
Pass k

Figura 8.10: Descripcin de un material en base a tcnicas y pasadas. El nmero de tcnicas y pasadas asociadas a cada tcnica puede ser diferente.

8.4.1. Composicin
Un material en Ogre est formado por una o varias tcnicas, que contienen a su vez una o varias Pasadas (ver Figura 8.10). En cada momento slo puede existir una tcnica activa, de modo que el resto de tcnicas no se emplearn en esa etapa de render. Una vez que Ogre ha decidido qu tcnica emplear, generar tantas pasadas (en el mismo orden de denicin) como indique el material. Cada pasada dene una operacin de despliegue en la GPU, por lo que si una tcnica tiene cuatro pasadas asociadas a un material tendr que desplegar el objeto tres veces en cada frame. Las Unidades de Textura (Texture Unit ) contienen referencias a una nica textura. Esta textura puede ser generada en cdigo (procedural ), puede ser obtenida mediante un archivo o mediante un ujo de vdeo. Cada pasada puede utilizar tantas unidades de textura como sean necesarias. Ogre optimiza el envo de texturas a la GPU, de modo que nicamente se descargar de la memoria de la tarjeta cuando no se vaya a utilizar ms.

Figura 8.9: Un material en Ogre se describe mediante sucesivas pasadas que van congurando la apariencia nal.

8.4.2. Ejemplo de Materiales


A continuacin veremos un ejemplo sencillo de denicin de materiales en Ogre. Como hemos visto, el material denido en el listado de la Figura 8.11 contiene una tcnica y una nica pasada que dene un mtodo de sombreado difuso (especicando el color base en RGB). El nombre asignado al material especicado a la derecha de la etiqueta Material (en este caso Material1) debe ser nico a lo largo de la aplicacin. El nombre de los elementos que denen el material (tcnicas, pasadas y unidades de textura ) es opcional. Si no se especica ninguno, Ogre comenzar a nombrarlas comenzando en 0 segn el orden de especicacin del script. El nombre de estos elementos puede repetirse en diferentes materiales.

[168] Atributo lod_values receive_shadows

CAPTULO 8. MATERIALES Y TEXTURAS Descripcin Lista de distancias para aplicar diferentes niveles de detalle. Est relacionado con el campo lod_strategy (ver API de Ogre). Admite valores on (por defecto) y off. Indica si el objeto slido puede recibir sombras. Los objetos transparentes nunca pueden recibir sombras (aunque s arrojarlas, ver el siguiente campo). Indica si el material transparente puede arrojar sombras. Admite valores on y off (por defecto). Permite crear alias de un nombre de textura. Primero se indica el nombre del alias y despus del nombre de la textura original.

transparency_casts_shadows set_texture_alias

Cuadro 8.1: Atributos generales de Materiales.

Atributo ambient diffuse specular emissive scene_blend

Formato r g b [a] r g b [a] r g b [a] h r g b [a] (Ver valores)

depth_check lighting shading

on | off on | off (Ver valores)

polygon_mode

(Ver valores)

Descripcin Valor de sombreado ambiente (por defecto 1.0 1.0 1.0 1.0). Valor de sombreado difuso (por defecto 1.0 1.0 1.0 1.0). Valor de sombreado especular (por defecto 0.0 0.0 0.0 0.0). El valor de dureza (shininess) puede ser cualquier valor >0. Valor de emisin (por defecto 0.0 0.0 0.0 0.0). Tipo de mezclado de esta pasada con el resto de la escena. Por defecto no se realiza mezclado. Si se especica, puede tomar valores entre add, modulate, colour_blend y alpha_blend. Por defecto on. Indica si se utilizar el depth-buffer para comprobar la profundidad. Por defecto on. Indica si se emplear iluminacin dinmica en la pasada. Indica el tipo de mtodo de interpolacin de iluminacin a nivel de vrtice. Se especican los valores de interpolacin de sombreado at o gouraud o phong. Por defecto se emplea el mtodo de gouraud. Indica cmo se representarn los polgonos. Admite tres valores: solid (por defecto), wireframe o points.

Cuadro 8.2: Atributos generales de las Pasadas. Ver API de Ogre para una descripcin completa de todos los atributos soportados.

Veamos a continuacin un ejemplo ms complejo de denicin de material. En la pasada denida se utiliza una texture_unit que referencia a un archivo de mapa de entorno esfrico. Los mapas de entorno se utilizan para simular la reexin del mundo (representado en el mapa) dependiendo de la relacin entre las normales de las caras poligionales y la posicin del observador. En este caso, se indica a Ogre que el tipo de mapa de entorno es esfrico (tipo ojo de pez, ver Figura 8.12). El operador de colour_op empleado indica cmo se combinar el color de la textura con el color base del objeto. Existen diversas alternativas; mediante modulate se indica a Ogre que

Figura 8.12: Mapa de entorno esfrico empleado para simular la reexin de un supuesto mundo.

8.4. Materiales en Ogre

[169]

Figura 8.11: Denicin y resultado de un sencillo material con sombreado difuso.

Figura 8.13: Un material ms complejo que incluye la denicin de una texture_unit con diversas componentes de sombreado.

multiplique el color base (en este caso, un color amarillo indicado en la componente difusa del color) y el color del mapa. A continuacin se describen algunas de las propiedades generales de los materiales. En la tabla 8.1 se resumen los atributos generales ms relevantes empleados en la denicin de materiales, mientras que las tablas 8.2 y 8.3 resumen los atributos globales ms utilizados en la denicin de las pasadas y unidades de textura resepectivamente. Cada pasada tiene asociada cero o ms unidades de textura. En los siguientes ejemplos veremos cmo combinar varias pasadas y unidades de textura para denir materiales complejos en Ogre.

[170] Atributo texture anim_texture ltering colour_op colour_op_ex env_map rotate scale

CAPTULO 8. MATERIALES Y TEXTURAS Descripcin Especica el nombre de la textura (esttica) para esta texture_unit. Permite especicar el tipo, y el uso o no de canal alpha separado. Permite utilizar un conjunto de imgenes como textura animada. Se especica el nmero de frames y el tiempo (en segundos). Filtro empleado para ampliar o reducir la textura. Admite valores entre none, bilinear (por defecto), trilinear o anisotropic. Permite determinar cmo se mezcla la unidad de textura. Admite valores entre replace, add, modulate (por defecto) o alpha_blend. Versin extendida del atributo anterior, que permite especicar con mucho mayor detalle el tipo de mezclado. Uso de mapa de entorno. Si se especica (por defecto est en off, puede tomar valores entre spherical, planar, cubic_reection y cubic_normal. Permite ajustar la rotacin de la textura. Requiere como parmetro el ngulo de rotacin (en contra de las agujas del reloj). Ajusta la escala de la textura, especicando dos factores (en X e Y).

Cuadro 8.3: Atributos generales de las Unidades de Textura. Ver API de Ogre para una descripcin completa de todos los atributos soportados

8.5.

Mapeado UV en Blender
Mapas UV
El mapeado UV es el estndar en desarrollo de videojuegos, por lo que prestaremos especial atencin en este documento.

La forma ms exible para la proyeccin de texturas en aplicaciones interactivas es el mapeado paramtrico UV. Como hemos visto, a cada vrtice del modelo (con coordenadas X,Y,Z ) se le asocian dos coordenadas paramtricas 2D (U,V ). Los modelos de mapeado ortogonales no se ajustan bien en objetos complejos. Por ejemplo, la textura asociada a una cabeza de un personaje no se podra mapear adecuadamente empleando modelos de proyeccin ortogonal. Para tener el realismo necesario en modelos pintados manualmente (o proyectando texturas basadas en fotografas) es necesario tener control sobre la posicin nal de cada pxel sobre la textura. El mapa UV describe qu parte de la textura se asociar a cada polgono del modelo, de forma que, mediante una operacin de despliegue (unwrap) del modelo obtenemos la equivalencia de la supercie en el plano 2D. En esta seccin estudiaremos con ms detalle las opciones de Blender para trabajar con este tipo de coordenadas. Como vimos en el captulo 4, para comenzar es necesario aplicar una operacin de despliegue del modelo para obtener una o varias regiones en la ventana de UV/Image Editor . Esta operacin de despliegue se realiza siempre en modo edicin. Con el objeto en modo edicin, enlos botones de edicin , y tras aplicar el despliegue (Unwrap) (tecla U ), aparece un nuevo subpanel en el panel de herramientas (Tool Shelf ), accesible mediante la tecla T (ver Figura 8.15) que controla el modo en el que se realiza el despliegue del modelo. Este panel aparece mientras el objeto est en modo de edicin, y es dependiente del modo de despliegue elegido (por ejemplo, el de la Figura 8.15 con-

Figura 8.14: El problema del despliegue se ha afrontado desde los orgenes de la cartografa. En la imagen, un mapa de 1482 muestra una proyeccin del mundo conocido hasta el momento.

8.5. Mapeado UV en Blender

[171] tiene las opciones de Unwrap, pero otros modos de despliegue tendrn otras opciones asociadas). A continuacin describimos las principales opciones que pueden encontrarse en este tipo de subpaneles:

Isla UV
Se dene una isla en un mapa UV como cada regin que contiene vrtices no conectados con el resto.

Angle Based | Conformal. Dene el mtodo de clculo de la proyeccin. El basado en ngulo crea una nueva isla cuando el ngulo entre caras vecinas sea relevante. En el modo conformal se realiza dependiendo del mtodo de proyeccin seleccionado. El mtodo basado en ngulo ofrece, en general, mejores resultados. Fill Holes. Intenta ordenar todas las islas para evitar que queden huecos en la textura sin ninguna cara UV. Correct Aspect. Permite el escalado de los vrtices desplegados en UV para ajustarse a la relacin de aspecto de la textura a utilizar. Margin. Dene la separacin mnima entre islas. Use Subsurf Data. Utiliza el nivel de subdivisin especicado en Subsurf Target para el clculo de las coordenadas UV en lugar de la malla original (Red de Control). Transform Correction. Corrige la distorsin del mapa UV mientras se est editando.

Figura 8.15: Opciones del panel Unwrap.

Cube Size. Cuando se emplea una proyeccin cbica, este parmetro indica el porcentaje de la imagen que se emlpear por el mapa UV (por defecto el 100 %). Radius. Cuando se emplea el mtodo de proyeccin Cylinder projection, este parmetro dene el radio del cilindro de proyeccin. A menores valores, las coordenadas del objeto aparecern estiradas en el eje Y. Align: Polar ZX | Polar ZY. Determina el plano frontal de proyeccin en los mtodos cilndrico y esfrico. El modo general de trabajo asociado al despliegue de una malla est compuesto por la siguiente serie de pasos secuenciales: 1. Seleccionar el objeto que queremos desplegar. 2. Suele ser interesante ver los cambios realizados sobre la textura UV cambiando el modo de dibujado del objeto en la ventana 3D a Texture . 3. Cambiar al modo edicin (mediante TAB ) y seleccionar las caras ), que queremos desplegar. En algunos casos sern todas (tecla A o puede ser conveniente elegir individualmente (en este caso es conveniente elegir el modo de seleccin de caras en la cabecera de la ventana 3D). 4. Establecer los valores globales de despliegue en la pestaa asociada al mtodo de despliegue elegido (ver Figura 8.15).

Figura 8.16: Opciones del panel Mesh.

[172]

CAPTULO 8. MATERIALES Y TEXTURAS

5. Vericar que existe al menos una capa de textura UV en el panel Mesh del grupo de botones Object Data (ver Figura 8.16). Cada cara de la malla puede tener varias texturas UV, pero cada textura nicamente puede tener una nica imagen asignada. 6. Pulsando la tecla U accedemos al men de despliegue (UV Mapping) que nos permite elegir el mtodo de despiegue que aplicaremos as la malla. Entre estos mtodos podemos destacar los siguientes (ver Figura 8.19): Unwrap. Esta opcin despliega las caras del objeto tratando de obtener una conguracin que rellene de la mejor forma posible la textura, empleando informacin topolgica de la malla (cmo estn conectadas las caras de la malla). Si es posible, cada cara desplegada tendr su propia regin de la imagen sin solapar con otras caras. Smart UV Projects. Este mtodo estudia la forma del objeto, estudiando la relacin entre las caras seleccionadas y crea un mapa UV basada en las opciones de conguracin que se muestran en la Figura 8.17. A menor lmite de ngulo, mayor nmero de islas se crearn. El margen existente entre islas se puede elegir en el parmetro Island Margin. El parmetro de Area Weight permite dar mayor peso a las caras de mayor supercie. Este mtodo de proyeccin automtico se ajusta perfectamente en multitud de situaciones, siendo el que probablemente ofrezca una mejor conguracin de partida para ajustar posteriormente los vrtices de forma manual. Lightmap Pack. Despliega las caras de forma regular para ser utilizados en el clculo de mapas de luz. Este tipo de despiegue ser utilizado en el Captulo 9 para el preclculo de iluminacin. Follow Active Quads. Este mtodo toma como entrada las caras seleccionadas y las despliega siguiendo bucles de cara continuos. Este mtodo no tiene en cuenta el tamao de la imagen. Cube | Cylinder | Sphere Projection. Estos mtodos tratan de despegar el objeto empleando estos modelos de proyeccin ortogonales. Como hemos visto anteriormente, en estos mtodos resulta especialmente relevante la denicin de las opciones del panel de la Figura 8.15. Project from View | (Bounds). Emplea el punto de vista 3D para desplegar el objeto. Si se elige la opcin Bounds, el despliegue se realizar ajustando a los lmites de la imagen. Reset. Mediante esta opcin todas las caras se despliegan ocupando el 100 % de la imagen, con vrtices en las esquinas de la misma. Una vez que la malla ha sido desplegada, podemos ayudarnos de la herramienta de generacin de rejillas de prueba que trae integrado Blender para hacernos una idea del resultado del despliegue. En la cabecera de la ventana del editor UV , accediendo al men Image/

Figura 8.17: Conguracin de las opciones de despliegue en Smart UV Project.

Figura 8.18: Ventana para la creacin de una nueva textura para el mapeado UV.

Figura 8.20: Resultado de aplicar la textura de prueba a la malla de Suzanne con el modo de despliegue bsico.

8.5. Mapeado UV en Blender

[173]

Figura 8.19: Resultado obtenido tras aplicar diferentes mtodos de despliegue (unwrap) al modelo de Suzanne con todas las caras seleccionadas: a) Unwrap, b) Cube, c) Cylinder, d) Sphere, e) Project from view, f) Reset, g) Lightmap y h) Smart UV.

New Image la ventana de la Figura 8.18, donde podemos elegir la resolucin en pxeles de la nueva imagen (por defecto 1024x1024 pxeles), el color de fondo y el nivel de Alpha. Si activamos el botn UV Test Grid, se crear la imagen con la rejilla de fondo que se muestra en la Figura 8.20. Esta imagen permite hacerse una idea del resultado del despliegue tras aplicar la textura al objeto 3D. Las coordenadas UV se almacenan en el modelo de Blender y son pasadas a Ogre empleando el script de exportacin. Sin embargo, es comn utilizar un editor de imgenes externo para asignar colores a la textura. Para guardar el estado del despliegue (y utilizarlo como plantilla para el programa de edicin, como GIMP (GNU Image Manipulation Program)), es posible emplear el script de la cabecera de la ventana en UVs / Export UV Layout para generar una del UV/ Image Editor imagen PNG, EPS o SVG. En la cabecera de la ventana 3D puede elegirse el modo Texture Paint (ver Figura 8.21). Cuando este modo est activo, nos permite dibujar directamente sobre el modelo 3D, accediendo a los controles que se encuentran en el subpanel de la vista 3D accesible medidante la tecla T ((ver Figura 8.22)).

Figura 8.21: Editando la textura aplicada a Suzanne en el espacio 3D mediante el modo Texture Paint.

[174]

CAPTULO 8. MATERIALES Y TEXTURAS

Figura 8.23: Utilizacin de costuras y despliegue del modelo utilizando diferentes tcnicas de despliegue. En la imagen de la izquerda se marcan perfectamente los seams denidos para recortar el modelo adecuadamente.

8.5.1. Costuras
En el despliegue de mallas complejas, es necesario ayudar a los mtodos de despliegue deniendo costuras (seams). Estas costuras servirn para denir las zonas de recorte, guiando as al mtodo de desplegado. Para denir una costura basta con elegir las aristas que la denen en modo edicin, tal y como se muestra en la Figura 8.23 . La seleccin de bucles de aristas (como en el caso del bote de spray del modelo) puede realizarse cmodamente seleccionando las una de aristas del bucle y empleando la combinacin de teclas Control E Edge Loop. Cuando tenemos la zona de recorte seleccionada, deniremos la costura mediante la combinacin Control E Mark Seam. En este men aparece igualmente la opcin para eliminar una costura Clear Seam. Una vez denidas las costuras, podemos emplear la seleccin de zonas enlazadas (mediante la tecla L ) para elegir regiones conectadas. Podemos aplicar a cada grupo de caras un modo de despliegue distinto. Por ejemplo, en la Figura 8.23 se ha utilizado una proyeccin cilndrica para el cuerpo central del Spray y para el difusor, mientras que la base y la zona superior se han desplegado mediante el modo general Unwrap. pueCada zona de despliegue en la ventana de UV Image Editor de igualmente desplazarse empleando los operadores habituales de traslacin G , rotacin R y escalado S . En esta ventana puede igualmente emplearse el atajo de teclado para seleccionar los vrtices rpidamente regiones desplegadas conectados (link) L y seleccionar (incrementalmente si pulsamos L mientras mantenemos pulsada la ). tecla Shift

Figura 8.22: Subpanel de opciones de Texture Paint en el que puede elegirse el color de pintado, tamao del pincel, opacidad, etc...

8.6. Ejemplos de Materiales en Ogre

[175]

Figura 8.24: Ejemplos de denicin de algunos materiales empleando diversos modos de composicin en Ogre.

8.6.

Ejemplos de Materiales en Ogre

En esta seccin estudiaremos algunos ejemplos de denicin de materiales empleando diversas unidades de tetura en Ogre. Nos centraremos en el uso de algunos operadores para la composicin de diferentes unidades de textura. Las Figuras 8.24 y 8.27 muestran el resultado de denicin de estos materiales y texturas. Veamos algunas de las propiedades empleadas en su denicin.
Figura 8.25: Despliegue del modelo de los ejemplos. Se ha empleado una operacin de despliegue cinlndrico para la mandbula inferior, Smart Projections para los dientes y el Unwrap bsico para el resto del objeto.

En la denicin del Material3 se ha empleado el despliegue que se muestra en la Figura 8.25. Este material simplemente utiliza las coordenadas UV del modelo para proyectar la misma textura que en el suelo de la escena. En la denicin del Material4 se utiliza una textura de tipo cebra donde las bandas negras son totalmente transparentes. En la pasada de este material se utiliza el atributo scene_blend que permite especicar el tipo de mezclado de esta pasada con el resto de contenido de la

[176]

CAPTULO 8. MATERIALES Y TEXTURAS

escena. Como veremos en el ejemplo del Material6, la pricipal diferencia entre las operaciones de mezclado a nivel de pasada o a nivel de textura es que las primeras denen la mezcla con el contenido global de la escena, mientras que las segundas estn limitadas entre capas de textura. Mediante el modicador alpha_blend se indica que utilizaremos el valor alpha de la textura. A continuacin estudiaremos las opciones permitidas por el atributo scene_blend en sus dos versiones. El formato de scene_blend permite elegir cuatro parmetros en su forma bsica: add. El color del resultado de la pasada se suma al resultado de la escena. modulate. El resultado de la pasada se multiplica con el resultado de color de la escena. colour_blend. El color resultado de la pasada se mezcla empleando la componente de brillo de los colores. alpha_blend. Este modo utiliza la informacin de transparencia del resultado. El atributo scene_blend permite otro formato mucho ms general y exible, que requiere dos parmetros: scene_blend src dest. En esta segunda versin, el color nal se obtiene como: c = (texture * src) + (scene_pixel * dest). En esta segunda versin, src y dest son factores de mezclado, entre 10 posibles valores: one. Valor constante 1.0. zero. Valor constante 0.0. dest_colour. Color del pxel en la escena. src_colour. Color del txel (de la pasada). one_minus_dest_colour. 1 - (dest_colour). one_minus_src_colour. 1 - (src_colour). dest_alpha. Valor alfa del pxel en la escena. src_alpha. Valor alfa del txel (de la pasada). one_minus_dest_alpha. 1 - (dest_alpha). one_minus_src_alpha. 1 - (src_alpha). De este modo, el scene_blend por defecto que se aplica es el totalmente opaco, utilizando totalmente el valor del txel de la pasada y sin tener en cuenta el valor del pxel existente en la escena (scene_blend one zero ). Anlogamente, el equivalente al modo bsico de alpha_blend estudiado anteriormente sera scene_blend src_alpha one_minus_src_alpha, el modo bsico add se escribira como scene_blend one one, etc... Para nalizar la descripcin de los atributos utilizados en el Material4, mediante depth_write off se fuerza a que la pasada no utilice el
Consulta el manual!
En el manual de Ogre pueden consultarse todos los parmetros que admiten todos los operadores disponibles a nivel de textura y pasadas. Figura 8.26: En los ejemplos se han utilizado dos versiones de la textura de cebra; una con transparencia total denida en las bandas negras (en formato PNG), y otra en JPG sin transparencia.

8.6. Ejemplos de Materiales en Ogre

[177]

ZBuffer. Es habitual desactivar el ZBuffer cuando se despliegan objetos transparentes sobre la escena, para que se superpongan adecuadamente. El atributo lighting off indica que no se tenga en cuenta la iluminacin dinmica en esta pasada. Cuando se desactiva la iluminacin dinmica, las propiedades de sombreado difusas, ambientales, especulares y de emisin no se tienen en cuenta, por lo que cualquier denicin en el material sera redundante. El Material5 dene un color transparente deniendo una unidad de textura manualmente. Este material hace uso de las versiones que ms precisin ofrecen a la hora de denir cmo se combina el color (y la opacidad) de una capa de textura con las anteriores. As, la denicin del color manualmente de la fuente como verde, y el nivel de transparencia como 0.25. En trminos generales, el atributo colour_op_ex requiere como primer parmetro el identicador de una operacin operation, y luego dos fuentes src1 src2. Las fuentes pueden ser una de las siguientes cinco opciones: src_current. El color obtenido en capas anteriores. src_texture. El color de la capa actual. src_diffuse. El color difuso de los vrtices. src_specular. El color especular de los vrtices. src_manual. Denicin manual del color. Como operacin admite 15 valores diferentes. Si se indica source1 o source2 se utilizar su valor directamente sin modicacin. La operacin blend_current_alpha (como veremos en el siguiente ejemplo) utiliza la informacin de alpha de las capas anteriores. La operacin modulate multiplica los valores de src1 y src2. El Material6 dene tres capas de textura. La primera carga una textura de csped. La segunda capa carga la textura de cebra con transparencia, e indica que la combinar con la anterior empleando la informacin de alpha de esta segunda textura. Finalmente la tercera capa utiliza el operador extendido de colour_op_ex, donde dene que combinar el color de la capa actual (indicado como primer parmetro en src_texture con el obtenido en las capas anteriores src_current. El parmetro blend_current_alpha multiplica el alpha de src2 por (1alpha(src1)). Los ejemplos de la Figura 8.27 utilizan algunas de las opciones de animacin existentes en las unidades de textura. El Material7 por ejemplo dene dos capas de textura. La primera aplica la textura del suelo al objeto, utilizando el atributo rotate_anim. Este atributo requiere un parmetro que indica el nmero de revoluciones por segundo (empleando velocidad constante) de la textura. La composicin de la segunda capa de textura (que emplea un mapeado de entorno esfrico) se realiza utilizando el atributo colour_op_ex estudiado anteriormente. La versin de la operacin modulate_x2 multiplica el resultado de modulate (multiplicacin) por dos, para obtener un resultado ms brillante.

[178]

CAPTULO 8. MATERIALES Y TEXTURAS

Figura 8.27: Ejemplos de uso de animacin de texturas (rotacin y onda senoidal).

En el ejemplo del Material8 se denen dos capas de textura, ambas con animacin. La segunda capa utiliza una operacin de suma sobre la textura de cebra sin opacidad, de modo que las bandas negras se ignoran. A esta textura se aplica una rotacin de 0.15 revoluciones por segundo. La primera capa utiliza el atributo scroll_anim que permite denir un desplazamiento constante de la textura en X (primer parmetro) y en Y (segundo parmetro). En este ejemplo la textura nicamente se desplaza en el eje X . De igual modo, la primera capa emplea wave_xform para denir una animacin basado en una funcin de onda. En este caso se utiliza una funcin senoidal indicando los parmetros requeridos de base, frecuencia, fase y amplitud (ver el manual de Ogre para ms detalles sobre el uso de la funcin).

8.7.

Render a Textura

En esta seccin estudiaremos un ejemplo en el que se denir una textura que contendr el resultado de renderizar la escena empleando otra cmara auxiliar. Para ello, estudiaremos la creacin manual de texturas, y el uso de un Listener particular que ser ejecutado cada vez que se produzca una actualizacin en la textura. El objeto sobre el que se proyectar la textura est denido en la Figura 8.28.a). En este modelo se han denido tres materiales, cada uno con sus propias coordenadas de despiegue. Las coordenadas ms importantes son las relativas a la pantalla de la televisin, sobre la que desplegaremos la textura. Estas coordenadas se han denido de modo que ocupan todo el rea de mapeado (como se muestra en la Figura 8.28.b). El material asociado a la pantalla se ha nombrado como pantallaTV, y ser editado en cdigo a nivel de SubEntity. Cuando

8.7. Render a Textura

[179]

a)

b)

c)

d)

Figura 8.28: Construccin del ejemplo de R TT. a) Modelo empleado para desplegar la textura de R TT. El modelo se ha denido con tres materiales; uno para la carcasa, otro para las letras del logotipo (ambos desplegados en c), y uno para la pantalla llamado pantallaTV , desplegado en b). En d) se muestra el resultado de la ejecucin del programa de ejemplo.

un modelo cuenta con diversos materiales (como es el caso), Ogre crea un objeto de la clase SubEntity para cada material, de modo que, como veremos a continuacin, tendremos que acceder a todos los SubEntity del objeto para elegir el que tiene el material de la pantalla y cambiarlo por el que calcularemos en tiempo de ejecucin.
Render a Textura
Existen multitud de aplicaciones en videojuegos para utilizar Render a Textura. Por ejemplo, los espejos de cualquier simulador de conduccin o cmaras de vigilancia dentro del juego, as como multitud de efectos grcos (como espejos, motion blur...) y de postproduccin que se realizan empleando esta tcnica.

Hasta ahora hemos desplegado el resultado de la escena sobre la ventana principal de la aplicacin. Sin embargo, en multitud de aplicaciones es habitual renderizar la escena total o parcialmente sobre una textura. Ogre facilita enormemente la construccin de este tipo de texturas. Una vez que tenemos la textura, podemos aplicar cualquier operador de los estudiados en la seccin anterior para mezclarlas con otras capas de textura. El siguiente listado muestra el cdigo relevante para el ejemplo de Render a Textura. El primer paso para aplicar el a Textura es obtener un ob Render ), que permite crear una textura jeto de tipo TexturePtr (lneas 1-3 manualmente, indicando el nombre de la textura (RttT ), y las propiedades de tamao (512x512 pxeles), as como el formato de color (32Bits en RGB, sin canal alfa PF_R8G8B8 ). El ltimo parmetro de TU_RENDERTARGET indica a Ogre el tipo de uso que haremos de la textura.

[180]

CAPTULO 8. MATERIALES Y TEXTURAS

Listado 8.1: Fragmento de CreateScene (MyApp.cpp).


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

TexturePtr rtt = TextureManager::getSingleton().createManual( "RttT", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); RenderTexture *rtex = rtt->getBuffer()->getRenderTarget(); Camera *cam = _sceneManager->createCamera("SecondCamera"); cam->setPosition(Vector3(17,16,-4)); cam->lookAt(Vector3(-3,2.7,0)); cam->setNearClipDistance(5); cam->setFOVy(Degree(38)); rtex->addViewport(cam); rtex->getViewport(0)->setClearEveryFrame(true); rtex->getViewport(0)->setBackgroundColour(ColourValue::Black); rtex->getViewport(0)->setOverlaysEnabled(false); rtex->setAutoUpdated(true); MaterialPtr mPtr = MaterialManager::getSingleton().create( "RttMat",Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); Technique* matTechnique = mPtr->createTechnique(); matTechnique->createPass(); mPtr->getTechnique(0)->getPass(0)->setLightingEnabled(true); mPtr->getTechnique(0)->getPass(0)->setDiffuse(.9,.9,.9,1); mPtr->getTechnique(0)->getPass(0)->setSelfIllumination(.4,.4,.4); mPtr->getTechnique(0)->getPass(0)->createTextureUnitState("RttT"); for (unsigned int i=0; i<entTV->getNumSubEntities(); i++) { SubEntity *aux = entTV->getSubEntity(i); if (aux->getMaterialName() == "pantallaTV") aux->setMaterialName("RttMat"); }

En la lnea 5 se obtiene un puntero a un RenderTexture que es una especializacin de la clase RenderTarget especca para renderizar sobre una textura. Puede haber varios RenderTargets que generen resultados sobre la misma textura. A este de tipo RenderTexture le asociamos objeto ), y una cmara en la lnea 13 (que ha sido creada en las lneas 7-11 conguramos las propiedades especdas del viewport asociado (como que se limpie en cada , y que no represente los frame en la lnea 14 overlays en la lnea 16 ). En la lnea 17 indicamos que la textura se actualice automticamente (gestionada por el bucle principal de Ogre). En otro caso, ser necesario ejecutar manualmente el mtodo update del RenderTarget. Las lneas 19-25 declaran manualmente el material sobre el que emplearemos la Texture Unit con la textura anteriormente denida. En creamos un material llamado RttMat , con una nica tcnica 19-20 (lnea 21 ) y una pasada (lnea 22 ). Esa pasada dene sus propiedades en las lneas 23-25 , y aade como TextureUnit a la textura RttT . El ltimo bucle recorre todas las SubEntities que forman a la entidad de la televisin. En el caso de que el material asociado a la suben tidad sea el llamado pantallaTV (lnea31 ), le asignamos el material que hemos creado anteriormente (lnea 32 ).

8.7. Render a Textura

[181]

8.7.1. Texture Listener


En el ejemplo anterior, la textura proyectada sobre la televisin tiene un efecto recursivo debido a que aparece en el render de la cmara auxiliar. En muchos casos, interesa ocultar uno o varios objetos de la escena para realizar el render a textura (por ejemplo si queremos simular el punto de vista desde el interior de un objeto). Al igual que ocurre a nivel de Frame, es posible aadir uno o varios objetos Listener para controlar la actualizacin de las texturas. De este modo, cada vez que se renderiza un RenderTarget (en nuestro caso concreto una textura), Ogre invocar previamente el mtodo asociado al preRenderTargetUpdate. Cuando la textura se haya actualizado, se ejecutar el mtodo llamado postRenderTargetUpdate.
Figura 8.29: Tras aplicar el texture listener que oculta la entidad de la televisin, se consigue eliminar el efecto de despliegue recursivo.

El siguiente listado muestra el chero de cabecera de la declaracin de una clase propia llamada MyTextureListener que implementa el interfaz denido en RenderTargetListener. Esta clase recibe en el constructor un parmetro con el puntero a un objeto de tipo Entity. La clase se encargar de ocultar esa entidad antes de renderizar la escena sobre la textura y de volver a mostrarlo tras el despliegue.
Listado 8.2: MyTextureListener.h
1 2 3 4 5 6 7 8 9 10 11 12 13

#include <Ogre.h> using namespace std; using namespace Ogre; class MyTextureListener : public RenderTargetListener { private: Entity* _ent; public: MyTextureListener(Entity *ent); ~MyTextureListener(); virtual void preRenderTargetUpdate(const RenderTargetEvent& evt); virtual void postRenderTargetUpdate(const RenderTargetEvent& evt); };

A continuacin se muestra el listado que dene la clase MyTextureListener. La funcionalidad ha sido comentada anteriormente.
Listado 8.3: MyTextureListener.cpp
1 2 3 4 5 6 7 8 9

#include "MyTextureListener.h" MyTextureListener::MyTextureListener(Entity* ent){ _ent = ent; } MyTextureListener::~MyTextureListener(){ }

void MyTextureListener::preRenderTargetUpdate(const RenderTargetEvent& evt) { 10 cout << "preRenderTargetupdate" << endl; 11 _ent->setVisible(false); 12 }
13 14 void MyTextureListener::postRenderTargetUpdate(const

RenderTargetEvent& evt) {

[182]

CAPTULO 8. MATERIALES Y TEXTURAS

15 cout << "postRenderTargetupdate" << endl; 16 _ent->setVisible(true); 17 }

El uso de la clase es muy sencillo. Basta con aadir el listener al objeto de tipo RenderTexture (ver lnea 2 del siguiente listado).
Listado 8.4: Utilizacin en MyApp.cpp
1 _textureListener = new MyTextureListener(entTV); 2 rtex->addListener(_textureListener);

8.7.2. Espejo (Mirror)


La reexin en Espejo es otro de los efectos clsicos que se obtienen mediante render a textura. El siguiente listado muestra el cdigo necesario para realizar este ejemplo. Estudiaremos los aspectos que lo distinguen sobre el cdigo de la seccin anterior. En las lneas 8-12 se dene la cmara que utilizaremos para crear el efecto de mirror. Esta cmara debe tener la misma posicin y orientacin que la cmara desde donde percibimos la escena, pero debe ser independiente (ya que activaremos la reexin sobre un plano, y modicaremos su plano de recorte cercano en las lneas 42-43). Esta cmara para el efecto de espejo (llamada MirrorCamera en este ejemplo) debe estar siempre correctamente alineada con la cmara principal. En este ejemplo, la cmara principal es esttica, por lo que tampoco modicaremos la posicin y orientacin de la MirrorCamera. Queda como ejercicio propuesto para el lector aadir movimiento a la cmara principal, actualizando anlogamente en cada frame la posicin de la cmara Mirror. En las lneas 24-30 se denen las propiedades generales del material. La lnea 31 nos permite generar las coordenadas de textura segn la cmara que se le pasa como argumento, de modo que da la impresin de que la textura ha sido proyectada sobre la supercie. De esta forma, la textura que generamos ser posteriormente renderizada utilizando el modelo de proyeccin denido por la cmara de Mirror. Para concluir, en las lneas 42-43 se conguran los aspectos relativos a la cmara Mirror en relacin al plano de reexin. La llamada a enableReection hace que se modique el Frustum de la cmara de modo que renderice empleando la reexin con respecto del plano que se le pasa como argumento.

Figura 8.30: Resultado de aplicar el material con Render a Textura para simular espejo sobre el plano del suelo.

8.7. Render a Textura

[183] Finalmente, la llamada a enableCustomNearClipPlane permite recortar la geometra situada debajo del plano pasado como argumento, de modo que nicamente la geometra que est situada sobre el plano ser nalmente desplegada en el reejo, evitando as errores de visualizacin.
Listado 8.5: Denicin del Material tipo Espejo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

TexturePtr rttM_texture = TextureManager::getSingleton() .createManual("RttMTex", ResourceGroupManager:: DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); RenderTexture *rMtex= rttM_texture->getBuffer()->getRenderTarget(); Camera *camM = _sceneManager->createCamera("MirrorCamera"); Camera *mainCam = _sceneManager->getCamera("MainCamera"); camM->setPosition(mainCam->getPosition()); camM->setOrientation(mainCam->getOrientation()); camM->setAspectRatio(mainCam->getAspectRatio()); rMtex->addViewport(camM); rMtex->getViewport(0)->setClearEveryFrame(true); rMtex->getViewport(0)->setBackgroundColour(ColourValue::Black); rMtex->getViewport(0)->setOverlaysEnabled(false); rMtex->setAutoUpdated(true); MaterialPtr mMPtr=MaterialManager::getSingleton().create("RttMMat", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); Technique* matMTechnique = mMPtr->createTechnique(); matMTechnique->createPass(); TextureUnitState *t = mMPtr->getTechnique(0)->getPass(0)-> createTextureUnitState("grid.jpg"); t = mMPtr->getTechnique(0)-> getPass(0)->createTextureUnitState("RttMTex"); t->setColourOperationEx(LBX_BLEND_MANUAL, LBS_TEXTURE, LBS_CURRENT, ColourValue::White, ColourValue::White, 0.5); t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); t->setProjectiveTexturing(true, camM); // Creacion del plano del suelo... Plane plane1(Vector3::UNIT_Y, 0); MeshManager::getSingleton().createPlane("plane1", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane1, 200,200,1,1,true,1,10,10,Vector3::UNIT_Z); SceneNode* node3 = _sceneManager->createSceneNode("ground"); Entity* grEnt = _sceneManager->createEntity("planeEnt", "plane1"); camM->enableReflection(plane1); camM->enableCustomNearClipPlane(plane1); grEnt->setMaterialName("RttMMat");

Captulo

Iluminacin
Carlos Gonzlez Morcillo

n el captulo anterior hemos estudiado algunas de las caractersticas relativas a la denicin de materiales bsicos. Estas propiedades estn directamente relacionadas con el modelo de iluminacin y la simulacin de las fuentes de luz que realicemos. Este captulo introduce algunos conceptos generales sobre iluminacin en videojuegos, as como tcnicas ampliamente utilizadas para la simulacin de la iluminacin global.

9.1.

Introduccin

Una pequea parte de los rayos de luz son visibles al ojo humano. Aquellos rayos que estn denidos por una onda con longitud de onda entre 700 y 400nm. Variando las longitudes de onda obtenemos diversos colores. En grcos por computador es habitual emplear los denominados colores-luz, donde el Rojo, Verde y Azul son los colores primarios y el resto se obtienen de su combinacin. En los colores-luz el color blanco se obtiene como la suma de los tres colores bsicos. El RGB es un modelo clsico de este tipo. En el mundo fsico real se trabaja con colores-pigmento, donde el Cyan, el Magenta y el Amarillo forman los colores primerarios. La combinacin de igual cantidad de los tres colores primarios obtiene el color negro1 . As, el CMYK (Cyan Magenta Yellow Key) empleado por las impresoras es un clsico modelo
1 En realidad se obtiene un tono parduzco, por lo que habitualmente es necesario incorporar el negro como color primario.

185

[186] de este tipo. De un modo simplicado, podemos denir los pasos ms relevantes para realizar la representacin de una escena sinttica: 1. La luz es emitida por las fuentes de luz de la escena (como el sol, una lmpara de luz situada encima de la mesa, o un panel luminoso en el techo de la habitacin). 2. Los rayos de luz interactan con los objetos de la escena. Dependiendo de las propiedades del material de estos objetos, parte de la luz ser absorbida y otra parte reejada y propagada en diversas direcciones. Todos los rayos que no son totalmente absorbidos continuarn rebotando en el entorno. 3. Finalmente algunos rayos de luz sern capturados por un sensor (como un ojo humano, el sensor CCD (Charge-Coupled Device) de una cmara digital o una pelcula fotogrca). La luz puede ser modelada empleando diversas aproximaciones, centrndose en las propiedades direccionales (rayos puramente geomtricos), como ondas electromagnticas o como partculas cunticas (fotones). Dependiendo del mtodo de representacin, suele emplearse un modelo u otro. Independientemente del tratamiento que demos a la luz, sta debe ser simulada como energa que viaja en el espacio. Las fuentes de luz sern emisores de esta energa. Directamente asociado al concepto de iluminacin encontramos las sombras. Gracias a la proyeccin de sombras, podemos establecer relaciones espaciales entre los objetos de la escena. Por ejemplo, en la Figura 9.1, gracias al uso de sombras podemos saber la posicin exacta de la esfera relativa a la escalera. A continuacin estudiaremos los principales tipos de luz que suelen emplearse en videojuegos, as como los modelos de sombreado estticos y dinmicos ms utilizados.

CAPTULO 9. ILUMINACIN

Figura 9.1: Gracias a la proyeccin de sombras es posible conocer la posicin relativa entre objetos. En la imagen superior no es posible determinar si el modelo de Suzanne reposa sobre algn escaln o est otando en el aire. La imagen inferior, gracias al uso de sombras elimina esa ambigedad visual.

Simplica!!
Como ya comentamos en el Captulo 8, este modelo de iluminacin es una simplicacin del modelo fsicamente correcto que se resuelve con mejores aproximaciones de la ecuacin de Rendering de James Kajiya.

9.2.

Tipos de Fuentes de Luz

Las fuentes de luz pueden representarse de diversas formas, dependiendo de las caractersticas que queramos simular en la etapa de rendering. Para especicar la cantidad de energa emitida por una fuente de luz, la radiometra (ciencia que se encarga de medir la luz) dene la irradiancia como la cantidad de fotones que pasan por una supercie por segundo. En videojuegos suelen permitirse tres tipos de fuentes de luz directamente soportadas por el hardware de aceleracin grco: Las fuentes puntuales (point lights) irradian energa en todas las direcciones a partir de un punto que dene su posicin en el espacio. Este tipo de fuentes permite variar su posicin pero no su direccin. En realidad, las fuentes de luz puntuales no

9.3. Sombras Estticas Vs Dinmicas

[187]

existen como tal en el mundo fsico (cualquier fuente de luz tiene asociada un rea, por lo que para realizar simulaciones realistas de la iluminacin tendremos que trabajar con fuentes de rea. Ogre dene este tipo de fuente como LT_POINT.
Fuente Puntual

Fuente Direccional

Uno de los tipos de fuentes ms sencillo de simular son las denominadas fuentes direccionales (directional lights), que pueden considerarse fuentes situadas a una distancia muy grande, por lo que los rayos viajan en una nica direccin en la escena (son paralelos entre s). El sol podra ser modelado mediante una fuente de luz direccional. De este modo, la direccin viene determinada por un vector l (especicado en coordenadas universales). Este tipo de fuentes de luz no tienen por tanto una posicin asociada (nicamente direccin). Este tipo de fuente est descrito como LT_DIRECTIONAL en Ogre. Finalmente los focos (spot lights) son en cierto modo similares a las fuentes de luz puntuales, pero aadiendo una direccin de emisin. Los focos arrojan luz en forma cnica o piramidal en una direccin especca. De este modo, requieren un parmetro de direccin, adems de dos ngulos para denir los conos de emisin interno y externo. Ogre las dene como LT_SPOTLIGHT. Las fuentes de luz permiten especicar multitud de parmetros y propiedades, como el color difuso y especular. Una fuente de luz puede denir un color de iluminacin difuso (como si el cristal de la bombilla estuviera tintado), y un color diferente para el brillo especular. Ambas propiedades estn directamente relacionadas con el modo en el que reejarn la luz los materiales. En aplicaciones de sntesis de imagen realista suelen denirse adems fuentes de luz de rea. Este tipo de fuentes simulan el comportamiento de la luz de un modo ms realista, donde potencialmente cada punto de la supercie se comporta como un emisor de luz. En la seccin 9.7 estudiaremos el modelo de Radiosidad que permite trabajar con fuentes de luz de rea.

Fuente Foco
Figura 9.2: Tipos de fuentes de luz utilizadas en aplicaciones interactivas. Ogre soporta nicamente estos tres tipos de fuentes bsicos.

9.3.

Sombras Estticas Vs Dinmicas

La gestin de sombras es un aspecto crtico para dotar de realismo a las escenas sintticas. Sin embargo, el clculo de sombras trae asociado un coste computacional importante. De esta forma, en multitud de ocasiones se emplean tcnicas de pre-clculo de la iluminacin y las sombras. Estos mapas de iluminacin permiten generar sombras suaves sin coste computacional adicional. Ogre soporta dos tcnicas bsicas de sombreado dinmico: sombreado empleando el Stencil Buffer y mediante Mapas de Texturas (ver Figura 9.4). Ambas aproximaciones admiten la especicacin como Additive o Modulative.

[188]

CAPTULO 9. ILUMINACIN

En muchas ocasiones se implementan, empleando el Pipeline en GPU programable, algoritmos de sombreado avanzados como aproximaciones al Ambient Occlusion (que veremos en la seccin 9.6 o Radiosidad Instantnea (ver seccin 9.7).
a

Las tcnicas de tipo Modulative nicamente oscurecen las zonas que quedan en sombra, sin importar el nmero de fuentes de luz de la escena. Por su parte, si la tcnica se especica de tipo Additive es necesario realizar el clculo por cada fuente de luz de modo acumulativo, obteniendo un resultado ms preciso (pero ms costoso computacionalmente). Cada tcnica tiene sus ventajas e inconvenientes (como por ejemplo, el relativo a la resolucin en el caso de los Mapas de Textura, como se muestra en la Figura 9.3). No es posible utilizar varias tcnicas a la vez, por lo que deberemos elegir la tcnica que mejor se ajuste a las caractersticas de la escena que queremos representar. En trminos generales, los mtodos basados en mapas de textura suelen ser ms precisos, pero requieren el uso de tarjetas aceleradoras ms potentes. Veamos las caractersticas generales de las tcnicas de sombreado para estudiar a continuacin las caractersticas particulares de cada mtodo. nicamente podemos utilizar una tcnica de sombreado en la escena. Esta tcnica debe ser especicada preferiblemente antes de especicar los objetos que formen parte de la escena. Las propiedades del material determinan si el objeto arrojar o recibir sombra. Por defecto los objetos arrojan sombra (salvo los objetos con materiales transparentes, que no arrojarn sombra). Es posible denir fuentes de luz que no arrojen sombras. En ambos casos es conveniente evitar que las sombras se proyecten de forma extrema (por ejemplo, simulando un amanacer). Este tipo de situaciones hace que la calidad de la sombra se degrade enormemente. Dado su coste computacional, por defecto las sombras estn desactivadas en Ogre. Para que un material reciba o arroje sombras, el parmetro lighting del material debe estar en on (por defecto). A continuacin estudiaremos los detalles de ambos tipos de sombras soportados en Ogre.

b
Figura 9.3: Comparativa entre sombras calculadas por a) Mapas de Texturas y b) Stencil Buffer. Las basadas en mapas de texturas son claramente dependientes de la resolucin del mapa, por lo que deben evitarse con reas de proyeccin muy extensas.

9.3.1. Sombras basadas en Stencil Buffer


Empleando esta tcnica de sombreado, la forma de la sombra que ser proyectada se obtiene proyectando la silueta del objeto calculada desde la perspectiva de la fuente de luz.

9.3. Sombras Estticas Vs Dinmicas

[189]

Figura 9.4: Utilizacin de diversos modos de clculo de sombras y materiales asociados. a) Sombras mediante Mapas de Texturas y Material simple. b) Sombras por Stencil Buffer y Material simple. c) Sombras por Stencil Buffer y Material con Ambient Occlusion precalculado. d) Sombras mediante Mapas de Texturas y Material basado en textura de mrmol procedural precalculada. e) Sombras por Stencil Buffer y Material basado en textura de mrmol procedural precalculada. f) Sombras por Stencil Buffer y Material combinado de c) + e) (Ambient Occlusion y Textura de Mrmol precalculados).

El Stencil Buffer es un buffer extra disponible en las GPUs modernas que permite almacenar un byte por pxel. Habitualmente se emplea para recortar el rea de renderizado de una escena. En el clculo de sombras, se utiliza en combinacin con el ZBuffer para recortar la zona de sombra relativa al punto de vista. El proceso de clculo puede resumirse en los siguientes pasos (ver Figura 9.5): 1. Para cada fuente de luz, obtener la lista de aristas de cada objeto que comparten polgonos cuyo vector normal apunta hacia la fuente de luz y las que estn opuestas a la misma. Estas aristas denen la silueta del objeto desde el punto de vista de la fuente de luz. 2. Proyectar estas aristas de silueta desde la fuente de luz hacia la escena. Obtener el volumen de sombra proyectado sobre los objetos de la escena. 3. Finalmente, utilizar la informacin de profundidad de la escena (desde el punto de vista de la cmara virtual) para denir en el Stencil Buffer la zona que debe recortarse de la sombra (aquella cuya profundidad desde la cmara sea mayor que la denida en el ZBuffer ). La Figura 9.5 muestra cmo la proyeccin del volumen

[190]

CAPTULO 9. ILUMINACIN

Fuente F o co

ZBuffer (Mapa Profundidad)

Imagen Resultado

+
Cmara Volumen de sombra proyectada

Volumen de sombra proyectada

tencil buffer

Figura 9.5: Proceso de utilizacin del Stencil Buffer para el recorte de la proyeccin del volumen de sombra.

de sombra es recortado para aquellos puntos cuya profundidad es menor que la relativa a la proyeccin del volumen de sombra. Esta tcnica de generacin de sombras, a diferencia de las basadas en Mapas de Textura, utiliza ciclos de la CPU para el renderizado (las operaciones relativas al clculo de aristas y proyeccin sobre la escena 3D). A continuacin se describen algunas de las caractersticas fundamentales de las sombras basadas en Stencil Buffer. Empleando el Stencil Buffer, las sombras de objetos transparentes emitirn sombras totalmente slidas. Es posible desactivar totalmente las sombras de este tipo de objetos, pero empleando Stencil Buffer no es posible obtener sombras semitransparentes. Empleando esta tcnica no es posible obtener sombras con aristas suaves. En el caso de necesitar este tipo de sombras ser necesario emplear la tcnica basada de Mapas de Textura (ver Seccin 9.3.2). Esta tcnica permite que el objeto reciba su propia sombra, como se muestra en la Figura 9.6.b. Es necesario que Ogre conozca el conjunto de aristas que denen el modelo. Exportando desde Blender, la utilidad OgreXMLConverter realiza el clculo automticamente. Sin embargo, si implementamos nuestro propio cargador, deberemos llamar a buildEdgeList de la clase Mesh para que construya la lista.
a

Figura 9.6: En el clculo de sombras mediante Mapas de Textura (en a)), el objeto emisor de sombras no recibe su propia sombra proyectada. Empleando el Stencil Buffer (b)) es posible recibir la sombra proyectada.

9.3. Sombras Estticas Vs Dinmicas

[191]

Fuente de luz

Fuente de luz

Cmara

b a
Mapa Profundidad desde la fuente de luz

Pb

Resultado final

Pa

Figura 9.7: Pasos en el clculo de sombras mediante mapas de textura.

9.3.2. Sombras basadas en Texturas


El clculo de las sombras basadas en texturas se basa en un simple principio: si observamos una escena desde el punto de vista de la fuente de luz, cualquier punto situado detrs de lo que ve la fuente de luz estar en sombra. Esta idea puede realizarse en dos pasos principales empleando texturas calculadas directamente en la GPU. En el primer paso se construye el mapa de profundidad desde el punto de vista. Este mapa simplemente codica la distancia menor de los objetos de la escena a la fuente de luz (como se muestra en la parte izquierda de la Figura 9.7). El segundo paso utiliza esta informacin para construir la sombra. Se calcula la distancia del objeto a la cmara y compara esta distancia con la codicada en el mapa de profundidad. Si la distancia entre cada punto y la fuente de luz es mayor que la almacenada en dicho mapa, el punto est en sombra (Figura 9.7 derecha). Empleando sombras basadas en texturas el objeto debe ser denido como receptor o emisor de sombras. Un objeto no puede ser emisor y receptor de sombras a la vez (por lo que un emisor no puede recibir sus propias sombras). A continuacin enumeraremos algunas de las caractersticas fundamentales de este tipo de tcnica.
Z-Fighting
La distincin en grupos de emisores y receptores de sombras se crea para evitar problemas de Z-ghting (cuando dos o ms elementos tienen asociada la misma profundidad en el ZBuffer y su representacin es incorrecta).

Este tipo de sombras permiten el manejo correcto de la transparencia. Adems, las sombras pueden tener un color propio. Se basan principalmente en el uso de la GPU, por lo que descargan en gran medida la CPU. Directamente relacionado con esta caracterstica, las sombras basadas en mapas de textura permiten componer otros efectos en la GPU (como deformaciones empleando un Vertex Shader ). Esta tcnica no permite que el objeto reciba sus propias sombras.

[192]

CAPTULO 9. ILUMINACIN

9.4.

Ejemplo de uso

El siguiente ejemplo de uso construye una aplicacin que permite elegir entre el uso de texturas basadas en Stencil Buffer o en Mapas de Textura.
Listado 9.1: Fragmento de MyApp.cpp
1 void MyApp::createScene() { 2 _sceneManager->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE); 3 _sceneManager->setShadowColour(ColourValue(0.5, 0.5, 0.5)); 4 _sceneManager->setAmbientLight(ColourValue(0.9, 0.9, 0.9)); 5 6 _sceneManager->setShadowTextureCount(2); 7 _sceneManager->setShadowTextureSize(512); 8 9 Light* light = _sceneManager->createLight("Light1"); 10 light->setPosition(-5,12,2); 11 light->setType(Light::LT_SPOTLIGHT); 12 light->setDirection(Vector3(1,-1,0)); 13 light->setSpotlightInnerAngle(Degree(25.0f)); 14 light->setSpotlightOuterAngle(Degree(60.0f)); 15 light->setSpotlightFalloff(0.0f); 16 light->setCastShadows(true); 17 18 Light* light2 = _sceneManager->createLight("Light2"); 19 light2->setPosition(3,12,3); 20 light2->setDiffuseColour(0.2,0.2,0.2); 21 light2->setType(Light::LT_SPOTLIGHT); 22 light2->setDirection(Vector3(-0.3,-1,0)); 23 light2->setSpotlightInnerAngle(Degree(25.0f)); 24 light2->setSpotlightOuterAngle(Degree(60.0f)); 25 light2->setSpotlightFalloff(5.0f); 26 light2->setCastShadows(true); 27 28 Entity* ent1 = _sceneManager->createEntity("Neptuno.mesh"); 29 SceneNode* node1 = _sceneManager->createSceneNode("Neptuno"); 30 ent1->setCastShadows(true); 31 node1->attachObject(ent1); 32 _sceneManager->getRootSceneNode()->addChild(node1); 33 34 // ... Creamos plano1 manualmente (codigo eliminado) 35 36 SceneNode* node2 = _sceneManager->createSceneNode("ground"); 37 Entity* groundEnt = _sceneManager->createEntity("p", "plane1"); 38 groundEnt->setMaterialName("Ground"); 39 groundEnt->setCastShadows(false); 40 node2->attachObject(groundEnt); 41 _sceneManager->getRootSceneNode()->addChild(node2); 42 }

En la lnea 2 se dene la tcnica de clculo de sombras que se utilizar por defecto, aunque en el FrameListener se cambiar en tiempo de ejecucin empleando las teclas 1 y 2 . Las lneas 2-3 denen propiedades generales de la escena, como el color con el que se representarn las sombras y el color de la luz ambiental (que en este ejemplo, debido a la denicin de los materiales, tendr especial importancia). Las lneas 6-9 nicamente tienen relevancia en el caso del uso del mtodo de clculo basado en mapas de textura. Si el mtodo utiliza-

9.4. Ejemplo de uso

[193] do es el de Stencil Buffer simplemente sern ignoradas. La lnea 6 congura el nmero de texturas que se emplearn para calcular las sombras. Si se dispone de ms de una fuente de luz (como en este ejemplo), habr que especicar el nmero de texturas a utilizar. El tamao de la textura (cuadrada) se indica en la lnea 7 . A mayor tamao, mejor resolucin en la sombra (pero mayor cantidad de memoria gastada). El tamao por defecto es 512, y debe ser potencia de dos. A continuacin en las lneas 9-26 se denen dos fuente de luz de tipo SPOTLIGHT. Cada luz dene su posicin y rotacin. En el caso de la segunda fuente de luz se dene adems un color difuso (lnea ). 20 El ngulo interno y externo 13-14 dene el cono de iluminacin de la fuente. En ambas fuentes se ha activado la propiedad de que la fuente de luz permita el clculo de sombras.

El mtodo de setCastShadows pertenece a la clase MovableObject. En el caso de entidades, si se especica como cierto, el objeto arrojar sombras sobre otros objetos. En caso contrario, funcionar como un receptor de sombras. El mismo mtodo se aplica sobre luces (que, es un tipo especco de MovableObject ). En el caso de fuentes de luz, el mismo mtodo sirve para especicar si esa fuente de luz se utilizar en el clculo de sombras.

Figura 9.8: Denicin del material multicapa para componer una textura con iluminacin de tipo AbmientOcclusion con la textura de color. Ambas texturas emplean un despliegue automtico (tipo LightMap en Blender).

Como hemos comentado en la seccin 9.3.2, si utilizamos mapas de textura para calcular sombras, un objeto puede funcionar nicamente como receptor o como emisor de sombras. En este ejemplo, el plano se congura como receptor de sombras (en la lnea 39 ), mientras que el ). objeto Neptuno funciona como emisor (lnea 30 Mediante las teclas 7 ... 0 es posible cambiar el material asociado al objeto principal de la escena. En el caso del ltimo material de nido para el objeto (tecla 0 ), se compone en dos capas de textura el color base (calculado mediante una textura procedural) y una capa de iluminacin basada en Ambient Occlusion. La denicin del material compuesto se muestra en la Figura 9.8. Gracias a la separacin de la iluminacin y del color en diferentes mapas, es posible cambiar la resolucin individualmente de cada uno de ellos, o reutilizar el mapa de iluminacin en diferentes modelos que compartan el mismo mapa de iluminacin pero tengan diferente mapa de color. Multitud de juegos utilizan el preclculo de la iluminacin. Quake II y III utilizaron modelos de Radiosidad para crear mapas de iluminacin para simular de una forma mucho ms realista el comportamiento fsico de la luz en la escena. Aunque actualmente poco a poco se implantan las tcnicas de iluminacin dinmicas a nivel de pxel, los mapas de iluminacin siguen siendo una opcin ampliamente utilizada.

[194]

CAPTULO 9. ILUMINACIN

Geometra base

Mapa de color

Mapa de Iluminacin
(Ambient Occlusion)

Resultado Final

Figura 9.9: Ejemplo de uso de un mapa de iluminacin para denir sombras suaves en un objeto. El mapa de color y el mapa de iluminacin son texturas independiente que se combinan (multiplicando su valor) en la etapa nal.

9.5.

Mapas de Iluminacin

Como hemos visto anteriormente, los modelos de iluminacin local calculan en cada vrtice del modelo la interaccin con la luz. El color nal de cada punto del modelo se calcula mediante tcnicas de interpolacin. Las sombras obtenidas empleando estos mtodos no son precisas (por ejemplo, no se pueden calcular sombras difusas). En los ltimos aos las tarjetas grcas permiten el clculo de mtodos de iluminacin por pxel (per pixel lighting), de modo que por cada pxel de la escena se calcula la contribucin real de la iluminacin. El clculo preciso de las sombras es posible, aunque a da de hoy todava es muy costoso para videojuegos. Los mapas de luz permiten precalcular la iluminacin por pxel de forma esttica. Esta iluminacin precalculada puede ser combinada sin ningn problema con los mtodos de iluminacin dinmicos estudiados hasta el momento. La calidad nal de la iluminacin es nicamente dependiente del tiempo invertido en el preclculo de la misma y la resolucin de las texturas.

En trminos generales, el pxel de una textura se denomina texel (de Texture Element ). De forma anloga, un pxel de un mapa de iluminacin se denomina lumel (Lumination Element ).

De este modo, para cada cara poligonal del modelo se denen una o varias capas de textura. La capa del mapa de iluminacin es nalmente multiplicada con el resultado de las capas anteriores (como se puede ver en la Figura 9.9). A diferencia de las texturas de color donde cada vrtice del modelo puede compartir las mismas coordenadas UV con otros vrtices, en

9.5. Mapas de Iluminacin

[195] mapas de iluminacin cada vrtice de cada cara debe tener una coordenada nica. Los mapas de iluminacin se cargan de la misma forma que el resto de texturas de la escena. En la Figura 9.8 hemos estudiado un modo sencillo de composicin de estos mapas de iluminacin, aunque pueden denirse otros mtodos que utilicen varias pasadas y realicen otros modos de composicin. A continuacin estudiaremos dos tcnicas ampliamente utilizadas en el preclculo de la iluminacin empleando mapas de iluminacin: Ambient Occlusion y Radiosidad.

Aunque nos centremos en los mtodos de Ambient Occlusion y Radiosidad, Blender permite precalcular (Render Baking) cualquier conguracin de escena. De este modo, se puede precalcular cualquier conguracin de luces y materiales de la escena.

Figura 9.10: Despliegue del modelo de Neptuno empleando Lightmap Pack. Cada cara poligonal tiene asociado un espacio propio en la textura.

Como hemos comentado antes, cualquiera de los mtodos de clculo de mapas de iluminacin requiere que cada cara poligional del modelo tenga unas coordenadas UV nicas en el modelo. Como estudiamos en la seccin 8.5, empleando el despliegue de tipo Lightmap Pack conseguimos que Blender despliegue el modelo de esta forma, asignando el rea de la imagen de forma proporcional al tamao de cada cara del modelo. La Figura 9.10 muestra el despliegue realizado para el modelo de Neptuno tras aplicar Ambient Occlusion. Una vez realizado el despliegue y con una imagen asociada al despiegue UV (puede crearse una imagen nueva vaca de color slido desde la cabecera de la ventana UV Image Editor en el men Image/ New Image ), el preclculo de la iluminacin se realiza en la pestaa Bake del grupo de botones de Render (ver Figura 9.11). A continuacin se estudiarn las opciones ms relevantes en el mbito del preclculo de la iluminacin. Mediante la lista desplegable Bake Mode, se elige el tipo de preclculo que va a realizarse. Con Full Render se realizar el clculo de todas las propiedades del material, texturas e iluminacin sobre la textura (sin tener en cuenta el brillo especular que es dependiente del punto de vista del observador). Si se elige la opcin Ambient Occlusion (como se muestra en la gura 9.11), nicamente se tendr en cuenta la informacin de AO ignorando el resto de fuentes de luz de la escena (ver seccin 9.6). Mediante la opcin Textures se asignan los colores base de los materiales y texturas (sin tener en cuenta el sombreado). El checkbox Clear sirve para borrar la textura antes de realizar el baking. Puede ser interesante desactivarlo si queremos aplicar una pasada de AO a una textura previamente asignada manualmente. El botn Selected to Active permite asignar la informacin de otro objeto. Un uso tpico de esta herramienta es disponer de un modelo en alta resolucin que dene una geometra muy detallada, y mapear su informacin en otro modelo de baja resolucin. En esta seccin utilizaremos esta funcionalidad para asociar la informacin de una

Figura 9.11: Opciones de la pestaa Bake del grupo de botones de Render.

[196] malla de radiosidad a la malla en baja resolucin de la escena. Finalmente, cuando se han elegido los parmetros en la pestaa, pulsando el botn Bake se inicia el proceso de clculo. En la ventana de UV Mapping deber verse la actualizacin en tiempo real de la textura mapeada al modelo.

CAPTULO 9. ILUMINACIN

9.6.

Ambient Occlusion
Punto de Vista Objeto
a

El empleo del trmino de luz ambiente viene aplicndose desde el inicio de los grcos por computador como un mtodo muy rpido de simular la contribucin de luz ambiental que proviene de todas las direcciones. La tcnica de Ambient Occlusion es un caso particular del uso de pruebas de oclusin en entornos con iluminacin local para determinar los efectos difusos de iluminacin. Estas tcnicas fueron introducidas inicialmente por Zhurov como alternativa a las tcnicas de radiosidad para aplicaciones interactivas (videojuegos), por su bajo coste computacional. En el esquema de la gura 9.12 podemos ver en qu se basan estas tcnicas. Desde cada punto P de interseccin con cada supercie (obtenido mediante trazado de rayos), calculamos el valor de ocultacin de ese punto que ser proporcional al nmero de rayos que alcanzan el cielo (los que no intersectan con ningn objeto dada una distancia mxima de interseccin). En el caso de la gura sern 4/7 de los rayos lanzados. Podemos denir la ocultacin de un punto de una supercie como: W (P ) = 1 (d(P, ))cosd

(9.1)

Obteniendo un valor de ocultacin W (P ) entre 0 y 1, siendo d(P, ) la distancia entre P y la primera interseccin con algn objeto en la direccin de . (d(P, )) es una funcin con valores entre 0 y 1 que nos indica la magnitud de iluminacin ambiental que viene en la direccin de , y es el ngulo formado entre la normal en el punto P y la direccin de . Estas tcnicas de ocultacin (obscurances) se desacoplan totalmente de la fase de iluminacin local, teniendo lugar en una segunda fase de iluminacin secundaria difusa. Se emplea un valor de distancia para limitar la ocultacin nicamente a polgonos cercanos a la zona a sombrear mediante una funcin. Si la funcin toma valor de ocultacin igual a cero en aquellos puntos que no superan un umbral y un valor de uno si estn por encima del umbral, la tcnica de ocultacin se denomina Ambient Occlusion. Existen multitud de funciones exponenciales que se utilizan para lograr estos efectos. La principal ventaja de esta tcnica es que es bastante ms rpida que las tcnicas que realizan un clculo correcto de la iluminacin indirecta. Adems, debido a la sencillez de los clculos, pueden realizarse aproximaciones muy rpidas empleando la GPU, pudiendo utilizarse en aplicaciones interactivas. El principal inconveniente es

Figura 9.12: Descripcin esquemtica del clculo de Ambient Occlusion. a) Esquema de clculo del valor de ocultacin W (P ). b) Render obtenido con iluminacin lobal (dos fuentes puntuales). c) La misma conguracin que en b) pero con Ambient Occlusion de 10 muetras por pxel.

9.7. Radiosidad

[197] que no es un mtodo de iluminacin global y no puede simular efectos complejos como casticas o contribuciones de luz entre supercies con reexin difusa. Para activar el uso de Ambient Occlusion (AO) en Blender, en el , en la pestaa Ambient Occlusion actigrupo de botones del mundo vamos el checkbox (ver Figura 9.13). La pestaa Gather permite elegir el tipo de recoleccin de muestras entre trazado de rayos Raytrace o Aproximada Approximate (ver Figura 9.13). El clculo de AO mediante Trazado de Rayos ofrece resultados ms precisos a costa de un tiempo de render mucho mayor. El efecto del ruido blanco debido al nmero de rayos por pxel puede disminuirse a costa de aumentar el tiempo de cmputo aumentando el nmero de muestras (Samples).

Figura 9.13: Pestaa Amb Occ en Blender.

El mtodo AO Aproximado realiza una rpida aproximacin que, en muchos casos, puede ser suciente. No sufre de ruido de muestreo, por lo que es buena opcin para ser utilizada en multitud de ocasiones. El parmetro Error dene la calidad de las sombras calculadas (valores menores implican mejores resultados con mayor tiempo de cmputo). El checkbox Pixel Cache si est activo hace que el valor de sombreado se interpole entre pxeles vecinos, haciendo que el clculo sea an ms rpido (aunque menos exacto). A continuacin estudiaremos algunas opciones relevantes del mtodo: Falloff: Esta opcin controla el tamao de las sombras calculadas por AO. Si est activa, aparece un nuevo control Strength que permite variar el factor de atenuacin. Con valores mayores de Strength, la sombra aparece ms enfocada (es ms pequea). Add (Por defecto): El punto recibe luz segn los rayos que no se han chocado con ningn objeto. La escena esta ms luminosa que la original sin AO. Multiply: El punto recibe sombra segn los rayos que han chocado con algn objeto. La escena es ms oscura que la original sin AO.

9.7.

Radiosidad

En esta tcnica se calcula el intercambio de luz entre supercies. Esto se consigue subdividiendo el modelo en pequeas unidades denominadas parches, que sern la base de la distribucin de luz nal. Inicialmente los modelos de radiosidad calculaban las interacciones de luz entre supercies difusas (aquellas que reejan la luz igual en todas las direcciones), aunque existen modelos ms avanzados que tienen en cuenta modelos de reexin ms complejos.
Figura 9.14: El modelo de Radiosidad permite calcular el intercambio de luz entre supercies difusas, mostrando un resultado de render correcto en el problema planteado en la histrica Cornell Box.

El modelo bsico de radiosidad calcula una solucin independiente del punto de vista. Sin embargo, el clculo de la solucin es muy costoso en tiempo y en espacio de almacenamiento. No obstante, cuando la iluminacin ha sido calculada, puede utilizarse para renderizar la

[198] escena desde diferentes ngulos, lo que hace que este tipo de soluciones se utilicen en visitas interactivas y videojuegos en primera persona actuales. En el ejemplo de la gura 9.15, en el techo de la habitacin se encuentran las caras poligonales con propiedades de emisin de luz. Tras aplicar el proceso del clculo de radiosidad obtenemos la malla de radiosidad que contiene informacin sobre la distribucin de iluminacin entre supercies difusas. En el modelo de radiosidad, cada supercie tiene asociados dos valores: la intensidad luminosa que recibe, y la cantidad de energa que emite (energa radiante). En este algoritmo se calcula la interaccin de energa desde cada supercie hacia el resto. Si tenemos n supercies, la complejidad del algoritmo ser O(n2 ). El valor matemtico que calcula la relacin geomtrica entre supercies se denomina Factor de Forma, y se dene como: cosi cosj Hij dAj (9.2) r2 Siendo Fij el factor de forma de la supercie i a la supercie j , en el numerador de la fraccin denimos el ngulo que forman las normales de las supercies, r2 mide la distancia entre las supercies, Hij es el parmetro de visibilidad, que valdr uno si la superce j es totalmente visible desde i, cero si no es visible y un valor entre uno y cero segn el nivel de oclusin. Finalmente, dAj indica el rea de la superce j (no tendremos el mismo resultado con una pequea supercie emisora de luz sobre una superce grande que al contrario). Este factor de forma se suele calcular empleando un hemi-cubo. Fij = Ser necesario calcular n2 factores de forma (no cumple la propiedad conmutativa) debido a que se tiene en cuenta la relacin de rea entre supercies. La matriz que contiene los factores de forma relacionando todas las supercies se denomina Matriz de Radiosidad. Cada elemento de esta matriz contiene un factor de forma para la interaccin desde la supercie indexada por la columna hacia la supercie indexada por la la (ver gura 9.16). Algoritmo de renamiento progresivo
1 2 3 4 5 6 7

CAPTULO 9. ILUMINACIN

Para cada iteracin seleccionar un parche i calcular Fij para todas las superficies j para cada superficie j hacer: actualizar la radiosidad de la superficie j actualizar la emisin de la superficie j emision(i) = 0

En 1988, Cohen introdujo una variante de clculo basada en el renamiento progresivo que permite que la solucin de radiosidad encontrada en cada iteracin del algoritmo sea mostrada al usuario. Este mtodo progresivo es un mtodo incremental que requiere menos tiempo de cmputo y de almacenamiento; en cada iteracin se calcula los factores de forma entre una supercie y el resto (en el artculo original se requera el clculo de n2 factores de forma).

9.7. Radiosidad

[199]

Figura 9.15: Ejemplo de aplicacin del mtodo de radiosidad sobre una escena simple. En el techo de la habitacin se ha denido una fuente de luz. a) Malla original. b) Malla de radiosidad. c) Resultado del proceso de renderizado.

Este mtodo de renamiento progresivo nalmente obtiene la misma solucin que el original, proporcionando resultados intermedios que van siendo renados.
Renamiento Progresivo
Blender implementa el mtodo de Radiosidad basado en renamiento progresivo

En general, el clculo de la radiosidad es eciente para el clculo de distribuciones de luz en modelos simples con materiales difusos, pero resulta muy costoso para modelos complejos (debido a que se calculan los valores de energa para cada parche del modelo) o con materiales no difusos. Adems, la solucin del algoritmo se muestra como una nueva malla poligonal que tiende a desenfocar los lmites de las sombras. Como en videojuegos suelen emplearse modelos en baja poligonalizacin, y es posible mapear esta iluminacin precalculada en texturas, el modelo de Radiosidad se ha empleado en diveros ttulos de gran xito comercial. Actualmente incluso existen motores grcos que calculan soluciones de radiosidad en tiempo real. Veamos a continuacin un ejemplo de utilizacin de Radiosidad en Blender. Como hemos indicado anteriormente, el modelo de Radiosidad calcula la interaccin de iluminacin entre supercies. As, la iluminacin de la escena vendr dada por las reas de luz de las supercies superiores (planos) de la habitacin. De esta forma, necesitaremos crear planos a los que asignaremos un material que emita luz. La escena de ejemplo (ver Figura 9.17) cuenta con planos con estas propiedades denidas.

Figura 9.17: Escena de ejemplo para el clculo de la Radiosidad.

[200]

CAPTULO 9. ILUMINACIN

2 1 3 4

Figura 9.16: Esquema de la matriz de radiosidad. En cada posicin de la matriz se calcula el Factor de Forma. La diagonal principal de la matriz no se calcula.

Necesario Blender 2.49b. Aunque la radiosidad es un mtodo muy empleado en videojuegos, fue eliminado de la implementacin de Blender a partir de la versin 2.5. Probablemente vuelva a incorporarse en futuras versiones, pero de momento es necesario utilizar versiones anteriores del programa. La ltima versin que la incorpor (Blender 2.49b) puede ser descargada de la pgina ocial http://download.blender.org/release/.

Es muy importante la direccin del vector normal ya que Blender calcular la interaccin de la luz en ese sentido. Por tanto, tendremos que asegurarnos que el vector normal de cada foco apunta hacia el suelo , tal y como muestra la Figura 9.18. Para comprobar que es as, seleccionamos cada emisor de luz, en modo de edicin de vrtices activamos el botn Draw Normals de la pestaa Mesh Tools More. Podemos ajustar el tamao de representacin del vector normal en Nsize. En caso de que la normal est invertida, podemos ajustarla pulsando W Flip Normals. Los elementos que emiten luz tendrn el campo Emit del material con un valor mayor que 0. Los emisores de este ejemplo tienen un valor de emisin de 0.4. dentro de los botones de Accedemos al men de radiosidad . Seleccionamos todas las mallas que forman nuestra sombreado escena A y pinchamos en el botn Collect Meshes (ver Figura 9.19). La escena aparecer con colores slidos.
Figura 9.18: Focos del techo con el vector normal correctamente denido.

9.7. Radiosidad

[201]

Figura 9.19: Opciones generales de Radiosidad (Paneles Radio Render, Radio Tool y Calculation.

. De esta forma comienza el proceso Hecho esto, pinchamos en Go de clculo de la solucin de radiosidad. Podemos parar el proceso en cualquier momento pulsando Escape , quedndonos con la aproximacin que se ha conseguido hasta ese instante. Si no estamos satisfechos con la solucin de Radiosidad calculada, podemos eliminarla pinchando en Free Radio Data. En la Figura 9.19 se muestran algunas opciones relativas al clculo de la solucin de radiosidad. El tamao de los Parches (PaMax - PaMin ) determina el detalle nal (cuanto ms pequeo sea, ms detallado ser el resultado nal), pero incrementamos el tiempo de clculo. De forma similar ocurre con el tamao de los Elementos2 (ElMax - ElMin ). En Max Iterations indicamos el nmero de pasadas que Blender har en el bucle de Radiosidad. Un valor 0 indica que haga las que estime necesarias para minimizar el error (lo que es conveniente si queremos generar la malla de radiosidad nal). MaxEl indica el nmero mximo de elementos para la escena. Hemires es el tamao del hemicubo para el clculo del factor de forma. Una vez terminado el proceso de clculo (podemos pararlo cuan ), podemos aadir la nueva malla do la calidad sea aceptable con Esc calculada reemplazando las creadas anteriormente (Replace Meshes) o aadirla como nueva a la escena (Add new Meshes). Elegiremos esta segunda opcin, para aplicar posteriormente el resultado a la malla en baja poligonalizacin. Antes de deseleccionar la malla con la informacin de radiosidad calculada, la moveremos a otra capa (mediante ) para tener los objetos mejor organizados. Hecho esto, pola tecla M demos liberar la memoria ocupada por estos datos pinchando en Free Radio Data.
Figura 9.20: Resultado de la malla de radiosidad.

El resultado de la malla de radiosidad se muestra en la Figura 9.20. Como se puede comprobar, es una malla extremadamente densa, que no es directamente utilizable en aplicaciones de tiempo real. Vamos a utilizar el Baking de Blender para utilizar esta informacin de texturas sobre la escena original en baja poligonalizacin.
2 En Blender, cada Parche est formado por un conjunto de Elementos, que describen supercies de intercambio de mayor nivel de detalle.

[202]

CAPTULO 9. ILUMINACIN

Figura 9.21: Resultado de aplicacin del mapa de radiosidad al modelo en baja resolucin.

Por simplicidad, uniremos todos los objetos de la escena original en una nica malla (seleccionndolos todos A y pulsando Control J Join Selected Meshes). A continuacin, desplegaremos el objeto empleando el modo de despliegue de Light Map, y crearemos una nueva imagen que recibir el resultado del render Baking. seleccionamos primero la malla de radiosidad, y despus con Ahora Shift pulsado seleccionamos la malla en baja resolucin. Pinchamos en el botn Selected to Active de la pestaa Bake, activamos Full Render y pinchamos en el botn Bake . Con esto debemos haber asignado el mapa de iluminacin de la malla de radiosidad al objeto en baja poligonalizacin (ver Figura 9.21).

Captulo

Exportacin y Uso de Datos de Intercambio


Carlos Gonzlez Morcillo

10

asta ahora hemos empleado exportadores genricos de contenido de animacin, mallas poligonales y denicin de texturas. Estas herramientas facilitan enormemente la tarea de construccin de contenido genrico para nuestros videojuegos. En este captulo veremos cmo crear nuestros propios scripts de exportacin y su posterior utilizacin en una sencilla demo de ejemplo.

10.1.

Introduccin

En captulos anteriores hemos utilizado exportadores genricos de contenido para su posterior importacin. En multitud de ocasiones en necesario desarrollar herramientas de exportacin de elementos desde las herramientas de diseo 3D a formatos de intercambio. La comunidad de Ogre ha desarrollado algunos exportadores de geometra y animaciones para las principales suites de animacin y modelado 3D. Sin embargo, estos elementos almacenan su posicin relativa a su sistema de coordenadas, y no tienen en cuenta otros elementos (como cmaras, fuentes de luz, etc...).
Figura 10.1: El Wumpus ser el personaje principal del videojuego demostrador de este captulo NoEscape Demo.

En esta seccin utilizaremos las clases denidas en el Captulo 6 del Mdulo 1 para desarrollar un potencial juego llamado NoEscapeDemo. Estas clases importan contenido denido en formato XML, que fue descrito en dicho captulo. 203

[204]

CAPTULO 10. EXPORTACIN Y USO DE DATOS DE INTERCAMBIO

A continuacin enumeraremos las caractersticas esenciales que debe soportar el exportador a desarrollar: Mltiples nodos. El mapa del escenario (ver Figura 10.4) describe un grafo. Utilizaremos un objeto de tipo malla poligonal para modelarlo en Blender. Cada vrtice de la malla representar un nodo del grafo. Los nodos del grafo podrn ser de tres tipos: Nodo productor de Wumpus (tipo spawn), Nodo destructor de Wumpus (tipo drain) o un Nodo genrico del grafo (que servir para modelar las intersecciones donde el Wumpus puede cambiar de direccin). Mltiples aristas. Cada nodo del grafo estar conectado por uno o ms nodos, deniendo mltiples aristas. Cada arista conectar una pareja de nodos. En este grafo, las aristas no tienen asociada ninguna direccin. Mltiples cmaras animadas. El exportador almacenar igualmente las animaciones denidas en las cmaras de la escena. En el caso de querer almacenar cmaras estticas, se exportar nicamente un fotograma de la animacin. Para cada frame de la animacin de cada cmara, el exportador almacenar la posicin y rotacin (mediante un cuaternio ) de la cmara en el XML.

Existen algunas especicaciones en XML genricas para la denicin de escenas (como el formato .scene ) en Ogre, que est soportado por unas clases adicionales disponibles en el Wiki (http://www.ogre3d.org/tikiwiki/DotScene) del framework. Aunque este formato dene gran cantidad de elementos de una escena, resulta crtico conocer los mecanismos de exportacin para desarrollar los scripts especcos que necesitemos en cada proyecto.

Figura 10.2: Como se estudi en el Captulo 4, es necesario denir el centro de los objetos especicando adecuadamente su centro. En el caso del Wumpus, el centro se dene en el centro de la base, escalndolo adems al tamao existente entre las paredes del escenario.

El mapa del escenario y los personajes principales se exportarn atendiendo a las indicaciones estudiadas en el Captulo 4 (ver Figura 10.2). La exportacin del XML se realizar empleando el script descrito a continuacin. Blender dene una API de programacin muy completa en Python. Python es un lenguaje ampliamente utilizado por su facilidad, versatilidad y potencia 1 . Python es un lenguaje de muy alto nivel, interpretado (compilado a un cdigo intermedio), orientado a objetos y libre bajo licencia GPL. Aunque en esta seccin nos centraremos en su uso directo como lenguaje de acceso a la API de Blender, en el mdulo 3 estudiaremos cmo utilizar Python como lenguaje de script dentro de nuestra apliacin en C++.
1 Resulta especialmente interesante la comparativa emprica de Python con otros lenguajes de programacin disponible en http://www.ipd.uka.de/~{}prechelt/ \discretionary{-}{}{}Biblio/jccpprtTR.pdf

10.1. Introduccin

[205]

Quin usa Python? Existen multitud de ttulos comerciales y videojuegos de xito que han utilizado Python como lenguaje para su desarrollo. Por ejemplo, Civilization 4 utiliza python para la gestin de mltiples tareas, Vampire: The Masquerade lo emplea para la descripcin de Mods, o Battleeld 2 (de Digital Illusions) para la denicin de todos los complementos del juego.

La versin de Blender 2.65 utiliza Python 3.3, por lo que ser necesaria su instalacin para ejecutar los scripts desarrollados. En una ventana de tipo Text Editor podemos editar los scripts. Para su ejecucin, bastar con situar el puntero del ratn dentro de la ventana de texto y pulsar Alt P . Aunque la versin 2.65 de Blender permite aadir nuevas propiedades a los objetos de la escena, por mantener la compatibilidad con versiones anteriores lo haremos codicndolo como parte del nombre. En la pestaa Object, es posible especicar el nombre del objeto, como se muestra en la Figura 10.3. En nuestro ejemplo, se ha utilizado el siguiente convenio de nombrado:
Figura 10.3: Especicacin del nombre del objeto en la pestaa Object.

Cmaras. Las cmaras codican en el nombre (separadas por guin bajo), como primer parmetro el identicador de la misma (un ndice nico), y como segundo parmetro el nmero de frames asociado a su animacin. De este modo, la cmara llamada GameCamera_1_350 indica que es la primera cmara (que ser la utilizada en el estado de Juego ), y que tiene una animacin denida de 350 frames. Empty. Como no es posible asignar tipos a los vrtices de la malla poligonal con la que se denir el grafo, se han aadido objetos de tipo Empty que servirn para asociar los generadores (spawn ) y destructores (drain ) de Wumpus. Estos objetos Empty tendrn como nombre el literal spawn o drain y a continuacin un nmero del 1 al 9. A continuacin se muestra el cdigo fuente del script de exportatres constantes que pueden ser modicin. Las lneas 8-10 denen cadas en su ejecucin: 8 el nombre del chero XML que se exportar, 9 el nombre del objeto donde se dene el grafo (como hemos indicado anteriormente ser una malla poligonal), y 10 un valor que utilizaremos como distancia mxima de separacin entre un vrtice del grafo y cada Empty de la escena (para considerar que estn asociados).

[206]

CAPTULO 10. EXPORTACIN Y USO DE DATOS DE INTERCAMBIO

Listado 10.1: Script de exportacin de NoEscapeDemo.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

# Exportador NoEscape 1.1 (Adaptado a Blender 2.65) import bpy, os, sys import mathutils from math import * from bpy import * FILENAME = "output.xml" GRAPHNAME = "Graph" EPSILON = 0.01 # Archivo XML de salida # Nombre del objeto Mesh del grafo # Valor de distancia Epsilon

# --- isclose -------------------------------------------------# Decide si un empty coincide con un vertice del grafo # -------------------------------------------------------------def isclose(empty, coord): xo, yo, zo = coord xd, yd, zd = empty.location v = mathutils.Vector((xo-xd, yo-yd, zo-zd)) if (v.length < EPSILON): return True else: return False # --- gettype -------------------------------------------------# Devuelve una cadena con el tipo del nodo del grafo # -------------------------------------------------------------def gettype (dv, key): obs = [ob for ob in bpy.data.objects if ob.type == EMPTY] for empty in obs: empName = empty.name if ((empName.find("spawn") != -1) or (empName.find("drain") != -1)): if (isclose(empty, dv[key])): return type ="+ empName[:-1] +" return type="" ID1 ID2 ID3 ID4 = = = = *2 *4 *6 *8 # Identadores para el xml # Solo con proposito de obtener un xml "bonito"

graph = bpy.data.objects[GRAPHNAME] dv = {} # Diccionario de vertices for vertex in graph.data.vertices: dv[vertex.index+1] = vertex.co de = {} # Diccionario de aristas for edge in graph.data.edges: # Diccionario de aristas de[edge.index+1] = (edge.vertices[0], edge.vertices[1]) file = open(FILENAME, "w") std=sys.stdout sys.stdout=file print ("<?xml version=1.0 encoding=UTF-8?>\n") print ("<data>\n") # --------- Exportacion del grafo --------------------print ("<graph>") for key in dv.keys(): print (ID1 + <vertex index=" + str(key) + " + gettype(dv,key) +>) x,y,z = dv[key]

10.1. Introduccin

[207]

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

print (ID2 + <x> %f</x> <y> %f</y> <z> %f</z> % (x,y,z)) print (ID1 + </vertex>) for key in de.keys(): print (ID1 + <edge>) v1,v2 = de[key] print (ID2 + <vertex> %i</vertex> <vertex> %i</vertex> % (v1,v2)) print (ID1 + </edge>) print ("</graph>\n") # --------- Exportacion de la camara ------------------obs = [ob for ob in bpy.data.objects if ob.type == CAMERA] for camera in obs: camId = camera.name camName = camId.split("_")[0] camIndex = int(camId.split("_")[1]) camFrames = int (camId.split("_")[2]) print (<camera index=" %i" fps=" %i"> % (camIndex, bpy.data.scenes[Scene].render.fps)) print (ID1 + <path>) for i in range (camFrames): cFrame = bpy.data.scenes[Scene].frame_current bpy.data.scenes[Scene].frame_set(cFrame+1) x,y,z = camera.matrix_world.translation qx,qy,qz,qw = camera.matrix_world.to_quaternion() print (ID2 + <frame index=" %i"> % (i+1)) print (ID3 + <position>) print (ID4 + <x> %f</x> <y> %f</y> <z> %f</z> % (x,y,z)) print (ID3 + </position>) print (ID3 + <rotation>) print (ID4 + <x> %f</x> <y> %f</y> <z> %f</z> <w> %f</w> % (qx,qy,qz,qw)) print (ID3 + </rotation>) print (ID2 + </frame>) print (ID1 + </path>) print (</camera>) print ("</data>") file.close() sys.stdout = std

El proceso de exportacin del XML se realiza directamente al vuelo, sin emplear las facilidades (como el DOM o SAX (Simple API for XML) de Python). La sencillez del XML descrito, as como la independencia de una instalacin completa de Python hace que sta sea la alternativa implementada en otros exportadores (como el exportador de Ogre, o el de Collada). En las lneas 44,48 se crean dos diccionarios donde se guardarn las listas relativas a las coordenadas de los vrtices del grafo y las aristas. Blender numera los vrtices y aristas asociados a una malla poligonal comenzando en 0. En la descripcin del XML indicamos por convenio que todos los ndices comenzaran en 1, por lo que es necesario sumar 1 a los ndices que nos devuelve Blender. La malla asociada al objeto de nombre indicado en GRAPHNAME se obtiene mediante la llamada a bpy.data.objects (lnea 42 ). La lnea 56 simplemente imprime la cabecera del XML.

[208]

CAPTULO 10. EXPORTACIN Y USO DE DATOS DE INTERCAMBIO

spawn4

spawn1 drain2

spawn2 drain1

spawn3

Figura 10.4: Denicin del grafo asociado al juego NoEscapeDemo en Blender. En la imagen de la izquierda se han destacado la posicin de los Emptys auxiliares para describir el tipo especial de algunos nodos (vrtices) del grafo. La imagen de la derecha muestra las dos cmaras de la escena y la ruta descrita para la cmara principal del juego.

En el bloque descrito por 59-73 se generan las entradas relativas a la denicin del grafo, empleando los diccionarios de vrtices dv y de aristas de creados anteriormente. En la denicin del XML (ver Captulo 6 del Mdulo 1), un nodo puede tener asociado un tipo. Para obtener el tipo de cada nodo utilizamos una funcin auxiliar llamada gettype (denida en las lneas ). 27-35 En gettype se calcula la cadena correspondiente al tipo del nodo del grafo. Como hemos indicado anteriormente, el tipo del nodo se calcula segn la distancia a los objetos Empty de la escena. Si el vrtice est muy cerca de un Empty con subcadena drain o spawn en su nombre, le asignaremos ese tipo al vrtice del grafo. En otro caso, el nodo del grafo ser genrico. De este modo, en la lnea 28 se obtiene en obs la lista de todos los objetos de tipo Empty de la escena. Para cada uno de estos objetos, si el nombre contiene alguna de las subcadenas indicadas y est sucientemente cerca (empleando la funcin auxiliar 34 ) para el nodo pasado isclose ), entonces devolvemos ese tipo (lnea como argumento de la funcin (lnea 27 ). En otro caso, devolvemos la cadena vaca para tipo (que indica que no es un nodo especial del grafo) en la lnea 35 .

Muy Cerca!
Se emplea un valor Epsilon para calcular si un Empty ocupa la posicin de un nodo del grafo porque las comparaciones de igualdad con valores de punto otante pueden dar resultados incorrectos debido a la precisin.

10.1. Introduccin

[209] La funcin auxiliar isclose (denida en las lneas 15-22 devolver True si el empty est a una distancia menor que respecto del nodo del grafo. En otro caso, devolver False. Para realizar esta comparacin, simplemente creamos un vector restando las coordenadas del vrtice con la posicin Empty y utilizamos directamente el atributo de del longitud (lnea 19 ) de la clase Vector de la biblioteca mathutils.

La biblioteca Mathutils de Blender contiene una gran cantidad de funciones para trabajar con Matrices, Vectores, Cuaternios y un largo etctera.

Trayectorias genricas
Aunque en este ejemplo exportaremos trayectorias sencillas, el exportar la posicin de la cmara en cada frame nos permite tener un control absoluto sobre la pose en cada instante. En la implementacin en OGRE tendremos que utilizar algn mecanismo de interpolacin entre cada pose clave.

La segunda parte del cdigo (denido en las lneas 76-100 ) se encarga de exportar las animaciones asociadas a las cmaras. Segn el convenio explicado anteriormente, el propio nombre de la cmara codica el ndice de la cmara (verlnea ) y el nmero de frames que 80 ). En el caso de este ejemplo se han contiene su animacin (ver lnea 81 denido dos cmaras (ver Figura 10.4). La cmara del men inicial es esttica, por lo que dene en la parte relativa a los frames un valor de 1 (no hay animacin). La cmara del juego describir rotaciones siguiendo una trayectoria circular. El nmero de frame se modica directamente en el atributo fra ). Para cada frame se me_current del la escena actual (ver lnea 86 exporta la posicin de la cmara (obtenida en la ltima columna de la matriz de transformacin del objeto, en la lnea 88 ), y el cuaternio de ). La Figura 10.5 rotacin (mediante una conversin de la matriz en 89 muestra un fragmento del XML exportado relativo a la escena base del ejemplo. Esta exportacin puede realizarse ejecutando el chero .py desde lnea de rdenes, llamando a Blender con el parmetro -P <script.py> (siendo script.py el nombre del script de exportacin).

Figura 10.5: Fragmento del resultado de la exportacin del XML del ejemplo.

Captulo

Animacin
Carlos Gonzlez Morcillo

11

E
Animacin?
El trmino animacin proviene del griego Anemos, que es la base de la palabra latina Animus que signica Dar aliento, dar vida.

n este captulo estudiaremos los fundamentos de la animacin por computador, analizando los diversos mtodos y tcnicas de construccin, realizando ejemplos de composicin bsicos con Ogre. Se estudiar el concepto de Animation State, exportando animaciones denidas previamente en Blender.

11.1.

Introduccin

En su forma ms simple, la animacin por computador consiste en generar un conjunto de imgenes que, mostradas consecutivamente, producen sensacin de movimiento. Debido al fenmeno de la Persistencia de la Visin, descubierto en 1824 por Peter Mark Roget, el ojo humano retiene las imgenes una vez vistas unos 40 ms. Siempre que mostremos imgenes a una frecuencia mayor, tendremos sensacin de movimiento continuo1 . Cada una de las imgenes que forman la secuencia animada recibe el nombre de frame2 . La animacin por computador cuenta con una serie de ventajas que no se dan en animacin tradicional; por ejemplo, la animacin puede producirse directamente desde modelos o conjuntos de ecuaciones que especican el comportamiento dinmico de los objetos a animar.

1 A frecuencias menores de 20hz se percibir la discretizacin del movimiento, en un efecto de tipo estroboscpico. 2 tambin, aunque menos extendido en el mbito de la animacin por computador se utiliza el trmino cuadro o fotograma

211

[212] Cuando hablamos de tcnicas de animacin por computador nos referimos a sistemas de control del movimiento. Existen multitud de elementos que hacen el problema del control del movimiento complejo, y de igual forma, existen varias aproximaciones a la resolucin de estas dicultades. La disparidad de aproximaciones y la falta de unidad en los convenios de nombrado, hacen que la categorizacin de las tcnicas de animacin por computador sea difcil. Una propuesta de clasicacin de se realiza segn el nivel de abstraccin. As, se distingue entre sistemas de animacin de alto nivel, que permiten al animador especicar el movimiento en trminos generales (denen el comportamiento en trminos de eventos y relaciones), mientras que los sistemas de bajo nivel requieren que el animador indique los parmetros de movimiento individualmente. Si se desean animar objetos complejos (como por ejemplo la gura humana), es necesario, al menos, un control de jerarqua para reducir el nmero de parmetros que el animador debe especicar. Incluso en personajes digitales sencillos, como el mostrado en la gura 11.1 el esqueleto interno necesario tiene un grado de complejidad considerable. En concreto, este esqueleto tiene asociados 40 huesos con diversos modicadores aplicados individualmente. Al igual que en los lenguajes de programacin de alto nivel, las construcciones deben nalmente compilarse a instrucciones de bajo nivel. Esto implica que cualquier descripcin paramtrica de alto nivel debe transformarse en descripciones de salida de bajo nivel. Este proceso proceso nalizar cuando dispongamos de todos los datos necesarios para todos los frames de la animacin. De esta forma, lo que se busca en el mbito de la animacin es ir subiendo de nivel, obteniendo sistemas de mayor nivel de abstraccin. Las primeras investigaciones comenzaron estudiando las tcnicas de interpolacin de movimiento entre frames clave, utilizando Splines. Mediante este tipo de curvas, los objetos podan moverse de forma suave a lo largo de un camino en el espacio. Desde este punto, han aparecido multitud de tcnicas de animacin de medio nivel (como la animacin basada en scripts, animacin procedural, animacin jerrquica basada en cinemtica directa e inversa y los estudios de sntesis animacin automtica). A continuacin estudiaremos los principales niveles de abstraccin relativos a la denicin de animacin por computador.

CAPTULO 11. ANIMACIN

Figura 11.1: Uno de los personajes principales de YoFrankie, proyecto de videojuego libre de la Blender Foundation.

Tcnicas bsicas

11.1.1.

Animacin Bsica

Lo fundamental en este nivel es cmo parametrizar los caminos bsicos de movimiento en el espacio. Hay diversas alternativas (no excluyentes) como los sistemas de Script, sistemas de Frame Clave y animacin dirigida por Splines. Sistemas de Script. Histricamente, los primeros sistemas de control del movimiento fueron los sistemas basados en scripts. Este tipo de sistemas requieren que el usuario escriba un guin

Estas tcnicas forman la base de los mtodos de animacin ms avanzados, por lo que es imprescindible conocer su funcionamiento para emplear correctamente los mtodos de animacin basados en cinemtica directa o inversa que estudiaremos ms adelante.

11.1. Introduccin

[213] en un lenguaje especco para animacin y adems, presuponen una habilidad por parte del animador de expresar la animacin con el lenguaje de script. Este tipo de aproximacin producen animaciones de baja calidad, dada la complejidad en la especicacin de las acciones. Sistema de Frame Clave. Los sistemas de Frame Clave toman su nombre de la jerarqua de produccin tradicional de Walt Disney. En estos sistemas, los animadores ms experimentados diseaban los fotogramas principales de cada secuencia. La produccin se completaba con artistas jvenes que aadan los frames intermedios3 . Dependiendo del tipo de mtodo que se utilice para el clculo de los fotogramas intermedios estaremos ante una tcnica de interpolacin u otra. En general, suelen emplearse curvas de interpolacin del tipo Spline, que dependiendo de sus propiedades de continuidad y el tipo de clculo de los ajustes de tangente obtendremos diferentes resultados. En el ejemplo de la Figura 11.2, se han aadido claves en los frames 1 y 10 con respecto a la posicin (localizacin) y rotacin en el eje Z del objeto. El ordenador calcula automticamente la posicin y rotacin de las posiciones intermedias. La gura muestra las posiciones intermedias calculadas para los frames 4 y 7 de la animacin. Animacin Procedural. En esta categora, el control sobre el movimiento se realiza empleando procedimientos que denen explcitamente el movimiento como funcin del tiempo. La generacin de la animacin se realiza mediante descripciones fsicas, como por ejemplo en visualizaciones cientcas, simulaciones de uidos, tejidos, etc... Estas tcnicas de animacin procedural sern igualmente estudiadas a continuacin este mdulo curso. La simulacin dinmica, basada en descripciones matemticas y fsicas suele emplearse en animacin de acciones secundarias. Es habitual contar con animaciones almacenadas a nivel de vrtice simulando comportamiento fsico en videojuegos. Sera el equivalente al Baking de animaciones complejas precalculadas. Con base en estas tcnicas fundamentales se denen los mtodos de animacin de alto nivel descritos a continuacin.

11.1.2. Animacin de Alto Nivel


Dentro de este grupo incluimos la animacin mediante tcnicas cinemticas jerrquicas (como cinemtica directa o inversa de guras articuladas), las modernas aproximaciones de sntesis automtica de animacin o los sistemas de captura del movimiento. Estas tcnicas especcas sern estudiadas en detalle en el Mdulo 3 del curso, por lo que nicamente realizaremos aqu una pequea descripcin introductoria.
3 Realizando

la tcnica llamada n between"

[214]

CAPTULO 11. ANIMACIN

Posicin Clave Frame 1!

Posiciones "nter#ola$as Frames 4 % 7!

Posicin Clave Frame 10! Rotacin Z

Posicin X Posicin Y Posicin Z Frame

10

Figura 11.2: Ejemplo de uso de Frames Clave y Splines asociadas a la interpolacin realizada.

Cinemtica Directa. Empleando cinemtica directa, el movimiento asociado a las articulaciones debe ser especicado explcitamente por el animador. En el ejemplo de la Figura 11.3, la animacin del efector nal vendra determinada indirectamente por la composicin de transformaciones sobre la base, el hombro, el codo y la mueca. Esto es, una estructura arbrea descendente. Esto es, dado el conjunto de rotaciones , obtenemos la posicin del efector nal X como X = f (). Cinemtica Inversa. El animador dene nicamente la posicin del efector nal. Mediante cinemtica inversa se calcula la posicin y orientacin de todas las articulaciones de la jerarqua que consiguen esa posicin particular del efector nal mediante = f (X ). Una vez realizada esta introduccin general a las tcnicas de animacin por computador, estudiaremos en la siguiente seccin los tipos de animacin y las caractersticas generales de cada uno de ellos en el motor grco Ogre.

11.2. Animacin en Ogre

[215]

Hombro

Codo

Posicin del Efector

Base

Mueca

Posicin del Efector

Figura 11.3: Ejemplo de uso de Frames Clave y Splines asociadas a la interpolacin realizada.

11.2.

Animacin en Ogre

Ogre gestiona la posicin de los elementos de la escena en cada frame. Esto signica que la escena es redibujada en cada frame. Ogre no mantiene ningn tipo de estructuras de datos con el estado anterior de los objetos de la escena. La animacin se gestiona con dos aproximaciones; una basada en frames clave y otra mediante una variable (habitualmente se emplear el tiempo) utilizada como controlador. El modo ms sencillo de crear animaciones es mediante el uso de una herramienta externa y reproducirlas posteriormente.
AnimationState
Cada animacin de un AnimationState tiene asociado un nombre nico mediante el que puede ser accedido.

Como hemos sealado anteriormente, de modo general Ogre soporta dos modos de animacin: basada en Frames Clave (Keyframe Animation ) y basada en Controladores.

11.2.1. Animacin Keyframe


Ogre utiliza el trmino pista Track para referirse a un conjunto de datos almacenados en funcin del tiempo. Cada muestra realizada en un determinado instante de tiempo es un Keyframe. Dependiendo del tipo de Keyframes y el tipo de pista, se denen diferentes tipos de animaciones.

[216] Las animaciones asociadas a una Entidad se representan en un AnimationState. Este objeto tiene una serie de propiedades que pueden ser consultadas: Nombre. Mediante la llamada a getAnimationName se puede obtener el nombre de la animacin que est siendo utilizada por el AnimationState. Activa. Es posible activar y consultar el estado de una animacin mediante las llamadas a getEnabled y setEnabled. Longitud. Obtiene en punto otante el nmero de segundos de la animacin, mediante la llamada a getLength. Posicin. Es posible obtener y establecer el punto de reproduccin actual de la animacin mediante llamadas a getTimePosition y setTimePosition. El tiempo se establece en punto otante en segundos. Bucle. La animacin puede reproducirse en modo bucle (cuando llega al nal continua reproduciendo el primer frame). Las llamadas a mtodos son getLoop y setLoop. Peso. Este parmetro controla la mezcla de animaciones, que ser descrita en la seccin 11.4. El estado de la animacin requiere que se le especique el tiempo transcurrido desde la ltima vez que se actualiz.

CAPTULO 11. ANIMACIN

Tiempo
El tiempo transcurrido desde la ltima actualizacin puede especicarse con un valor o negativo (en el caso de querer retroceder en la animacin). Este valor de tiempo simplemente se aade a la posicin de reproduccin de la animacin.

11.2.2.

Controladores

La animacin basada en frames clave permite animar mallas poligionales. Mediante el uso de controladores se posicionan los nodos, deniendo una funcin. El controlador permite modicar las propiedades de los nodos empleando un valor que se calcula en tiempo de ejecucin.

11.3.

Exportacin desde Blender

En esta seccin estudiaremos la exportacin de animaciones de cuerpos rgidos. Aunque para almacenar los AnimationState es necesario asociar un esqueleto al objeto que se desea animar, no entraremos en detalles para la animacin de jerarquas compuestas (personajes). Desde el punto de vista de la exportacin en Ogre es similar.

11.3. Exportacin desde Blender

[217]

Figura 11.4: Principales ventanas de Blender empleadas en la animacin de objetos. En el centro se encuentran las ventanas del NLA Editor y del Dope Sheet, que se utilizarn para denir acciones que sern exportadas empleando el script de Exportacin a Ogre.

Para exportar diferentes animaciones, ser conveniente congurar el interfaz de Blender como se muestra en la Figura 11.4. A continuacin describiremos brevemente las dos ventanas principales que utilizaremos en la exportacin de animaciones: permite la edicin de animacin no lineal en El NLA Editor Blender. Mediante esta tcnica de composicin, la animacin nal se crea mediante fragmentos de animacin especcos (cada uno est especializado en un determinado movimiento) llamados acciones. Estas acciones pueden duplicarse, repetirse, acelerarse o decelerarse en el tiempo para formar la animacin nal.
Acciones
Las accciones permiten trabajar a un nivel de abstraccin mayor que empleando curvas IPO (InterPOlation curve). Es conveniente emplear esta aproximacin siempre que denamos animaciones complejas.

(en versiones anteriores de Blender se denomiEl Dope Sheet naba Action Editor ) permite el control de mltiples acciones simultneamente, agrupndolas por tipo. Este editor est a un nivel de abstraccin medio, entre las curvas IPO y el NLA Editor descrito anteriormente. Esta ventana permite trabajar muy rpidamente con los datos de la animacin, desplazando la posicin de los frames clave (y modicando as el Timing de cada accin). En el rea de trabajo principal del Dope Sheet se muestran los canales de animacin asociados a cada objeto. Cada diamante de las barras asociadas a cada canal se corresponden con un keyframe y pueden ser desplazadas individualmente o en grupos para modicar la temporizacin de cada animacin. Las acciones aparecern en el interfaz del exportador de Ogre, siempre que hayan sido correctamente creadas y estn asociadas a un hueso de un esqueleto. En la Figura 11.4 se han denido dos acciones llamadas Saltar y Rotar (la accin Rotar est seleccionada y aparece resaltada en la gura). A continuacin estudiaremos el proceso de exportacin de animaciones.

[218] Como se ha comentado anteriormente, las animaciones deben exportarse empleando animacin basada en esqueletos. En el caso ms sencillo de animaciones de cuerpo rgido, bastar con crear un esqueleto de un nico hueso y emparentarlo con el objeto que queremos animar. Aadimos un esqueleto con un nico hueso al objeto que quere mos aadir mediante Shift A Add/Armature/Single Bone. Ajustamos el extremo superior del hueso para que tenga un tamao similar al objeto a animar (como se muestra en la Figura 11.5). A continuacin crearemos una relacin de parentesco entre el objeto y el hueso del esqueleto, de forma que el objeto sea hijo de el esqueleto. . Con el hueso Este parentesco debe denirse en modo Pose del esqueleto seleccionado, elegiremos el modo Pose en la cabecera de la ventana 3D (o bien empleando el atajo de teclado Control TAB ). El hueso deber representarse en color azul en el interfaz de Blender. Con el hueso en modo pose, ahora seleccionamos primero al caballo, y a continuacin con Shift pulsado seleccionamos el hueso (se deber , eligiendo Set Parent to elegir en color azul), y pulsamos Control P >Bone. Si ahora desplazamos el hueso del esqueleto en modo pose, el objeto deber seguirle. Antes de crear las animaciones, debemos aadir un Modicador de objeto sobre la malla poligional. Con el objeto Horse seleccionado, en el panel Object Modiers aadimos un modicador de tipo Armature. Este modicador se utiliza para animar las poses de personajes y objetos asociados a esqueletos. Especicando el esqueleto que utilizaremos con cada objeto podremos incluso deformar los vrtices del propio modelo. Como se muestra en la Figura 11.6, en el campo Object especicaremos el nombre del esqueleto que utilizaremos con el modicador (Armature en este caso). En el mtodo de Bind to indicamos qu elementos se asociarn al esqueleto. Si queremos que los vrtices del modelo se deformen en funcin de los huesos del esqueleto, activaremos Vertex Groups (en este ejemplo deber estar desactivado). Mediante Bone Envelopes podemos indicar a Blender que utilice los lmites de cada hueso para denir la deformacin que se aplicar a cada hueso. A continuacin creamos un par de animaciones asociadas a este hueso. Recordemos que debemos trabajar en modo Pose , por lo que siempre el hueso debe estar seleccionado en color azul en el interfaz de Blender. Comenzaremos deniendo una accin que se llamar Saltar . Aadiremos los frames clave de la animacin (en este caso, hemos denido frames clave de LocRot en 1, 21 y 35). Tras realizar esta operacin, las ventanas de DopeSheet y NLA Editor mostrarn un aspecto como el de la Figura 11.7. La ventana Dopermite modicar fcilmente las posiciones de los frames peSheet clave asociados al hueso. Pinchando y desplazando los rombos asociados a cada clave, podemos modicar el timing de la animacin. En la ventana NLA podemos crear una accin (Action Strip), pinchando sobre el icono del copo de nieve . Tras esta operacin, se habr creado una accin denida mediante una barra amarilla.

CAPTULO 11. ANIMACIN

Figura 11.5: Ajuste del tamao del hueso para que sea similar al objeto a animar.

Figura 11.6: Opciones del Modicador Armature.

Figura 11.7: Ventanas de DopeSheet y NLA Editor.

11.3. Exportacin desde Blender

[219]

Es posible indicar el nombre de la accin en el campo Active Strip, accesible pulsando la tecla N . Aparecer un nuevo subpanel, como se muestra en la Figura 11.8, en la zona derecha de la ventana, donde se podrn congurar los parmetros asociados a la accin (nombre, frames, mtodo de mezclado con otras acciones, etc...).
Figura 11.8: Especicacin del nombre de la accin en el Panel de Propiedades.

Siguiendo el mismo procedimiento denimos otra accin llamada Rotar . Para que no tengan inuencia las acciones previamente creadas, y no molesten a la hora de denir nuevos comportamientos, es situado a la derecha posible ocultarlas pinchando sobre el botn del nombre de la accin (ver Figura 11.8).

Es posible exportar diferentes animaciones asociadas a un objeto. El rango de denicin de los frames puede ser diferente, como en el ejemplo estudiado en esta seccin.

Mediante el atajo de teclado Alt A podemos reproducir la animacin relativa a la accin que tenemos seleccionada. Resulta muy cpara denir el intervalo modo emplear una ventana de tipo Timeline sobre el que se crearn las animaciones. A la hora de exportar las animaciones, procedemos como vimos en el Captulo 4. En File/ Export/ Ogre3D, accederemos al exportador de Blender a Ogre3D. Es interesante activar las siguientes opciones de exportacin: Armature Animation. Crea el archivo con extensin .skeleton, que contiene la denicin jerrquica del conjunto de huesos, junto con su posicin y orientacin. Esta jerarqua incluye la inuencia que tiene cada hueso sobre los vrtices del modelo poligonal. Independent Animations. Exporta cada accin de forma independiente, de modo que no tienen inuencia combinada.
Huesos y vrtices
En este captulo trabajaremos con huesos que tienen una inuencia total sobre el objeto (es decir, inuencia de 1.0 sobre todos los vrtices del modelo).

El uso de las animaciones exportadas en Ogre es relativamente sencillo. En siguiente cdigo muestra un ejemplo de aplicacin de las ani maciones previamente exportadas. Cuando se pulsa la tecla A o Z se reproduce la animacin Saltar o Rotar hasta que naliza. En la lnea 18 se actualiza el tiempo transcurrido desde la ltima actualizacin. Cuando se pulsa alguna de las teclas anteriores, la animacin seleccionada se reproduce desde el principio (lnea 10 ). En el ejemplo siguiente puede ocurrir que se interrumpa una animacin por la seleccin de otra antes de nalizar el estado. Esto poda dar lugar a posiciones nales incorrectas. Por ejemplo, si durante la , el objeto se queejecucin de la accin Saltar se pulsaba la tecla Z daba otando en el aire ejecutando la segunda animacin.

[220]

CAPTULO 11. ANIMACIN

Listado 11.1: Fragmento de MyFrameListener.cpp.


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

if (_keyboard->isKeyDown(OIS::KC_A) || _keyboard->isKeyDown(OIS::KC_Z)) { if (_keyboard->isKeyDown(OIS::KC_A)) _animState = _sceneManager->getEntity("Horse")-> getAnimationState("Saltar"); else _animState = _sceneManager->getEntity("Horse")-> getAnimationState("Rotar"); _animState->setEnabled(true); _animState->setLoop(true); _animState->setTimePosition(0.0); } if (_animState != NULL) { if (_animState->hasEnded()) { _animState->setTimePosition(0.0); _animState->setEnabled(false); } else _animState->addTime(deltaT); }

Es posible denir varias animaciones y gestionarlas mediante diferentes AnimationState. En el siguiente ejemplo se cargan dos animaciones jas en el constructor del FrameListener (lnea 3-8 ). Empleando las mismas teclas que en el ejemplo anterior, se resetean cada una de ellas, y se actualizan ambas de forma independiente (en las lneas 26 y 28 ). Ogre se encarga de mezclar sus resultados (incluso es posible aplicar transformaciones a nivel de nodo, pulsando la tecla R mientras se reproducen las animaciones del AnimationState ).
Listado 11.2: Fragmento de MyFrameListener.cpp.
1 MyFrameListener::MyFrameListener() { 2 // ... 3 _animState = _sceneManager->getEntity("Horse")-> 4 getAnimationState("Saltar"); 5 _animState->setEnabled(false); 6 _animState2 = _sceneManager->getEntity("Horse")-> 7 getAnimationState("Rotar"); 8 _animState2->setEnabled(false); 9 } 10 11 bool MyFrameListener::frameStarted(const FrameEvent& evt) { 12 // ... 13 if (_keyboard->isKeyDown(OIS::KC_A)) { 14 _animState->setTimePosition(0.0); 15 _animState->setEnabled(true); 16 _animState->setLoop(false); 17 } 18 19 if (_keyboard->isKeyDown(OIS::KC_Z)) { 20 _animState2->setTimePosition(0.0); 21 _animState2->setEnabled(true); 22 _animState2->setLoop(false); 23 } 24 25 if (_animState->getEnabled() && !_animState->hasEnded()) 26 _animState->addTime(deltaT); 27 if (_animState2->getEnabled() && !_animState2->hasEnded()) 28 _animState2->addTime(deltaT); 29 // ...

11.4. Mezclado de animaciones

[221]

Obviamente, ser necesario contar con alguna clase de nivel superior que nos gestione las animaciones, y se encarge de gestionar los AnimationState, actualizndolos adecuadamente.

11.4.

Mezclado de animaciones

En la seccin anterior hemos utilizado dos canales de animacin, con posibilidad de reproduccin simultnea. En la mayora de las ocasiones es necesario contar con mecanismos que permitan el mezclado controlado de animaciones (Animation Blending). Esta tcnica fundamental se emplea desde hace aos en desarrollo de videojuegos. En la actualidad se emplean mdulos especcos para el mezclado de animaciones. El uso de rboles de prioridad (Priority Blend Tree 4 ) facilita al equipo artstico de una produccin especicar con un alto nivel de detalle cmo se realizar la composicin de las capas de animacin. El mezclado de animaciones requiere un considerable tiempo de
CPU. La interpolacin necesaria para mezclar los canales de anima-

cin en cada frame hace que el rendimiento del videojuego pueda verse afectado. Empleando interpoilacin esfrica SLERP, para cada elemento del esqueleto es necesario calcular varias operaciones costosas (cuatro senos, un arccos, y una raz cuadrada). A un alto nivel de abstraccin, cada animacin en Ogre tiene asociado un peso. Cuando se establece la posicin dentro de la animacin, puede igualmente modicarse el peso del canal de animacin. Dependiendo del peso asignado a cada animacin, Ogre se encargar de realizar la interpolacin de todas las animaciones activas para obtener la posicin nal del objeto. A continuacin deniremos una clase llamada AnimationBlender que se encargar de realizar la composicin bsica de capas de animacin.
Figura 11.9: La clase de AnimationBlender (Mezclado de Animaciones) no tiene nada que ver con el prestigioso paquete de animacin del mismo nombre.

Las variables miembro privadas de la clase AnimationBlender contienen a las animaciones de inicio y n del mezclado (lneas punteros 10 y 11 ), el tipo de transicin deseado (que es un tipo enumerado de nido en las lneas 3-6 ), y un booleano que indica si la animacin se reproducir en bucle. Las variables pblicas (denidas en 16-18 ) contienen el tiempo restante de reproduccin de la pista actual, la duracin (en segundos) del mezclado entre pistas y un valor booleano que indica si la reproduccin ha nalizado. La clase incorpora, adems de los tres mtodos principales que estudiaremos a continuacin, una serie de mtodos auxiliares que nos permiten obtener valores relativos a las variables privadas (lneas 24-27 ).

4 Ms informacin sobre cmo se implement el motor de mezclado de animaciones del MechWarrior en http://www.gamasutra.com/view/feature/3456/

[222]

CAPTULO 11. ANIMACIN

Listado 11.3: AminationBlender.h


1 class AnimationBlender { 2 public: 3 enum BlendingTransition { 4 Switch, // Parar fuente y reproduce destino 5 Blend // Cross fade (Mezclado suave) 6 }; 7 8 private: 9 Entity *mEntity; // Entidad a animar 10 AnimationState *mSource; // Animacion inicio 11 AnimationState *mTarget; // Animacion destino 12 BlendingTransition mTransition; // Tipo de transicion 13 bool mLoop; // Animacion en bucle? 14 15 public: 16 Real mTimeleft; // Tiempo restante de la animacion (segundos) 17 Real mDuration; // Tiempo invertido en el mezclado (segundos) 18 bool mComplete; // Ha finalizado la animacion? 19 20 AnimationBlender( Entity *); 21 void blend(const String &anim, BlendingTransition transition, 22 Real duration, bool l=true); 23 void addTime(Real); 24 Real getProgress() { return mTimeleft/mDuration; } 25 AnimationState *getSource() { return mSource; } 26 AnimationState *getTarget() { return mTarget; } 27 bool getLoop() { return mLoop; } 28 };

Veamos a continuacin los principales mtodos de la clase, decla rados en las lneas 20-23 del listado anterior.
Listado 11.4: AminationBlender.cpp (Constructor)
1 AnimationBlender::AnimationBlender(Entity *ent) : mEntity(ent) { 2 AnimationStateSet *set = mEntity->getAllAnimationStates(); 3 AnimationStateIterator it = set->getAnimationStateIterator(); 4 // Inicializamos los AnimationState de la entidad 5 while(it.hasMoreElements()) { 6 AnimationState *anim = it.getNext(); 7 anim->setEnabled(false); 8 anim->setWeight(0); 9 anim->setTimePosition(0); 10 } 11 mSource = NULL; mTarget = NULL; mTimeleft = 0; 12 }

En el constructor de la clase inicializamos todas las animaciones asociadas a la entidad (recibida como nico parmetro). Mediante un iterador (lnea 6 ) desactivamos todos los AnimationState asociados (l ), y reseteamos la posicin de reproduccin y su peso asociado nea 7 para su posterior composicin (lneas 8-9 ). La clase AnimationBlender dispone de un mtodo principal para cargar animaciones, indicando (como segundo parmetro) el tipo de mezcla que quiere realiarse con la animacin que est reproducindose. La implementacin actual de la clase admite dos modos de mezclado; un efecto de mezclado suave tipo cross fade y una transicin bsica de intercambio de canales.

11.4. Mezclado de animaciones

[223]

Saltar

Rotar
Saltar Rotar +

La transicin de tipo Blend implementa una transicin simple lineal de tipo Cross Fade. En la Figura 11.10 representa este tipo de transicin, donde el primer canal de animacin se mezclar de forma suave con el segundo, empleando una combinacin lineal de pesos.
Listado 11.5: AminationBlender.cpp (Blend)
1 void AnimationBlender::blend (const String &anim, 2 BlendingTransition transition, Real duration, bool l) { 3 4 AnimationState *newTarget = mEntity->getAnimationState(anim); 5 newTarget->setLoop(l); 6 mTransition = transition; 7 mDuration = duration; 8 mLoop = l; 9 10 if ((mTimeleft<=0) || (transition == AnimationBlender::Switch)){ 11 // No hay transicion (finalizo la anterior o Switch) 12 if (mSource != NULL) mSource->setEnabled(false); 13 mSource = newTarget; // Establecemos la nueva 14 mSource->setEnabled(true); 15 mSource->setWeight(1); // Con maxima influencia 16 mSource->setTimePosition(0); // Reseteamos la posicion 17 mTimeleft = mSource->getLength(); // Duracion del AnimState 18 mTarget = NULL; 19 } 20 else { // Hay transicion suave 21 if (mSource != newTarget) { 22 mTarget = newTarget; // Nuevo destino 23 mTarget->setEnabled(true); 24 mTarget->setWeight(0); // Cambia peso en addTime 25 mTarget->setTimePosition(0); 26 } 27 } 28 }

Saltar

Rotar

Duracin de la transicin

Figura 11.10: Efecto de transicin tipo Cross Fade. En el tiempo especicado en la duracin de la transicin ambos canales de animacin tienen inuencia en el resultado nal.

Saltar Rotar Saltar Rotar

Aunque la implementacin actual utiliza una simple combinacin lineal de pesos, es posible denir cualquier funcin de mezcla. Bastar con modicar la implementacin del mtodo addTime que veremos a continuacin. Por su parte, el mtodo de mezclado de tipo Switch realiza un intercambio directo de los dos canales de animacin (ver Figura 11.11). Este mtodo es el utilizado igualmente si el canal que se est reproduciendo actualmente ha nalizado (ver lnea 10 del listado anterior). La implementacin del mtodo anterior tiene en cuenta el canal de animacin que se est reproduciendo actualmente. Si el canal a ). En otro caso, se mezclar es igual que el actual, se descarta (lnea 21 aade como objetivo, activando el nuevo canal pero estableciendo su peso a 0 (lnea 24 ). La mezcla efectiva de las animaciones (el cambio de peso asociado a cada canal de animacin) se realiza en el mtodo addTime, cuyo listado se muestra a continuacin.

Figura 11.11: Transicin de tipo Intercambio. El parmetro de duracin, aunque se especique, no tiene ningn efecto.

[224]

CAPTULO 11. ANIMACIN

Listado 11.6: AminationBlender.cpp (addTime)


1 void AnimationBlender::addTime(Real time) { 2 if (mSource == NULL) return; // No hay fuente 3 mSource->addTime(time); 4 mTimeleft -= time; 5 mComplete = false; 6 if ((mTimeleft <= 0) && (mTarget == NULL)) mComplete = true; 7 8 if (mTarget != NULL) { // Si hay destino 9 if (mTimeleft <= 0) { 10 mSource->setEnabled(false); 11 mSource->setWeight(0); 12 mSource = mTarget; 13 mSource->setEnabled(true); 14 mSource->setWeight(1); 15 mTimeleft = mSource->getLength(); 16 mTarget = NULL; 17 } 18 else { // Queda tiempo en Source... cambiar pesos 19 Real weight = mTimeleft / mDuration; 20 if (weight > 1) weight = 1.0; 21 mSource->setWeight(weight); 22 mTarget->setWeight(1.0 - weight); 23 if (mTransition == AnimationBlender::Blend) 24 mTarget->addTime(time); 25 } 26 } 27 if ((mTimeleft <= 0) && mLoop) mTimeleft = mSource->getLength(); 28 }

Al igual que en el uso de animaciones bsicas en Ogre, el mtodo addTime debe ser llamado cada vez que se redibuje la escena, indicando el tiempo transcurrido desde la ltima actualizacin. La clase AnimationBlender se encargar a su vez de ejecutar add mtodo el ). El mtodo Time de los canales de animacin activos (lneas 3 y 24 addTime lleva internamente la cuenta del tiempo que le queda al canal de reproduccin al canal de animacin. Cuando el tiempo es menor o igual que el tiempo empleado para la transicin, se calcular el peso que se asignar a cada canal (lneas 19-22 ). El peso se calcula empleando una sencilla combinacin lineal, de modo que el peso total para ambos canales en cualquier instante debe ser igual a uno (ver Figura 11.12). No es necesario que el peso nal combinado de todas las animaciones sea igual a uno. No obstante, es conveniente que la suma de todos los canales de animacin estn normalizados y sean igual a 1. En el caso de asignar pesos negativos, la animacin se reproducir empleando curvas de animacin invertidas. La composicin de animaciones suele ser una tarea compleja. En el ejemplo desarrollado para ilustrar el uso de la clase AnimationBlender se han utilizado nicamente dos animaciones, y se han utilizado tiempos de transicin jos en todos los casos. En produccin es importante trabajar las transiciones y las curvas de animacin para obtener resultados atractivos.

Figura 11.12: Clculo del peso de cada animacin basndose en la duracin de la transicin. En los instantes de tiempo a, b y c se muestra el valor del peso asociado a cada canal de animacin.

Cuntas animaciones?
La cantidad de animaciones necesarias para aplicar correctamente las tcnicas de Animation Blending pueden ser muy elevadas. Por ejemplo, en MechWarrior de Microsoft cada robot tena asociadas ms de 150 animaciones.

11.4. Mezclado de animaciones

[225]

Figura 11.13: Ejemplo de aplicacin que utiliza la clase AnimationBlender. Mediante las teclas indicadas en el interfaz es posible componer las animaciones exportadas empleandos los dos modos de transicin implementados.

El mezclado de animaciones que son muy diferentes provoca resultados extraos. Es mejor combinar canales de animacin que son similares, de forma que la mezcla funciona adecuadamente. En el ejemplo de esta seccin se mezclan animaciones muy diferentes, para mostrar un caso extremo de uso de la clase. En entornos de produccin, suelen denirse puntos de conexin entre animaciones, de modo que la clase de Blending se espera hasta alcanzar uno de esos puntos para realizar la mezcla. De este modo, se generan un alto nmero de animaciones para garantizar que las mezclas funcionarn correctamente sin comportamientos extraos.

Es importante realizar pruebas de la correcta composicin y mezclado de animaciones en las primeras etapas del desarrollo del juego. De otra forma, podemos sufrir desagradables sorpresas cuando se acerca la deadline del proyecto. Puede resultar complicado ajustar en cdigo la mezcla de animaciones, por lo que suelen desarrollarse scripts de exportacin adicionales para indicar los puntos adecuados en cada animacin donde puede componerse con el resto.

El siguiente listado muestra un ejemplo de uso de la clase. En el constructor del FrameListener se crea una variable miembro de la cla-

[226] se que contendr un puntero al objeto AnimBlender. Cada vez que se actualiza el frame, llamamos al mtodo addTime (ver lnea 11 ) que actualizar los canales de animacin convenientes. En este ejemplo se han utilizado las 8 teclas descritas en la Figura 11.13 para mezclar las dos animaciones exportadas en Blender al inicio del captulo.
Listado 11.7: Uso de AnimationBlender
1 2 3 4 5 6 7 8 9 10 11

CAPTULO 11. ANIMACIN

if (_keyboard->isKeyDown(OIS::KC_Q)) _animBlender->blend("Saltar",AnimationBlender::Blend,0.5, false); if (_keyboard->isKeyDown(OIS::KC_R)) _animBlender->blend("Rotar", AnimationBlender::Blend, 0.5, true); if (_keyboard->isKeyDown(OIS::KC_S)) _animBlender->blend("Saltar", AnimationBlender::Switch, 0, true); if (_keyboard->isKeyDown(OIS::KC_D)) _animBlender->blend("Rotar", AnimationBlender::Switch, 0, false); _animBlender->addTime(deltaT);

En este captulo hemos estudiado los usos fundamentales de la animacin de cuerpo rgido. En el mdulo 3 del curso estudiaremos algunos aspectos avanzados, como la animacin de personajes empleando esqueletos y aproximaciones de cinemtica inversa y el uso de motores de simulacin fsica para obtener, de forma automtica, animaciones realistas.

Captulo

Simulacin Fsica
Carlos Gonzlez Morcillo

12

n prcticamente cualquier videojuego (tanto 2D como 3D) es necesaria la deteccin de colisiones y, en muchos casos, la simulacin realista de dinmica de cuerpo rgido. En este captulo estudiaremos la relacin existente entre sistemas de deteccin de colisiones y sistemas de simulacin fsica, y veremos algunos ejemplos de uso del motor de simulacin fsica libre Bullet.

12.1.
Figura 12.1: Anarkanoid, el machacaladrillos sin reglas es un juego tipo Breakout donde la simulacin fsica se reduce a una deteccin de colisiones 2D.

Introduccin

La mayora de los videojuegos requieren en mayor o menor medida el uso de tcnicas de deteccin de colisiones y simulacin fsica. Desde un videojuego clsico como Arkanoid, hasta modernos juegos automovilsticos como Gran Turismo requieren denir la interaccin de los elementos en el mundo fsico. El motor de simulacin fsica puede abarcar una amplia gama de caractersticas y funcionalidades, aunque la mayor parte de las veces el trmino se reere a un tipo concreto de simulacin de la dinmica de cuerpos rgidos. Esta dinmica se encarga de determinar el movimiento de estos cuerpos rgidos y su interaccin ante la inuencia de fuerzas. En el mundo real, los objetos no pueden pasar a travs de otros objetos (salvo casos especcos convenientemente documentados en la revista Ms All ). En nuestro videojuego, a menos que tengamos en cuenta las colisiones de los cuerpos, tendremos el mismo efecto. El sistema de deteccin de colisiones, que habitualmente es un mdulo 227

Cuerpo Rgido
Denimos un cuerpo rgido como un objeto slido ideal, innitamente duro y no deformable.

[228]

CAPTULO 12. SIMULACIN FSICA

del motor de simulacin fsica, se encarga de calcular estas relaciones, determinando la relacin espacial existente entre cuerpos rgidos. La mayor parte de los videojuegos actuales incorporan ciertos elementos de simulacin fsica bsicos. Algunos ttulos se animan a incorporar ciertos elementos complejos como simulacin de telas, cuerdas, pelo o uidos. Algunos elementos de simulacin fsica son precalculados y almacenados como animaciones estticas, mientras que otros necesitan ser calculados en tiempo real para conseguir una integracin adecuada. Como hemos indicado anteriormente, las tres tareas principales que deben estar soportadas por un motor de simulacin fsica son la deteccin de colisiones, su resolucin (junto con otras restricciones de los objetos) y calcular la actualizacin del mundo tras esas interacciones. De forma general, las caractersticas que suelen estar presentes en motores de simulacin fsica son: Deteccin de colisiones entre objetos dinmicos de la escena. Esta deteccin podr ser utilizada posteriormente por el mdulo de simulacin dinmica. Clculo de lineas de visin y tiro parablico, para la simulacin del lanzamiento de proyectiles en el juego. Denicin de geometra esttica de la escena (cuerpos de colisin) que formen el escenario del videojuego. Este tipo de geometra puede ser ms compleja que la geometra de cuerpos dinmicos. Especicacin de fuerzas (tales como viento, rozamiento, gravedad, etc...), que aadirn realismo al videjuego. Simulacin de destruccin de objetos: paredes y objetos del escenario. Denicin de diversos tipos de articulaciones, tanto en elementos del escenario (bisagras en puertas, rales...) como en la descripcin de las articulaciones de personajes. Especicacin de diversos tipos de motores y elementos generadores de fuerzas, as como simulacin de elementos de suspensin y muelles. Simulacin de uidos, telas y cuerpos blandos (ver Figura 12.2).

Figura 12.2: Tres instantes en la simulacin fsica de una tela sobre un cubo. Simulacin realizada con el motor Bullet.

12.1.1.

Algunos Motores de Simulacin

El desarrollo de un motor de simulacin fsica desde cero es una tarea compleja y que requiere gran cantidad de tiempo. Afortunadamente existen gran variedad de motores de simulacin fsica muy robustos, tanto basados en licencias libres como comerciales. A continuacin se describirn brevemente algunas de las bibliotecas ms utilizadas:

12.1. Introduccin

[229] Bullet. Bullet es una biblioteca de simulacin fsica ampliamente utilizada tanto en la industria del videojuego como en la sntesis de imagen realista (Blender, Houdini, Cinema 4D y LightWave las utilizan internamente). Bullet es multiplataforma, y se distribuye bajo una licencia libre zlib compatible con GPL. Estudiaremos con ms detalle este motor, junto con su uso en Ogre, en la Seccin 12.5. ODE. ODE (Open Dynamics Engine ) www.ode.org es un motor de simulacin fsica desarrollado en C++ bajo doble licencias BSD y LGPL. El desarrollo de ODE comenz en el 2001, y ha sido utilizado como motor de simulacin fsica en multitud de xitos mundiales, como el aclamado videojuego multiplataforma World of Goo, BloodRayne 2 (PlayStation 2 y Xbox), y TitanQuest (Windows). Ogre cuenta igualmente con un wrapper para utilizar este motor de simulacin fsica. PhysX. Este motor privativo, es actualmente mantenido por NVidia con aceleracin basada en hardware (mediante unidades especcas de procesamiento fsico PPUs Physics Processing Units o mediante ncleos CUDA. Las tarjetas grcas con soporte de CUDA (siempre que tengan al menos 32 ncleos CUDA) pueden realizar la simulacin fsica en GPU. Este motor puede ejecutarse en multitud de plataformas como PC (GNU/Linux, Windows y Mac), PlayStation 3, Xbox y Wii. El SDK es gratuito, tanto para proyectos comerciales como no comerciales. Existen multitud de videojuegos comerciales que utilizan este motor de simulacin. Gracias al wrapper NxOgre se puede utilizar este motor en Ogre. Havok. El motor Havok se ha convertido en el estndar de facto en el mundo del software privativo, con una amplia gama de caractersticas soportadas y plataformas de publicacin (PC, Videoconsolas y Smartphones). Desde que en 2007 Intel comprara la compaa que originalmente lo desarroll, Havok ha sido el sistema elegido por ms de 150 videojuegos comerciales de primera lnea. Ttulos como Age of Empires, Killzone 2 & 3, Portal 2 o Uncharted 3 avalan la calidad del motor. Existen algunas bibliotecas especcas para el clculo de colisiones (la mayora distribuidas bajo licencias libres). Por ejemplo, I-Collide, desarrollada en la Universidad de Carolina del Norte permite calcular intersecciones entre volmenes convexos. Existen versiones menos ecientes para el tratamiento de formas no convexas, llamadas V-Collide y RAPID. Estas bibliotecas pueden utilizarse como base para la construccin de nuestro propio conjunto de funciones de colisin para videojuegos que no requieran funcionalidades fsicas complejas.

Figura 12.3: Ejemplo de simulacin fsica con ODE (demo de la distribucin ocial), que incorpora el uso de motores y diferentes geometras de colisin.

Figura 12.4: Logotipo del motor de simulacin fsico estrella en el mundo del software privativo.

Fsica

... Lgica del Juego

Grficos

GUI IA

Networking

Figura 12.5: El motor de simulacin fsica est directamente relacionado con otros mdulos del videojuego. Esta dependencia conlleva una serie de dicultades que deben tenerse en cuenta.

12.1.2. Aspectos destacables


El uso de un motor de simulacin fsica en el desarrollo de un videojuego conlleva una serie de aspectos que deben tenerse en cuenta relativos al diseo del juego, tanto a nivel de jugabilidad como de mdulos arquitectnicos:

[230]

CAPTULO 12. SIMULACIN FSICA

Figura 12.6: Gracias al uso de PhysX, las baldosas del suelo en Batman Arkham Asylum pueden ser destruidas (derecha). En la imagen de la izquierda, sin usar PhysX el suelo permanece inalterado, restando realismo y espectacularidad a la dinmica del juego.

Predictibilidad. El uso de un motor de simulacin fsica afecta a la predictibilidad del comportamiento de sus elementos. Adems, el ajuste de los parmetros relativos a la denicin de las caractersticas fsicas de los objetos (coecientes, constantes, etc...) son difciles de visualizar. Realizacin de pruebas. La propia naturaleza catica de las simulaciones (en muchos casos no determinista) diculta la realizacin de pruebas en el videojuego. Integracin. La integracin con otros mdulos del juego puede ser compleja. Por ejemplo, qu impacto tendr en la bsqueda de caminos el uso de simulaciones fsicas? cmo garantizar el determinismo en un videojuego multijugador?. Realismo grco. El uso de un motor de simulacin puede dicultar el uso de ciertas tcnicas de representacin realista (como por ejemplo el preclculo de la iluminacin con objetos que pueden ser destruidos). Adems, el uso de cajas lmite puede producir ciertos resultados poco realistas en el clculo de colisiones. Exportacin. La denicin de objetos con propiedades fsicas aade nuevas variables y constantes que deben ser tratadas por las herramientas de exportacin de los datos del juego. En muchas ocasiones es necesario adems la exportacin de diferentes versiones de un mismo objeto (una versin de alta poligonalizacin, la versin de colisin, una versin destructible, etc). Interfaz de Usuario. Es necesario disear interfaces de usuario adaptados a las capacidades fsicas del motor (cmo se especica la fuerza y la direccin de lanzamiento de una granada?, de qu forma se interacta con objetos que pueden recogerse del suelo?).
Figura 12.7: La primera incursin de Steven Spielberg en el mundo de los videojuegos fue en 2008 con Boom Blox, un ttulo de Wii desarrollado por Electronic Arts con una componente de simulacin fsica crucial para la experiencia del jugador.

12.1. Introduccin

[231]

12.1.3. Conceptos Bsicos


A principios del siglo XVII, Isaac Netwon public las tres leyes fundamentales del movimiento. A partir de estos tres principios se explican la mayor parte de los problemas de dinmica relativos al movimiento de cuerpos y forman la base de la mecnica clsica. Las tres leyes pueden resumirse como: 1. Un cuerpo tiende a mantenerse en reposo o a continuar movindose en lnea recta a una velocidad constante a menos que acte sobre l una fuerza externa. Esta ley resume el concepto de inercia. 2. El cambio de movimiento es proporcional a la fuerza motriz aplicada y ocurre segn la lnea recta a lo largo de la que se aplica dicha fuerza. 3. Para cada fuerza que acta sobre un cuerpo ocurre una reaccin igual y contraria. De este modo, las acciones mutuas de dos cuerpos siempre son iguales y dirigidas en sentido opuesto. En el estudio de la dinmica resulta especialmente interesante la segunda ley de Newton, que puede ser escrita como F =ma (12.1)

(Ecuaciones)

Modelo

1 Proceso Fsico 4
(Implementacin)

donde F es la fuerza resultante que acta sobre un cuerpo de masa m, y con una aceleracin lineal a aplicada sobre el centro de gravedad del cuerpo. Desde el punto de vista de la mecnica en videojuegos, la masa puede verse como una medida de la resistencia de un cuerpo al movimiento (o al cambio en su movimiento). A mayor masa, mayor resistencia para el cambio en el movimiento. Segn la segunda ley de Newton que hemos visto anteriormente, podemos expresar que a = F/m, lo que nos da una impresin de cmo la masa aplica resistencia al movimiento. As, si aplicamos una fuerza constante e incrementamos la masa, la aceleracin resultante ser cada vez menor. El centro de masas (o de gravedad) de un cuerpo es el punto espacial donde, si se aplica una fuerza, el cuerpo se desplazara sin aplicar ninguna rotacin. Un sistema dinmico puede ser denido como cualquier coleccin de elementos que cambian sus propiedades a lo largo del tiempo. En el caso particular de las simulaciones de cuerpo rgido nos centraremos en el cambio de posicin y rotacin. As, nuestra simulacin consistir en la ejecucin de un modelo matemtico que describe un sistema dinmico en un ordenador. Al utilizar modelos, se simplica el sistema real, por lo que la simulacin no describe con total exactitud el sistema simulado.

3
de Simulacin

Algoritmo

Programa

5 Simulacin
(Ejecucin)

Figura 12.8: Etapas en la construccin de un motor de simulacin fsica.

[232]

CAPTULO 12. SIMULACIN FSICA

Habitualmente se emplean los trminos de interactividad y tiempo real de modo equivalente, aunque no lo son. Una simulacin interactiva es aquella que consigue una tasa de actualizacin suciente para el control por medio de una persona. Por su parte, una simulacin en tiepo real garantiza la actualizacin del sistema a un nmero jo de frames por segundo. Habitualmente los motores de simulacin fsica proporcionan tasas de frames para la simulacin interactiva, pero no son capaces de garantizar Tiempo Real.

zi
zi-1

iace Enl

i i-1
xx i-1i

En multitud de ocasiones es necesario denir restricciones que denan lmites a ciertos aspectos de la simulacin. Los controladores son elementos que generan entradas a la simulacin y que tratan de controlar el comportamiento de los objetos que estn siendo simulados. Por ejemplo, un controlador puede intentar mantener constante el ngulo entre dos eslabones de una cadena robtica (ver Figura 12.9).

Figura 12.9: Un controlador puede intentar que se mantenga constante el ngulo i formado entre dos eslabones de un brazo robtico.

12.2.

Sistema de Deteccin de Colisiones


Test de Interseccin
En realidad, el Sistema de Deteccin de Colisiones puede entenderse como un mdulo para realizar pruebas de interseccin complejas.

La responsabilidad principal del Sistema de Deteccin de Colisiones (SDC) es calcular cundo colisionan los objetos de la escena. Para calcular esta colisin, los objetos se representan internamente por una forma geomtrica sencilla (como esferas, cajas, cilindros...). Adems de comprobar si hubo colisin entre los objetos, el SDC se encarga de proporcionar informacin relevante al resto de mdulos del simulador fsico sobre las propiedades de la colisin. Esta informacin se utiliza para evitar efectos indeseables, como la penetracin de un objeto en otro, y consegir la estabilidad en la simulacin cuando el objeto llega a la posicin de equilibrio.

12.2.1.

Formas de Colisin

Como hemos comentado anteriormente, para calcular la colisin entre objetos, es necesario proporcionar una representacin geomtrica del cuerpo que se utilizar para calcular la colisin. Esta representacin interna se calcular para determinar la posicin y orientacin del objeto en el mundo. Estos datos, con una descripcin matemtica mucho ms simple y eciente, son diferentes de los que se emplean en la representacin visual del objeto (que cuentan con un mayor nivel de detalle). Habitualmente se trata de simplicar al mximo la forma de colisin. Aunque el SDC soporte objetos complejos, ser preferible emplear tipos de datos simples, siempre que el resultado sea aceptable. La Figura 12.10 muestra algunos ejemplos de aproximacin de formas de colisin para ciertos objetos del juego.

12.2. Sistema de Deteccin de Colisiones

[233]

Multitud de motores de simulacin fsica separan la forma de colisin de la transformacin interna que se aplica al objeto. De esta forma, como muchos de los objetos que intervienen en el juego son dinmicos, basta con aplicar la transformacin a la forma de un modo computacionalmente muy poco costoso. Adems, separando la transformacin de la forma de colisin es posible que varias entidades del juego compartan la misma forma de colisin.

Algunos motores de simulacin fsica permiten compartir la misma descripcin de la forma de colisin entre entidades. Esto resulta especialmente til en juegos donde la forma de colisin es compleja, como en simuladores de carreras de coches.

(a)
Como se muestra en la Figura 12.10, las entidades del juego pueden tener diferentes formas de colisin, o incluso pueden compartir varias primitivas bsicas (para representar por ejemplo cada parte de la articulacin de un brazo robtico).

(b)

(c)
Figura 12.10: Diferentes formas de colisin para el objeto de la imagen. (a) Aproximacin mediante una caja. (b) Aproximacin mediante un volumen convexo. (c) Aproximacin basada en la combinacin de varias primitivas de tipo cilndrico.

El Mundo Fsico sobre el que se ejecuta el SDC mantiene una lista de todas las entidades que pueden colisionar empleando habitualmente una estructura global Singleton. Este Mundo Fsico es una representacin del mundo del juego que mantiene la informacin necesaria para la deteccin de las colisiones. Esta separacin evita que el SDC tenga que acceder a estructuras de datos que no son necesarias para el clculo de la colisin. Los SDC mantienen estructuras de datos especcas para manejar las colisiones, proporcionando informacin sobre la naturaleza del contacto, que contiene la lista de las formas que estn intersectando, su velocidad, etc... Para gestionar de un modo ms eciente las colisiones, las formas que suelen utilizarse con convexas. Una forma convexa es aquella en la que un rayo que surja desde su interior atravesar la superce una nica vez. Las supercies convexas son mucho ms simples y requieren menor capacidad computacional para calcular colisiones que las formas cncavas. Algunas de las primitivas soportadas habitualmente en SDC son: Esferas. Son las primitivas ms simples y ecientes; basta con denir su centro y radio (uso de un vector de 4 elementos). Cajas. Por cuestiones de eciencia, se suelen emplear cajas lmite alineadas con los ejes del sistema de coordenadas (AABB o Axis Aligned Bounding Box ). Las cajas AABB se denen mediante las coordenadas de dos extremos opuestos. El principal problema de las cajas AABB es que, para resultar ecientes, requieren estar alineadas con los ejes del sistema de coordenas global. Esto implica que si el objeto rota, como se muestra en la Figura 12.11, la aproximacin de forma puede resultar de baja

Formas de colisin
A cada cuerpo dinmico se le asocia habitualmente una nica forma de colisin en el SDC.

[234]

CAPTULO 12. SIMULACIN FSICA

Figura 12.11: Gestin de la forma de un objeto empleando cajas lmite alineadas con el sistema de referencia universal AABBs. Como se muestra en la gura, la caja central realiza una aproximacin de la forma del objeto muy pobre.

calidad. Por su eciencia, este tipo de cajas suelen emplearse para realizar una primera aproximacin a la interseccin de objetos para, posteriormente, emplear formas ms precisas en el clculo de la colisin. Por su parte, las cajas OBB (Oriented Bounding Box ) denen una rotacin relativa al sistema de coordenadas. Su descripcin es muy simple y permiten calcular la colisin entre primitivas de una forma muy eciente. Cilindros. Los cilindros son ampliamente utilizados. Se denen mediante dos puntos y un radio. Una extensin de esta forma bsica es la cpsula, que es un cuerpo compuesto por un cilindro y dos semiesferas (ver Figura 12.12). Puede igualmente verse como el volumen resultante de desplazar una esfera entre dos puntos. El clculo de la interseccin con cpsulas es ms eciente que con esferas o cajas, por lo que se emplean para el modelo de formas de colisin en formas que son aproximadamente cilndricas (como las extremidades del cuerpo humano). Volmenes convexos. La mayora de los SDC permiten trabajar con volmenes convexos (ver Figura 12.10). La forma del objeto suele representarse internamente mediante un conjunto de n planos. Aunque este tipo de formas es menos eciente que las primitivas estudiadas anteriormente, existen ciertos algoritmos como el GJK que permiten optimizar los clculos en este tipo de formas. Malla poligional. En ciertas ocasiones puede ser interesante utilizar mallas arbitrarias. Este tipo de supercies pueden ser abiertas (no es necesario que denan un volumen), y se construyen como mallas de tringulos. Las mallas poligonales se suelen emplear en elementos de geometra esttica, como elementos del escenario, terrenos, etc. (ver Figura 12.13) Este tipo de formas de colisin son las ms complejas computacionalmente, ya que el

Figura 12.12: Algunas primitivas de colisin soportadas en ODE: Cajas, cilindros y cpsulas. La imagen inferior muestra los AABBs asociados a los objetos.

12.2. Sistema de Deteccin de Colisiones

[235]

SDC debe probar con cada tringulo. As, muchos juegos tratan de limitar el uso de este tipo de formas de colisin para evitar que el rendimiento se desplome. Formas compuestas. Este tipo de formas se utilizan cuando la descripcin de un objeto se aproxima ms convenientemente con una coleccin de formas. Este tipo de formas es la aproximacin deseable en el caso de que tengamos que utilizar objetos cncavos, que no se adaptan adecuadamente a volmenes convexos (ver Figura 12.14).

Figura 12.13: Bullet soporta la denicin de mallas poligonales animadas. En este ejemplo de las demos ociales, el suelo est animado y los objetos convexos colisionan respondiendo a su movimiento.

12.2.2. Optimizaciones
La deteccin de colisiones es, en general, una tarea que requiere el uso intensivo de la CPU. Por un lado, los clculos necesarios para determianr si dos formas intersecan no son triviales. Por otro lado, muchos juegos requiren un alto nmero de objetos en la escena, de modo que el nmero de test de interseccin a calcular rpidamente crece. En el caso de n objetos, si empleamos un algoritmo de fuerza bruta tendramos una complejidad O(n2 ). Es posible utilizar ciertos tipos de optimizaciones que mejoran esta complejidad inicial: Coherencia Temporal. Este tipo de tcnica de optimizacin (tambin llamada coherencia entre frames), evita recalcular cierto tipo de informacin en cada frame, ya que entre pequeos intervalos de tiempo los objetos mantienen las posiciones y orientaciones en valores muy similares. Particionamiento Espacial. El uso de estructuras de datos de particionamiento especial permite comprobar rpidamente si dos objetos podran estar intersecando si comparten la misma celda de la estructura de datos. Algunos esquemas de particionamiento jerrquico, como rboles octales, BSPs o rboles-kd permiten optimizar la deteccin de colisiones en el espacio. Estos esquemas tienen en comn que el esquema de particionamiento comienza realizando una subdivisin general en la raz, llegando a divisiones ms nas y especcas en las hojas. Los objetos que se encuentran en una determinada rama de la estructura no pueden estar colisionando con los objetos que se encuentran en otra rama distinta. Barrido y Poda (SAP). En la mayora de los motores de simulacin fsica se emplea un algoritmo Barrido y Poda (Sweep and Prune ). Esta tcnica ordena las cajas AABBs de los objetos de la escena y comprueba si hay intersecciones entre ellos. El algoritmo Sweep and Prune hace uso de la Coherencia temporal frame a frame para reducir la etapa de ordenacin de O(n log (n)) a O(n). En muchos motores, como en Bullet, se utilizan varias capas o pasadas para detectar las colisiones. Primero suelen emplearse cajas AABB para comprobar si los objetos pueden estar potencialmente en

a)

b)

Figura 12.14: El modelo de una silla es un objeto que no se adapta bien a un volumen convexo (a). En (b) se ha utilizado una forma compuesta deniendo dos cajas.

[236]

CAPTULO 12. SIMULACIN FSICA

d Po

d d d

Po a) b) c)

Po

Po d)

Figura 12.15: Clculo de los puntos de colisin empleando Shape Casting. a) La forma inicialmente se encuentra colisionando con algn objeto de la escena. b) El SDC obtiene un punto de colisin. c) La forma interseca con dos objetos a la vez. d) En este caso el sistema calcula todos los puntos de colisin a lo largo de la trayectoria en la direccin de d.

colisin (deteccin de la colisin amplia). A continuacin, en una segunda capa se hacen pruebas con volmenes generales que engloban los objetos (por ejemplo, en un objeto compuesto por varios subobjetos, se calcula una esfera que agrupe a todos los subobjetos). Si esta segunda capa de colisin da un resultado positivo, en una tercera pasada se calculan las colisiones empleando las formas nales.

12.2.3.

Preguntando al sistema...

En el mdulo 2 ya estudiamos algunas de las funcionalidades que se pueden encontrar en sistemas de deteccin de colisiones. El objetivo es poder obtener resultados a ciertas consultas sobre el primer objeto que intersecar con un determinado rayo, si hay objetos situados en el interior de un determinado volumen, etc. A continuacin veremos dos de las principales collision queries que pueden encontrarse habitualmente en un SDC: Ray Casting. Este tipo de query requiere que se especique un rayo, y un origen. Si el rayo interseca con algn objeto, se devolver un punto o una lista de puntos. Como vimos, el rayo se especica habitualmente mediante una ecuacin paramtrica de modo que p(t) = po + td, siendo t el parmetro que toma valores entre 0 y 1. d nos dene el vector direccin del rayo, que determinar la distancia mxima de clculo de la colisin. Po nos dene el punto de origen del rayo. Este valor de t que nos devuelve la query puede ser fcilmente convertido al punto de colisin en el espacio 3D. Shape Casting. El Shape Casting permite determinar los puntos de colisin de una forma que viaja en la direccin de un vector determinado. Es similar al Ray Casting, pero en este caso es necesario tener en cuenta dos posibles situaciones que pueden ocurrir: 1. La forma sobre la que aplicamos Shape Casting est inicialmente intersecando con al menos un objeto que evita que
Uso de Rayos
El Ray Casting se utiliza ampliamente en videojuegos. Por ejemplo, para comprobar si un personaje est dentro del rea de visin de otro personaje, para detectar si un disparo alcanza a un enemigo, para que los vehculos permanezcan en contacto con el suelo, etc.

Uso de Shape Casting


Un uso habitual de estas queries permite determinar si la cmara entra en colisin con los objetos de la escena, para ajustar la posicin de los personajes en terrenos irregulares, etc.

12.3. Dinmica del Cuerpo Rgido

[237]

c
Figura 12.16: Ejemplo de simulacin de cuerpos blandos con Bullet. a) Uso de softbodies con formas convexas. b) Simulacin de una tela sostenida por cuatro puntos. c) Simulacin de cuerdas.

Lista de colisiones
Para ciertas aplicaciones puede ser igualmente conveniente obtener la lista de todos los objetos con los que se interseca a lo largo de la trayectoria, como se muestra en la Figura 12.15.d).

se desplace desde su posicin inicial. En este caso el SDC devolver los puntos de contacto que pueden estar situados sobre la supercie o en el interior del volumen. 2. La forma no interseca sobre ningn objeto, por lo que puede desplazarse libremente por la escena. En este caso, el resultado de la colisin suele ser un punto de colisin situado a una determinada distancia del origen, aunque puede darse el caso de varias colisiones simultneas (como se muestra en la Figura 12.15). En muchos casos, los SDC nicamente devuelven el resultado de la primera colisin (una lista de estructuras que contienen el valor de t, el identicador del objeto con el que han colisionado, el punto de contacto, el vector normal de la supercie en ese punto de contacto, y algunos campos extra de informacin adicional).

12.3.

Dinmica del Cuerpo Rgido

La simulacin del movimiento de los objetos del juego forma parte del estudio de cmo las fuerzas afectan al comportamiento de los objetos. El mdulo del motor de simulacin que se encarga de la dinmica de los objetos estudia cmo cambian su posicin en el tiempo. Hasta hace pocos aos, los motores de simulacin fsica se centraban en estudiar exclusivamente la dinmica de cuerpos rgidos1 , que permite simplicar el clculo mediante dos suposiciones: Los objetos en la simulacin obedecen las leyes del movimiento de Newton (estudiadas en la Seccin 12.1.3). As, no se tienen en cuenta ningn tipo de efecto cuntico ni relativista. Todos los objetos que intervienen en la simulacin son perfectamente slidos y no se deforman. Esto equivale a armar que su forma es totalmente constante.
1 Aunque en la actualidad se encuentran soportadas de una forma muy eciente otras tcnicas, como se muestran en la Figura 12.16

[238]

CAPTULO 12. SIMULACIN FSICA

Restriccin Punto a Punto

Restriccin Muelle Rgido

Articulacin Bola

Articulacin Bisagra

Articulacin Prismtica Pistn

Figura 12.17: Representacin de algunas de las principales restricciones que pueden encontrarse en los motores de simulacin fsica.

En el clculo de la variacin de la posicin de los objetos con el tiempo, el motor de simulacin necesita resolver ecuaciones diferenciales, que cuentan como variable independiente el tiempo. La resolucin de estas ecuaciones habitualmente no puede realizarse de forma analtica (es imposible encontrar expresiones simples que relacionen las posiciones y velocidades de los objetos en funcin del tiempo), por lo que deben usarse mtodos de integracin numrica. Gracias a los mtodos de integracin numrica, es posible resolver las ecuaciones diferenciales en pasos de tiempo, de modo que la solucin en un instante de tiempo sirve como entrada para el siguiente paso de integracin. La duracin de cada paso de integracin suele mantenerse constante t. Uno de los mtodos ms sencillos que se pueden emplear es el de Euler, suponiendo que la velocidad del cuerpo es constante durante el incremento de tiempo. El mtodo tambin presenta buenos resultados cuando t es sucientemente pequeo. En trminos generales, este mtodo no es sucientemente preciso, y tiene problemas de convergencia y de estabilidad (el sistema se vuelve inestable, no converge y hace que la simulacin explote ). La alternativa ms utilizada en la actualidad es el mtodo de integracin de Verlet, por su bajo error y su eciencia computacional en la evaluacin de las expresiones.

12.4.

Restricciones

Las restricciones sirven para limitar el movimiento de un objeto. Un objeto sin ninguna restriccin tiene 6 grados de libertad. Las restricciones se usan en multitud de situaciones en desarrollo de videojuegos, como en puertas, suspensiones de vehculos, cadenas, cuerdas, etc. A continuacin enumeraremos brevemente los principales tipos de restricciones soportadas por los motores de simulacin fsica.

12.5. Introduccin a Bullet

[239] Punto a punto. Este es el tipo de restricciones ms sencillas; los objetos estn conectados por un punto. Los objetos tienen libertad de movimiento salvo por el hecho de que tienen que mantenerse conectados por ese punto. Muelle rgido. Un muelle rgido (Stiff Spring) funciona como una restriccin de tipo punto a punto salvo por el hecho de que los objetos estn separados por una determinada distancia. As, puede verse como unidos por una barra rgida que los separa una distancia ja. Bisagras. Este tipo de restriccin limitan el movimiento de rotacin en un determinado eje (ver Figura 12.17). Este tipo de restricciones pueden denir adems un lmite de rotacin angular permitido entre los objetos (para evitar, por ejemplo, que el codo de un brazo robtico adopte una posicin imposible). Pistones. Este tipo de restricciones, denominadas en general restricciones prismticas, permiten limitar el movimiento de traslacin a un nico eje. Estas restricciones podran permitir opcionalmente rotacin sobre ese eje. Bolas. Estas restricciones permiten denir lmites de rotacin exibles, estableciendo puntos de anclaje. Sirven por ejemplo para modelar la rotacin que ocurre en el hombro de un personaje. Otras restricciones. Cada motor permite una serie de restricciones especcas, como planares (que restringen el movimiento en un plano 2D), cuerdas, cadenas de objetos, rag dolls (denidas como una coleccin de cuerpos rgidos conectados utilizando una estructura jerrquica), etc...

12.5.

Introduccin a Bullet

Como se ha comentado al inicio del captulo, Bullet es una biblioteca de simulacin fsica muy utilizada, tanto en la industria del videojuego, como en la sntesis de imagen realista. Algunas de sus caractersticas principales son: Est desarrollada ntegramente en C++, y ha sido diseada de modo que tenga el menor nmero de dependencias externas posibles. Se distribuye bajo licencia Zlib (licencia libre compatible con GPL), y ha sido utilizada en proyectos profesionales en multitud de plataformas, entre las que destacan PlayStation 3, XBox 360, Wii, Linux, Windows, MacOSX, iPhone y Android. Cuenta con un integrador muy estable y rpido. Permite el clculo de dinmica de cuerpo rgido, dinmicas de vehculos y diversos tipos de restricciones (bisagras, pistones, bolas, etc...).

[240]

CAPTULO 12. SIMULACIN FSICA

Permite dinmica de SoftBodies, como telas, cuerdas y deformacin de volmenes arbitrarios. Las ltimas versiones permiten descargar algunos clculos a la GPU, empleando OpenCL. La utilizacin de esta funcionalidad se encuentra en fase experimental, y requiere la instalacin de versiones recientes de los drivers de la tarjeta grca. Est integrado en multitud de paquetes de sntesis de imagen realista (bien de forma interna o mediante plugins), como en Blender, Maya, Softimage, Houdini, Cinema4D, etc... Permite importar y exportar archivos Collada. Existen multitud de videojuegos comerciales que han utilizado Bullet como motor de simulacin fsica. Entre otros se pueden destacar Grand Theft Auto IV (de Red Dead Redemption), Free Realms (de Sony), HotWheels (de BattleForce), Blood Drive (de Activision) o Toy Story 3 (The Game) (de Disney). De igual forma, el motor se ha utilizado en pelculas profesionales, como Hancock (de Sony Pictures), Bolt de Walt Disney, Sherlock Holmes (de Framestore) o Shrek 4 (de DreamWorks). Muchos motores grcos y de videojuegos permiten utilizar Bullet. La comunidad ha desarrollado multitud de wrappers para facilitar la integracin en Ogre, Crystal Space, Irrlich y Blitz3D entre otros. En el diseo de Bullet se prest especial atencin en conseguir un motor fcilmente adaptable y modular. Tal y como se comenta en su manual de usuario, el desarrollador puede utilizar nicamente aquellos mdulos que necesite (ver Figura 12.19): Utilizacin exclusiva del componente de deteccin de colisiones. Utilizacin del componente de dinmicas de cuerpo rgido sin emplear los componentes de SoftBody. Utilizacin de pequeos fragmentos de cdigo de la biblioteca. Extensin de la biblioteca para las necesidades especcas de un proyecto. Eleccin entre utilizar precisin simple o doble, etc...

Figura 12.18: Multitud de videojuegos AAA utilizan Bullet como motor de simulacin fsica.

Dinmica Cuerpo R gido

Detecci!n de Colisiones
Contenedores, "esti!n de Memoria, Bib. Matemtica...

Figura 12.19: Esquema de los principales mdulos funcionales de Bullet.

12.5.1.

Pipeline de Fsicas de Cuerpo Rgido

Bullet dene el pipeline de procesamiento fsico como se muestra en la Figura 12.20. El pipeline se ejecuta desde la izquierda a la derecha, comenzando por la etapa de clculo de la gravedad, y nalizando con la integracin de las posiciones (actualizando la transformacin del mundo). Cada vez que se calcula un paso de la simulacin stepSimulation en el mundo, se ejecutan las 7 etapas denidas en la imagen anterior.

Plugins

Dinmica SoftBody

Bullet MultiHilo

.dea, .bsp, .obj...

12.5. Introduccin a Bullet

[241]

Inicio

Time Step

Time Step

Time Step

Time Step

Time Step

Fin

Dinmica
Aplicar Gravedad Predecir Transf.

Deteccin de Colisiones
Calcular AABBs Detectar Pares Puntos Contacto Definir Restricciones

Dinmica
Resolver Restricciones Integrar Posicin

Formas Colisin

AABBs Ob etos

Pares !uperpuestos

Puntos Contacto

"elocidades Transformadas

#asa Inercia

Restricciones Articulac.

Datos de Colisin

Datos de Dinmicas

Figura 12.20: Pipeline de Bullet. En la parte superior de la imagen se describen las principales etapas computacionales, y en la parte inferior las estructuras de datos ms importantes.

El Pipeline comienza aplicando la fuerza gravedad a los objetos de la escena. Posteriormente se realiza una prediccin de las transformaciones calculando la posicin actual de los objetos. Hecho esto se calculan las cajas AABBs, que darn una estimacin rpida de la posicin de los objetos. Con estas cajas se determinan los pares, que consiste en calcular si las cajas AABBs se solapan en algn eje. Si no hay ningn solape, podemos armar que no hay colisin. De otra forma, hay que realizar un estudio ms detallado del caso. Si hay posibilidad de contacto, se pasa a la siguiente etapa de calcular los contactos, que calcula utilizando la forma de colisin real del objeto el punto de contacto exacto. Estos puntos de contacto se pasan a la ltima etapa de clculo de la dinmica, que comienza con la resolucin de las restricciones, donde se determina la respuesta a la colisin empleando las restricciones de movimientos que se han denido en la escena. Finalmente se integran las posiciones de los objetos, obteniendo las posiciones y orientaciones nuevas para este paso de simulacin.
Tipos bsicos
Bullet cuenta con un subconjunto de utilidades matemticas bsicas con tipos de datos y operadores denidos como btScalar (escalar en punto otante), btVector3 (vector en el espacio 3D), btTransform (transformacin afn 3D), btQuaternion, btMatrix3x3...

Las estructuras de datos bsicas que dene Bullet se dividen en dos grupos: los datos de colisin, que dependen nicamente de la forma del objeto (no se tiene en cuenta las propiedades fscas, como la masa o la velocidad asociada al objeto), y los datos de propiedades dinmicas que almacenan las propiedades fsicas como la masa, la inercia, las restricciones y las articulaciones. En los datos de colisin se distinguen las formas de colisin, las cajas AABBs, los pares superpuestos que mantiene una lista de parejas de cajas AABB que se solapan en algn eje, y los puntos de contacto que han sido calculados como resultado de la colisin.

[242]

CAPTULO 12. SIMULACIN FSICA

12.5.2.

Hola Mundo en Bullet

Para comenzar, estudiaremos el Hola Mundo en Bullet, que denir una esfera que cae sobre un plano. Primero instalaremos las bibliotecas, que pueden descargarse de la pgina web del proyecto2 . Desde el directorio donde tengamos el cdigo descomprimido, ejecutamos:
cmake . -G "Unix Makefiles" -DINSTALL_LIBS=ON make sudo make install

Obviamente, es necesario tener instalado cmake para compilar la biblioteca. A continuacin estudiaremos el cdigo de la simulacin.
Listado 12.1: Hello World en Bullet.
1 #include <iostream> 2 #include <btBulletDynamicsCommon.h> 3 4 int main (void) { 5 btBroadphaseInterface* broadphase = new btDbvtBroadphase(); 6 btDefaultCollisionConfiguration* collisionConfiguration = 7 new btDefaultCollisionConfiguration(); 8 btCollisionDispatcher* dispatcher = new btCollisionDispatcher( 9 10

collisionConfiguration); btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver; btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver, collisionConfiguration); // Definicion de las propiedades del mundo --------------------dynamicsWorld->setGravity(btVector3(0,-10,0)); // Creacion de las formas de colision -------------------------btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1); btCollisionShape* fallShape = new btSphereShape(1); // Definicion de los cuerpos rigidos en la escena -------------btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1), btVector3(0,-1,0))); btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3 (0,0,0)); btRigidBody* gRigidBody = new btRigidBody(groundRigidBodyCI); dynamicsWorld->addRigidBody(gRigidBody); btDefaultMotionState* fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1), btVector3(0,50,0))); btScalar mass = 1; btVector3 fallInertia(0,0,0); fallShape->calculateLocalInertia(mass,fallInertia); btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass, fallMotionState,fallShape,fallInertia); btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI); dynamicsWorld->addRigidBody(fallRigidBody);

11 12 13 14 15 16 17 18 19 20 21

22 23 24 25 26 27 28 29 30 31 32 33 34

2 http://code.google.com/p/bullet/

12.5. Introduccin a Bullet

[243]

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 }

// Bucle principal de la simulacion ---------------------------for (int i=0 ; i<300 ; i++) { dynamicsWorld->stepSimulation(1/60.f,10); btTransform trans; fallRigidBody->getMotionState()->getWorldTransform(trans); std::cout << "Altura: " << trans.getOrigin().getY() << std:: endl; } // Finalizacion (limpieza) ---------------------------------dynamicsWorld->removeRigidBody(fallRigidBody); delete fallRigidBody->getMotionState(); delete fallRigidBody; dynamicsWorld->removeRigidBody(gRigidBody); delete gRigidBody->getMotionState(); delete gRigidBody; delete fallShape; delete groundShape; delete dynamicsWorld; delete solver; delete collisionConfiguration; delete dispatcher; delete broadphase; return 0;

Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: Altura: ...

49.9972 49.9917 49.9833 49.9722 49.9583 49.9417 49.9222 49.9 49.875 49.8472 49.8167 49.7833 49.7472 49.7083 49.6667

El ejemplo anterior podra compilarse con un sencillo makele como se muestra a continuacin:
Listado 12.2: Makele para hello world.
1 2 3 4 5 6 7

CXXFLAGS := pkg-config --cflags bullet LDLIBS := pkg-config --libs-only-l bullet all: HelloWorldBullet clean: rm HelloWorldBullet *~

Figura 12.21: Salida por pantalla de la ejecucin del Hola Mundo en Bullet.
60 50 40 30 20 10 0 50 100 150 200 250

Una vez compilado el programa de ejemplo, al ejecutarlo obtenemos un resultado puramente textual, como el mostrado en la Figura 12.21. Como hemos comentado anteriormente, los Bullet est diseado para permitir un uso modular. En este primer ejemplo no se ha hecho uso de ninguna biblioteca para la representacin grca de la escena. Si representamos los 300 valores de la altura de la esfera, obtenemos una grca como muestra la Figura 12.22. Como vemos, cuando la esfera (de 1 metro de radio) llega a un metro del suelo (medido desde el centro), rebota levemente y a partir del frame 230 aproximadamente se estabiliza. El primer include denido en la lnea 2 del programa anterior se encarga de incluir todos los archivos de cabecera necesarios para crear una aplicacin que haga uso del mdulo de dinmicas (cuerpo rgido, restricciones, etc...). Necesitaremos instanciar un mundo sobre el que realizar la simulacin. En nuestro caso crearemos un mundo discreto, que es el adecuado salvo que tengamos objetos de movimiento muy rpido sobre el que tengamos que hacer una deteccin de su movimiento (en cuyo caso podramos utilizar la clase an experimental btContinuousDynamicsWorld ).

Figura 12.22: Representacin de los valores obtenidos en el Hola Mundo.

[244]

CAPTULO 12. SIMULACIN FSICA

Y
Pr. B

a) B A

Y B A

b)

Y B A

c)

Figura 12.23: Aplicacin del Teorema de los Ejes Separados y uso con cajas AABB. a) La proyeccin de las formas convexas de los objetos A y B estn separadas en el eje X, pero no en el eje Y. Como podemos encontrar un eje sobre el que ambas proyecciones no intersecan, podemos asegurar que las formas no colisionan. b) El mismo principio aplicados sobre cajas AABB denidas en objetos cncavos, que no intersecan. c) La proyeccin de las cajas AABB se solapa en todos los ejes. Hay un posible caso de colisin entre formas.

Creacin del mundo Como vimos en la seccin 12.2.2, los motores de simulacin fsica utilizan varias capas para detectar las colisiones entre los objetos del mundo. Bullet permite utilizar algoritmos en una primera etapa (broadphase ) que utilizan las cajas lmite de los objetos del mundo para obtener una lista de pares de cajas que pueden estar en colisin. Esta lista es una lista exhaustiva de todas las cajas lmite que intersecan en alguno de los ejes (aunque, en etapas posteriores lleguen a descartarse porque en realidad no colisionan). Muchos sistemas de simulacin fsica se basan en el Teorema de los Ejes Separados. Este teorema dice que si existe un eje sobre el que la proyeccin de dos formas convexas no se solapan, entonces podemos asegurar que las dos formas no colisionan. Si no existe dicho eje y las dos formas son convexas, podemos asegurar que las formas colisionan. Si las formas son cncavas, podra ocurrir que no colisionaran (dependiendo de la suerte que tengamos con la forma de los objetos). Este teorema se puede visualizar fcilmente en 2 dimensiones, como se muestra en la Figura 12.23.a. El mismo teorema puede aplicarse para cajas AABB. Adems, el hecho de que las cajas AABB estn perfectamente alineadas con los ejes del sistema de referencia, hace que el clculo de la proyeccin de estas cajas sea muy rpida (simplemente podemos utilizar las coordenadas mnimas y mximas que denen las cajas). La Figura 12.23 representa la aplicacin de este teorema sobre cajas AABB. En el caso c) de dicha gura puede comprobarse que la proyeccin de las cajas se solapa en todos los ejes, por lo que tendramos un caso potencial de colisin. En realidad, como vemos en la gura las formas que contienen dichas cajas AABB no colisionan, pero este caso deber ser resuelto por algoritmos de deteccin de colisin de menor granularidad.

Pr. A

Proyeccin de A en X

Proyeccin de B en X

Ejemplo de AABBs que no intersecan

Ejemplo de AABBs que intersecan

12.5. Introduccin a Bullet

[245] En la lnea 5 creamos un objeto que implementa un algoritmo de optimizacin en una primera etapa broadphase. En posteriores etapas Bullet calcular las colisiones exactas. Existen dos algoritmos bsicos que implementa Bullet para mejorar al aproximacin a ciegas de complejidad O(n2 ) que comprobara toda la lista de pares. Estos algoritmos aaden nuevas parejas de cajas que en realidad no colisionan, aunque en general mejoran el tiempo de ejecucin. rbol AABB Dinmico. Este algoritmo est implementado en la clase btDbvtBroadphase. Se construye un rbol AABB de propsito general que se utiliza tanto en la primera etapa de optimizacin broadphase como en la deteccin de colisiones entre softbodies. Este tipo de arbol se adapta automticamente a las dimensiones del mundo, y la insercin y eliminacin de objetos es ms rpido que en SAP. Barrido y Poda (SAP ). La implementacin de Sweep and Prune de Bullet requiere que el tamao del mundo sea conocido de previamente. Este mtodo es el que tiene mejor comportamiento en mundos dinmicos donde la mayora de los objetos tienen poco movimiento. Se implementa en el conjunto de clases AxisSweep (con versiones de diverso nivel de precisin). Tras esta primera poda, hemos eliminado gran de objetos cantidad que no colisionan. A continuacin, en las lneas 6-8 se crea un objeto de conguracin de la colisin, que nos permitir adaptar los parmetros de los algoritmos utilizados en posteriores fases para comprobar la colisin. El btCollisionDispatcher es una clase que permite aadir funciones de callback para ciertos tipos de eventos (como por ejemplo, cuando los objetos se encuentren cerca ). ) se encarga de que los objetos interacten El objeto solver (lnea 9 adecuadamente, teniendo en cuenta la gravedad, las fuerzas, colisiones y restricciones. En este ejemplo se ha utilizado la versin secuencial (que implementa el mtodo de Gauss Seidel proyectado (PGS), para resolver problemas lineales), aunque existen versiones que hacen uso de paralelismo empleando hilos. En la lnea 10 se instancia el mundo. Este objeto nos permitir aadir los objetos del mundo, aplicar gravedad, y avanzar el paso de la simulacin. En concreto, en la lnea 12 se establece una de las propiedades del mundo, la gravedad, asignando un valor de 10m/s en el eje Y, por lo que se aplicar sobre ese eje la fuerza de gravedad. Al nalizar, Bullet requiere que el usuario libere la memoria que ha utilizado explcitamente. De esta forma, a partir de la lnea 42 se eliminan todos los elementos que han sido creados a lo largo de la simulacin. Hasta aqu hemos denido lo que puede ser el esqueleto bsico de una aplicacin mnima de Bullet. Vamos a denir a continuacin los objetos que forman nuestra escena y el bucle de simulacin.

Figura 12.24: El objeto solver se encargar de resolver la interaccin entre objetos.

Reutiliza!!
Es buena prctica reutilizar formas de colisin. Si varios objetos de la escena pueden compartir la misma forma de colisin (por ejemplo, todos los enemigos pueden gestionarse con una misma esfera de un determinado radio), es buena prctica compartir esa forma de colisin entre todos ellos.

[246] Formas de Colisin

CAPTULO 12. SIMULACIN FSICA

Como hemos comentado al inicio de la seccin, crearemos un objeto plano que servir como suelo sobre el que dejaremos caer una esfera. Cada uno de estos cuerpos necesita una forma de colisin, que internamente nicamente se utiliza para calcular la colisin (no tiene propiedades de masa, inercia, etc...). Las formas de colisin no tienen una posicin en el mundo; se adjuntan a los cuerpos rgidos. La eleccin de la forma de colisin adecuada, adems de mejorar el rendimiento de la simulacin, ayuda a conseguir una simulacin de calidad. Bullet permite el uso de primitivas (que implementan algoritmos de deteccin de colisiones muy optimizados) o mallas poligonales. Las primitivas soportadas por Bullet son: btSphereShape. Esfera; la primitiva ms simple y rpida. btBoxShape. La caja puede tener cualquier relacin de aspecto. btCylinderShape. Cilindro con cualquier relacin de aspecto. btCapsuleShape. Cpsula con cualquier relacin de aspecto. btConeShape. Los conos se denen con el vrtice en el (0,0,0). btMultiSphereShape. Forma convexa especial denida como combinacin de esferas. btCompoundShape. No es una primitiva bsica en s, sino que permite combinar formas de cualquier tipo (tanto primitivas como formas de colisin de tipo malla que veremos a continuacin). Permite obtener formas compuestas, como la que se estudi en la Figura 12.14. Las formas de colisin de tipo malla soportadas son: btConvexHull. Este es el tipo de forma de tipo malla ms rpido. Se dene como una nube de vrtices que forman la forma convexa ms pequea posible. El nmero de vrtices debe ser pequeo para que la forma funcione adecuadamente. El nmero de vrtices puede reducirse empleando la utilidad proporcionada por la clase btShapeHull. Existe una versin similar a este tipo llamado btConvexTriangleMeshShape, que est formado por caras triangulares, aunque es deseable utilizar btConvexHull porque es mucho ms eciente. btBvhTriangleMeshShape. Malla triangular esttica. Puede tener un nmero considerable de polgonos, ya que utiliza una jerarqua interna para calcular la colisin. Como la construccin de esta estructura de datos puede llevar tiempo, se recomienda serializar el rbol para cargarlo rpidamente. Bullet incorpora utilidades para la serializacin y carga del rbol BVH.

12.5. Introduccin a Bullet

[247] btHeighteldTerrainShape. Malla poligonal esttica optimizada descrita por un mapa de alturas. btStaticPlaneShape. Plano innito esttico. Se especica mediante un vector de direccin y una distancia respecto del origen del sistema de coordenadas.

Algunos consejos sobre el uso de formas de colisin en Bullet: Trata de utilizar las formas de colisin ms ecientes: esferas, cajas, cilindros y ConvexHull. Los objetos dinmicos deben tener una forma cerrada y denida por un volumen nito. Algunas formas de colisin como los planos o las triangleMesh no tienen un volumen nito, por lo que nicamente pueden ser usados como cuerpos estticos. Reutiliza siempre que sea posible las formas de colisin.

En la lnea 16-17 creamos una forma de colisin de tipo plano, pasando como parmetro el vector normal del plano (vector unitario en Y), y una distancia respecto del origen. As, el plano de colisin queda denido por la ecuacin y = 1. De igual modo, la forma de colisin del cuerpo que dejaremos caer sobre el suelo ser una esfera de radio 1 metro (lnea 18 ). Una vez denidas las formas de colisin, las posicionaremos asocindolas a instancias de cuerpos rgidos. En la siguiente subseccin aadiremos los cuerpos rgidos al mundo. Cuerpos Rgidos Para aadir cuerpos rgidos, necesitamos primero denir el concepto de MotionState en Bullet. Un MotionState es una abstraccin proporcionada por Bullet para actualizar la posicin de los objetos que sern dibujados en el game loop. Empleando MotionStates, Bullet se encargar de actualizar los objetos que sern representados por el motor grco. En la siguiente seccin estudiaremos cmo trabajar con MotionStates en Ogre.
MotionState propio
Para implementar nuestro propio MotionState basta con heredar de btMotionState y sobreescribir los mtodos getWorldTransform y setWorldTransform.

Gracias al uso de MotionStates, nicamente se actualiza la posicin de los objetos que se han movido. Bullet se encarga adems de la interpolacin de movimientos, aislando al programador de esta tarea. Cuando se consulte la posicin de un objeto, por defecto se devolver la correspondiente al ltimo paso de simulacin calculado. Sin embargo, cada vez que el motor grco necesite redibujar la escena, Bullet se encargar de devolver la transformacin interpolada. Los MotionStates deben utilizarse en dos situaciones:

[248]

CAPTULO 12. SIMULACIN FSICA

1. Cuando se crea un cuerpo. Bullet determina la posicin inicial del cuerpo en el momento de su creacin, y requiere una llamada al MotionState. 2. Cuando se quiera actualizar la posicin del objeto. Bullet proporciona un MotionState por defecto que podemos utili zar para instanciar cuerpos rgidos. As, en la lnea 21 se utiliza el MotionState por defecto especicando como rotacin la identidad, y trasladando el origen -1 unidad en Y 3 . En las lneas 22-23 se emplea la estructura btRigidBodyConstructionInfo para establecer la informacin para crear un cuerpo rgido.

Los componentes de la estructura btRigidBodyConstructionInfo se copian a la informacin del cuerpo cuando se llama al constructor. Si queremos crear un grupo de objetos con las mismas propiedades, puede crearse una nica estructura de este tipo y pasarla al constructor de todos los cuerpos.

El primer parmetro es la masa del objeto. Estableciendo una masa igual a cero (primer parmetro), se crea un objeto esttico (equivale a establecer una masa innita, de modo que el objeto no se puede mover). El ltimo parmetro es la inercia del suelo (que se establece igualmente a 0, por ser un objeto esttico). En la lnea 24 creamos el objeto rgido a partir de la informacin almacenada en la estructura anterior, y lo aadimos al mundo en la . lnea 25 La creacin de la esfera sigue un patrn de cdigo similar. En la lnea 27 se crea el MotionState para el objeto que dejaremos caer, situado a 50 metros del suelo (lnea 28 ). En las lneas 29-31 se establecen las propieades del cuerpo; una masa de 1Kg y se llama a un mtodo de btCollisionShape que nos calcula la inercia de una esfera a partir de su masa. Bucle Principal Para nalizar, el bucle principal se ejecuta en las lneas 36-41 . El bucle se ejecuta 300 veces, llamando al paso de simulacin con un intervalo de 60hz. En cada paso de la simulacin se imprime la altura de la esfera sobre el suelo. Como puede verse, la posicin y la orientacin del objeto dinmico se encapsulan en un objeto de tipo btTransform. Como se coment anteriormente, esta informacin puede obtenerse a partir del MotionS3 Esta traslacin se realiza a modo de ejemplo para compensar la traslacin de 1 unidad cuando se cre la forma de colisin del plano. El resultado sera el mismo si en ambos parmetros se hubiera puesto 0.

12.5. Introduccin a Bullet

[249] tate asociado al btRigidBody a travs de la estructura de inicializacin btRigidBodyConstructInfo. ) requieEl mtodo para avanzar un paso en la simulacin (lnea 38 re dos parmetros. El primero describe la cantidad de tiempo que queremos avanzar la simulacin. Bullet tiene un reloj interno que permite mantener constante esta actualizacin, de forma que sea independiente de la tasa de frames de la aplicacin. El segundo parmetro es el nmero de subpasos que debe realizar bullet cada vez que se llama stepSimulation. Los tiempos se miden en segundos. El primer parmetro debe ser siempre menor que el nmero de subpasos multiplicado por el tiempo jo de cada paso tStep < maxSubStep tF ixedStep .

Tiempos!
Cuidado, ya que las funciones de clculo de tiempo habitualmente devuelven los resultados en milisegundos. Bullet trabaja en segundos, por lo que sta es una fuente habitual de errores.

Supongamos que queremos un tiempo jo de simulacin en cada paso de 60hz. En el mejor de los casos, nuestro videojuego tendr una tasa de 120fps (120hz), y en el peor de los casos de 12fps. As, tStep en el primer caso ser 1/120 = 0,0083, y en el segundo tStep = 1/12 = 0,083. Por su parte, el tiempo del paso jo para la simulacin sera 1/60 = 0,017. Para que la expresin anterior se cumpla, en el primer caso el nmero de subpasos basta con 1 0,0083 < 1 0,017. En el peor de los casos, necesitaremos que el nmero de pasos sea al menos de 5 para que se cumpla la expresin 0,083 < 5 0,017. Con estas condiciones tendramos que establecer el nmero de subpasos a 5 para no perder tiempo de simulacin

No olvides...
Cuando cambies el valor de los tiempos de simulacin, recuerda calcular el nmero de subpasos de simulacin para que la ecuacin siga siendo correcta.

Decrementando el tamao de cada paso de simulacin se est aumentado la resolucin de la simulacin fsica. De este modo, si en el juego hay objetos que atraviesan objetos (como paredes), es posible decrementar el xedTimeStep para aumentar la resolucin. Obviamente, cuando se aumenta la resolucin al doble, se necesitar aumentar el nmero de maxSubSteps al doble, lo que requerir aproximadamente el doble de tiempo de CPU para el mismo tiempo de simulacin fsica. Cuando se especica un valor de maxSubSteps > 1, Bullet interpolar el movimiento (y evitar al programador tener que realizar los clculos). Si maxSubSteps == 1, no realizar interpolacin.

[250]

CAPTULO 12. SIMULACIN FSICA

12.6.

Integracin manual en Ogre

Como se ha estudiado en la seccin anterior, los MotionStates se denen en Bullet para abstraer la representacin de los rigidBody en el motor de dibujado. A continuacin deniremos manualmente una clase MyMotionState que se encargar de la actualizacin de las entidades en Ogre. La implementacin de un MotionState propio debe heredar de la clase btMotionState de bullet, y sobreescribir los mtodos getWorldTransform y setWorldTransform (por lo que se denen como virtuales). Ambos mtodos toman como parmetro un objeto de la clase btTransform, que se utiliza para la representacin interna de transformaciones de cuerpo rgido. El siguiente listado muestra la declaracin de la clase, que tiene dos variables miembro; el nodo asociado a ese MotionState (que tendremos que actualizar en setWorldTransform ), y la propia transformacin que devolveremos en getWorldTransform (lnea 7 ).
Listado 12.3: MyMotionState.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

btTransform
Las transformaciones de cuerpo rgido estn formadas nicamente por traslaciones y rotaciones (sin escalado). As, esta clase utiliza internamente un btVector3 para la traslacin y una matriz 3x3 para almacenar la rotacin.

#include <Ogre.h> #include <btBulletDynamicsCommon.h> class MyMotionState : public btMotionState { protected: Ogre::SceneNode* _visibleobj; btTransform _pos; public: MyMotionState(const btTransform &initialpos, Ogre::SceneNode* node); virtual ~MyMotionState(); void setNode(Ogre::SceneNode* node); virtual void getWorldTransform(btTransform &worldTr) const; virtual void setWorldTransform(const btTransform &worldTr); };

La denicin de la clase es directa. El siguiente listado muestra los mtodos ms importantes en su implementacin (el destructor no tiene que eliminar el nodo; se encargar Ogre al liberar los recursos). En las lneas 15-19 se dene el mtodo principal, que actualiza la posicin y rotacin del SceneNode en Ogre. Dado que Bullet y Ogre denen clases distintas para trabajar con Vectores y Cuaternios, es necesario obtener la rotacin y posicin del objeto por separado y asignarlo alnodo mediante las llamadas a setOrientation y setPosition (lneas 17 ). y 19 La llamada a setWorldTransform puede retornar en la lnea 15 si no se ha establecido nodo en el constructor. Se habilita un mtodo especco para establecer el nodo ms adelante. Esto es interesante si se quieren aadir objetos a la simulacin que no tengan representacin grca.

12.6. Integracin manual en Ogre

[251]

Listado 12.4: MyMotionState.cpp


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

#include "MyMotionState.h" MyMotionState::MyMotionState(const btTransform &initialpos, Ogre::SceneNode *node) { _visibleobj = node; _pos = initialpos; } void MyMotionState::setNode(Ogre::SceneNode *node) { _visibleobj = node; } void MyMotionState::getWorldTransform (btTransform &worldTr) const { worldTr = _pos; } void MyMotionState::setWorldTransform(const btTransform &worldTr){ if(NULL == _visibleobj) return; // Si no hay nodo, return btQuaternion rot = worldTr.getRotation(); _visibleobj->setOrientation(rot.w(), rot.x(), rot.y(), rot.z()); btVector3 pos = worldTr.getOrigin(); _visibleobj->setPosition(pos.x(), pos.y(), pos.z()); }

Una vez creada la clase que utilizaremos para denir el MotionState, la utilizaremos en el Hola Mundo construido en la seccin anterior para representar la simulacin con el plano y la esfera. El resultado que tendremos se muestra en la Figura 12.25. Para la construccin del ejemplo emplearemos como esqueleto base el FrameListener del Mdulo 2 del curso.
Figura 12.25: Fragmento del resultado de integracin del Hola Mundo de Bullet en Ogre, empleando la clase de MyMotionState denida anteriormente.

Listado 12.5: MyFrameListener.cpp


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

#include "MyFrameListener.h" #include "MyMotionState.h" MyFrameListener::MyFrameListener(RenderWindow* win, Camera* cam, OverlayManager *om, SceneManager *sm) { // .... Omitida parte de la inicializacion _broadphase = new btDbvtBroadphase(); _collisionConf = new btDefaultCollisionConfiguration(); _dispatcher = new btCollisionDispatcher(_collisionConf); _solver = new btSequentialImpulseConstraintSolver; _world = new btDiscreteDynamicsWorld(_dispatcher,_broadphase, _solver,_collisionConf); _world->setGravity(btVector3(0,-10,0)); CreateInitialWorld(); } MyFrameListener::~MyFrameListener() { _world->removeRigidBody(_fallRigidBody); delete _fallRigidBody->getMotionState(); delete _fallRigidBody; // ... Omitida la eliminacion de los objetos } void MyFrameListener::CreateInitialWorld() { // Creacion de la entidad y del SceneNode ----------------------Plane plane1(Vector3::Vector3(0,1,0), 0); MeshManager::getSingleton().createPlane("p1", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane1, 200, 200, 1, 1, true, 1, 20, 20, Vector3::UNIT_Z); SceneNode* node = _sceneManager->createSceneNode("ground"); Entity* groundEnt = _sceneManager->createEntity("planeEnt","p1");

[252]

CAPTULO 12. SIMULACIN FSICA

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

groundEnt->setMaterialName("Ground"); node->attachObject(groundEnt); _sceneManager->getRootSceneNode()->addChild(node); // Creamos las formas de colision ------------------------------_groundShape = new btStaticPlaneShape(btVector3(0,1,0),1); _fallShape = new btSphereShape(1); // Creamos el plano --------------------------------------------MyMotionState* groundMotionState = new MyMotionState( btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)), node); btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI (0,groundMotionState,_groundShape,btVector3(0,0,0)); _groundRigidBody = new btRigidBody(groundRigidBodyCI); _world->addRigidBody(_groundRigidBody); // Creamos la esfera -------------------------------------------Entity *entity2= _sceneManager->createEntity("ball","ball.mesh"); SceneNode *node2= _sceneManager->getRootSceneNode()-> createChildSceneNode(); node2->attachObject(entity2); MyMotionState* fallMotionState = new MyMotionState( btTransform(btQuaternion(0,0,0,1),btVector3(0,50,0)), node2); btScalar mass = 1; btVector3 fallInertia(0,0,0); _fallShape->calculateLocalInertia(mass,fallInertia); btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI( mass,fallMotionState,_fallShape,fallInertia); _fallRigidBody = new btRigidBody(fallRigidBodyCI); _world->addRigidBody(_fallRigidBody); } bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { Real deltaT = evt.timeSinceLastFrame; int fps = 1.0 / deltaT; _world->stepSimulation(deltaT, 5); // Actualizar fisica

_keyboard->capture(); if (_keyboard->isKeyDown(OIS::KC_ESCAPE)) return false; btVector3 impulse; if (_keyboard->isKeyDown(OIS::KC_I)) impulse=btVector3(0,0,-.1); if (_keyboard->isKeyDown(OIS::KC_J)) impulse=btVector3(-.1,0,0); if (_keyboard->isKeyDown(OIS::KC_K)) impulse=btVector3(0,0,.1); if (_keyboard->isKeyDown(OIS::KC_L)) impulse=btVector3(.1,0,0); _fallRigidBody->applyCentralImpulse(impulse); // Omitida parte del codigo fuente (manejo del raton, etc...) return true; } bool MyFrameListener::frameEnded(const Ogre::FrameEvent& evt) { Real deltaT = evt.timeSinceLastFrame; _world->stepSimulation(deltaT, 5); // Actualizar fisica return true; }

En la implementacin del FrameListener es necesario mantener como variables miembro el conjunto de objetos necesarios en la simula cin de Bullet. As, la implementacin del constructor (lneas 4-15 dene los objetos necesarios para crear el mundo de simulacin de Bullet (lnea 11-12 ). Estos objetos sern liberados en el destructor de la clase (ver lneas 17-22 ). De igual modo, los dos cuerpos rgidos que intervie-

12.7. Hola Mundo en OgreBullet

[253]

Variables miembro
Mantener los objetos como variables miembro de la clase no deja de ser una mala decisin de diseo. En la seccin 12.7 veremos cmo se gestionan listas dinmicas con los objetos y las formas de colisin.

nen en la simulacin y sus formas asociadas son variables miembro de la clase. ) se realiza El mtodo CreateInitialWorld (denido en las lneas 24-60 como ltimo paso en el constructor. En este mtodo se aaden a la escena de Ogre y al mundo de Bullet los elementos que intervendrn en la simulacin (en este caso la esfera y el plano). La creacin las de entidades y los nodos para el plano y la esfera (lneas 26-34 y 49-51 respectivamente) ya han sido estudiadas en el Mdulo 2 del curso. La creacin de las formas para el plano y la esfera ) fueron descritas en el cdigo de la seccin (lneas 37-38 anterior. Cabe destacar que la malla exportada en ball.mesh (lnea 49 ) debe tener un radio de 1 unidad, para que la forma de colisin denida en la lnea 38 se adapte bien a su representacin grca. Cada objeto tendr asociado un MotionState de la clase denida anteriormente, que recibir la rotacin y traslacin inicial, y el puntero al nodo que guarda la entidad a representar. En el caso del plano, se , y la esfera en 52-53 . dene en las lneas 41-42 Por ltimo, tendremos que aadir cdigo especco en los mtodos de retrollamada de actualizacin del frame. En el se listado anterior muestra el cdigo de frameStarted (lneas 62-86 ). En la lnea 66 se actualiza el paso de simulacin de Bullet, empleando el tiempo transcurridodesde Adems, si el usuario pulsa las la ltima actualizacin. teclas I , J , K o L (lneas 71-76 ), se aplicar una fuerza sobre la esfera. Veremos ms detalles sobre la aplicacin de impulsos a los objetos en el ejemplo de la seccin 12.8. Para nalizar, se muestran los ags del Makele necesarios para integrar Bullet en los ejemplos anteriores.
Listado 12.6: Fragmento de Makele
1 # Flags de compilacion ------------------------------------------2 CXXFLAGS := -I $(DIRHEA) -Wall pkg-config --cflags OGRE pkg-

Actualizacin del mundo


En el ejemplo anterior, se actualiza el paso de simulacin igualmente en el mtodo frameEnded. Bullet se encarga de interpolar las posiciones de dibujado de los objetos. Si se elimina la llamada a stepSimulation, el resultado de la simulacin es mucho ms brusco.

config

--cflags bullet

3 4 # Flags del linker ----------------------------------------------5 LDFLAGS := pkg-config --libs-only-L OGRE pkg-config --libs-only-

bullet bullet -lOIS -lGL -lstdc++

6 LDLIBS := pkg-config --libs-only-l OGRE pkg-config --libs-only-l

12.7.

Hola Mundo en OgreBullet

El desarrollo de un wrapper completo del motor Bullet puede ser una tarea costosa. Afortunadamente existen algunas alternativas que facilitan la integracin del motor en Ogre, como el proyecto OgreBullet. OgreBullet se distribuye bajo una licencia MIT libre, y es multiplataforma. Segn el autor, OgreBullet puede ser considerado un wrapper en versin estable. La noticacin de bugs, peticin de nuevos requisitos

[254]

CAPTULO 12. SIMULACIN FSICA

y ejemplos se mantiene en un apartado especco de los foros de Ogre 4 . Uno de los principales problemas relativos al uso de este wrapper es la falta de documentacin, por lo que en algunos casos la nica alternativa es la consulta de los archivos de cabecera de la distribucin.

OgreBullet puede descargarse de la pgina de complementos ocial de Ogre en: http://ogreaddons.svn.sourceforge. net/viewvc/ogreaddons/trunk/ogrebullet/?view=tar

En el siguiente ejemplo crearemos una escena donde se aadirn de forma dinmica cuerpos rgidos. Adems de un puntero al DynamicsWorld (variable miembro _world ), el FrameListener mantiene un ), que nos permite reprepuntero a un objeto _debugDrawer (lnea 7 sentar cierta informacin visual que facilita el depurado de la aplicacin. En este primer ejemplo se activa el dibujado de las formas de colisin (lnea 8 ), tal y como se muestra en la Figura 12.26. Este objeto permite aadir otros elementos que faciliten la depuracin, como lneas, puntos de contacto, cajas AABBs, etc. Los mtodos relativos a la representacin de texto 3D en modo depuracin estn previstos pero an no se encuentran desarrollados. Este objeto de depuracin debe ser aadido igualmente al grafo de escena de Ogre (lneas 9-11 del siguiente listado). La denicin del mundo en OgreBullet que se especiquen requiere los lmites de simulacin. En las lneas 14-15 se crea una caja AABB descrita por los vrtices de sus esquinas que dene el volumen en el que se realizar la simulacin fsica. Este lmite, con el vector de junto gravedad, permitirn crear el mundo (lneas 18-19 ).
Listado 12.7: Constructor
1 MyFrameListener::MyFrameListener(RenderWindow* win, 2 Camera* cam, OverlayManager *om, SceneManager *sm) { 3 _numEntities = 0; // Numero de Formas instanciadas 4 _timeLastObject = 0; // Tiempo desde ultimo objeto anadido 5 6 // Creacion del modulo de debug visual de Bullet --------------7 _debugDrawer = new OgreBulletCollisions::DebugDrawer(); 8 _debugDrawer->setDrawWireframe(true); 9 SceneNode *node = _sceneManager->getRootSceneNode()-> 10 createChildSceneNode("debugNode", Vector3::ZERO); 11 node->attachObject(static_cast<SimpleRenderable*>(_debugDrawer)); 12 // Creacion del mundo (definicion de los limites y la gravedad) 13 AxisAlignedBox worldBounds = AxisAlignedBox 14 (Vector3(-10000,-10000,-10000), Vector3(10000,10000,10000)); 15 Vector3 gravity = Vector3(0, -9.8, 0); 16 _world = new OgreBulletDynamics::DynamicsWorld(_sceneManager, 17 worldBounds, gravity); 18 _world->setDebugDrawer (_debugDrawer); 19 _world->setShowDebugShapes (true); // Muestra formas debug 20 CreateInitialWorld(); // Inicializa el mundo 21 }
4 Foros

Figura 12.26: Salida del primer ejemplo con OgreBullet. El objeto _debugDrawer muestra las formas de colisin asociadas a las entidades de Ogre.

OgreBullet: http://www.ogre3d.org/addonforums/viewforum.php?f=12

12.7. Hola Mundo en OgreBullet

[255]

El FrameListener mantiene dos colas de doble n (deque ) de punteros a los RigidBody (_bodies) y a las CollisionShape (_shapes), que facilitan la insercin y borrado de elementos de un modo ms rpido que los vectores. As, cuando se aadan objetos de forma dinmica a la escena, ser necesario aadirlos a estas estructuras para su posterior liberacin en el destructor de la clase. El siguiente listado muestra la implementacin del destructor del FrameListener. De igual modo es necesario liberar los recursos asociados al mundo ). dinmico y al debugDrawer creado en el constructor (ver lneas 16-17
Listado 12.8: Destructor
1 MyFrameListener::~MyFrameListener() { 2 // Eliminar cuerpos rigidos -----------------------------------3 std::deque <OgreBulletDynamics::RigidBody *>::iterator 4 itBody = _bodies.begin(); 5 while (_bodies.end() != itBody) { 6 delete *itBody; ++itBody; 7 } 8 // Eliminar formas de colision --------------------------------9 std::deque<OgreBulletCollisions::CollisionShape *>::iterator 10 itShape = _shapes.begin(); 11 while (_shapes.end() != itShape) { 12 delete *itShape; ++itShape; 13 } 14 _bodies.clear(); _shapes.clear(); 15 // Eliminar mundo dinamico y debugDrawer ----------------------16 delete _world->getDebugDrawer(); _world->setDebugDrawer(0); 17 delete _world; 18 }

Para aadir un objeto de simulacin de OgreBullet debemos crear dos elementos bsicos; por un lado la CollisionShape (lneas ), y 14-16 ). por otro lado el RigidBody (lneas 17-18 La asociacin del nodo de dibujado con el cuerpo rgido se establece en la misma llamada en la que se asocia la forma de colisin al RigidBody. En la clase OgreBulletDynamics::RigidBody existen dos mtodos que permiten asociar una forma de colisin a un RigidBody; setShape y setStaticShape. La segunda cuenta con varias versiones; una de ellas no requiere especicar el SceneNode, y se corresponde con la utilizada en la lnea 21 para aadir la forma de colisin al plano.
Aadir a las colas
Una vez aadido el objeto, deben aadirse las referencias a la forma de colisin y al cuerpo rgido en las colas de la clase (lnea 24).

Listado 12.9: CreateInitialWorld


1 void MyFrameListener::CreateInitialWorld() { 2 // Creacion de la entidad y del SceneNode ----------------------3 Plane plane1(Vector3::Vector3(0,1,0), 0); 4 MeshManager::getSingleton().createPlane("p1", 5 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane1, 6 200, 200, 1, 1, true, 1, 20, 20, Vector3::UNIT_Z); 7 SceneNode* node= _sceneManager->createSceneNode("ground"); 8 Entity* groundEnt= _sceneManager->createEntity("planeEnt", "p1"); 9 groundEnt->setMaterialName("Ground"); 10 node->attachObject(groundEnt); 11 _sceneManager->getRootSceneNode()->addChild(node); 12 13 // Creamos forma de colision para el plano ----------------------

[256]

CAPTULO 12. SIMULACIN FSICA

14 15 16 17 18 19 20 21 22 23 24 25 }

OgreBulletCollisions::CollisionShape *Shape; Shape = new OgreBulletCollisions::StaticPlaneCollisionShape (Ogre::Vector3(0,1,0), 0); // Vector normal y distancia OgreBulletDynamics::RigidBody *rigidBodyPlane = new OgreBulletDynamics::RigidBody("rigidBodyPlane", _world); // Creamos la forma estatica (forma, Restitucion, Friccion) ---rigidBodyPlane->setStaticShape(Shape, 0.1, 0.8); // Anadimos los objetos Shape y RigidBody ---------------------_shapes.push_back(Shape); _bodies.push_back(rigidBodyPlane);

La actualizacin del mundo se realiza de forma similar a la estudiada anteriormente. La aplicacin de ejemplo aadir adems, permite ). A continuaobjetos dinmicos cuando se pulse la tecla B (lnea 9 cin veremos el cdigo para aadir cuerpos dinmicos.
Listado 12.10: FrameStarted
1 bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { 2 Ogre::Real deltaT = evt.timeSinceLastFrame; 3 _world->stepSimulation(deltaT); // Actualizar simulacion Bullet 4 _timeLastObject -= deltaT; 5 6 _keyboard->capture(); 7 if (_keyboard->isKeyDown(OIS::KC_ESCAPE)) return false; 8 if ((_keyboard->isKeyDown(OIS::KC_B)) && (_timeLastObject <= 0)) 9 AddDynamicObject(); 10 // Omitido el resto del cogido del metodo ... 11 return true; 12 }

stepSimulation
La llamada a stepSimulation en OgreBullet acepta dos parmetros opcionales, el nmero de subpasos de simulacin (por defecto a 1), y el xedTimeStep (por defecto 1/60).

El siguiente listado implementa la funcionalidad de aadir cajas dinmicas a la escena. Los objetos se crearn teniendo en cuenta la posicin y rotacin de la cmara. Para ello, se toma como vector de posicin inicial el calculado como la posicin de lacmara desplazada 10 unidades segn su vector direccin (lneas 5-6 ).
Listado 12.11: AddDynamicObject
1 void MyFrameListener::AddDynamicObject() { 2 _timeLastObject = 0.25; // Segundos para anadir uno nuevo... 3 4 Vector3 size = Vector3::ZERO; // Tamano y posicion inicial 5 Vector3 position = (_camera->getDerivedPosition() 6 + _camera->getDerivedDirection().normalisedCopy() * 10); 7 8 // Creamos la entidad y el nodo de la escena ------------------9 Entity *entity = _sceneManager->createEntity("Box" + 10 StringConverter::toString(_numEntities), "cube.mesh"); 11 entity->setMaterialName("cube"); 12 SceneNode *node = _sceneManager->getRootSceneNode()-> 13 createChildSceneNode(); 14 node->attachObject(entity); 15 16 // Obtenemos la bounding box de la entidad creada -------------17 AxisAlignedBox boundingB = entity->getBoundingBox(); 18 size = boundingB.getSize(); 19 size /= 2.0f; // Tamano en Bullet desde el centro (la mitad)

12.8. RayQueries

[257]

20 21 22 23 24 25 26 27 28 29 30 31 32 33 }

OgreBulletCollisions::BoxCollisionShape *boxShape = new OgreBulletCollisions::BoxCollisionShape(size); OgreBulletDynamics::RigidBody *rigidBox = new OgreBulletDynamics::RigidBody("rigidBox" + StringConverter::toString(_numEntities), _world); rigidBox->setShape(node, boxShape, /* Restitucion, Friccion, Masa */ 0.6, 0.6, 5.0, /* Pos. y Orient. */ position , Quaternion::IDENTITY); rigidBox->setLinearVelocity( _camera->getDerivedDirection().normalisedCopy() * 7.0); _numEntities++; // Anadimos los objetos a las deques --------------------------_shapes.push_back(boxShape); _bodies.push_back(rigidBox);

En el listado anterior, el nodo asociado a cada caja se aade en ). Pese a que Bullet soporta mulla llamada a setShape (lneas 25-27 titud de propiedades en la estructura btRigidBodyConstructionInfo, el wrapper se centra exclusivamente en la denicin de la masa, y los coecientes de friccin y restitucin. La posicin inicial y el cuaternio se indican igualmente en la llamada al mtodo, que nos abstrae de la necesidad de denir el MotionState. Las cajas se aaden a la escena con una velocidad lineal relativa a la rotacin de la cmara (ver lneas 28-29 ).

12.8.

RayQueries

Al inicio del captulo estudiamos algunos tipos de preguntas que podan realizarse al motor de simulacin fsica. Uno de ellos eran los RayQueries que permitan obtener las formas de colisin que intersecaban con un determinado rayo.
Ogre? Bullet?
Recordemos que los objetos de simulacin fsica no son conocidos por Ogre. Aunque en el mdulo 2 del curso estudiamos los RayQueries en Ogre, es necesario realizar la pregunta en Bullet para obtener las referencias a los RigidBody.

Utilizaremos esta funcionalidad del SDC para aplicar un determinado impulso al primer objeto que sea tocado por el puntero del ratn. De igual forma, en este ejemplo se aadirn objetos deniendo una forma de colisin convexa. El resultado de la simulacin (activando la representacin de las formas de colisin) se muestra en la Figura 12.27. La llamada al mtodo AddDynamicObject recibe como parmetro un tipo enumerado, que indica si queremos aadir una oveja o una caja. La forma de colisin de la caja se calcula automticamente em pleando la clase StaticMeshToShapeConverter (lnea 17 ).

Reutiliza las formas de colisin! Tanto en el ejemplo de la seccin anterior como en este cdigo, no se reutilizan las formas de colisin. Queda como ejercicio propuesto para el lector mantener referencias a las formas de colisin (para las ovejas y para las cajas), y comprobar la diferencia de rendimiento en frames por segundo cuando el nmero de objetos de la escena crece.

[258]

CAPTULO 12. SIMULACIN FSICA

Listado 12.12: AddDynamicObject


1 void MyFrameListener::AddDynamicObject(TEDynamicObject tObject) { 2 // Omitido codigo anterior del metodo --------------------------3 Entity *entity = NULL; 4 switch (tObject) { 5 case sheep: 6 entity = _sceneManager->createEntity("Sheep" + 7 StringConverter::toString(_numEntities), "sheep.mesh"); 8 break; 9 case box: default: 10 // (Omitido) Analogamente se carga el modelo de la caja... 11 } 12 13 SceneNode *node = _sceneManager->getRootSceneNode()-> 14 createChildSceneNode(); 15 node->attachObject(entity); 16 17 OgreBulletCollisions::StaticMeshToShapeConverter * 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 }

trimeshConverter = NULL; OgreBulletCollisions::CollisionShape *bodyShape = NULL; OgreBulletDynamics::RigidBody *rigidBody = NULL; switch (tObject) { case sheep: trimeshConverter = new OgreBulletCollisions::StaticMeshToShapeConverter(entity); bodyShape = trimeshConverter->createConvex(); delete trimeshConverter; break; case box: default: // (Omitido) Crear bodyShape como en el ejemplo anterior... } rigidBody = new OgreBulletDynamics::RigidBody("rigidBody" + StringConverter::toString(_numEntities), _world); // Omitido resto de codigo del metodo ---------------------------

El objeto de la clase StaticMeshToShapeConverter recibe como parmetro una Entity de Ogre en el constructor. Esta entidad puede ser convertida a multitud de formas de colisin. En el momento de la creacin, la clase reduce el nmero de vrtices de la forma de colisin. Cuando se pincha con el botn derecho o izquierdo del ratn sobre algn objeto de la simulacin, se un impulso con diferente aplicar fuerza (denida en F , ver lnea 18 del siguiente cdigo). El mtodo pickBody se encarga de obtener el primer cuerpo que colisiona con el rayo denido por la posicin de la cmara y el puntero del ratn. Este mtodo devuelve igualmente en los dos primeros parmetros el punto de colisin en el objeto y el rayo utilizado para construir el RayQuery. El mtodo pickBody primero obtiene el rayo utilizando la funcionalidad de Ogre, empleando las coordenadas de pantalla normalizadas ). Hecho esto, se crea una Query que requiere como tercer (lneas 20-21 parmetro la distancia mxima a la que se calcular la colisin, en la direccin del rayo, teniendo en cuenta su posicin inicial (lnea 4 ). Si el rayo colisiona en algn (lnea 6 ), se devuelve el cuerpo cuerpo ). y el punto de colisin (lneas 7-11

Figura 12.27: Resultado de la simulacin del ejemplo.

Conversor a Shape
Adems de la llamada a createConvex, el conversor estudiado en el cdigo anterior puede generar otras formas de colisin con createSphere, createBox, createTrimesh, createCylinder y createConvexDecomposition entre otras.

12.8. RayQueries

[259]

Listado 12.13: RayQuery en Bullet


1 RigidBody* MyFrameListener::pickBody (Vector3 &p, Ray &r, float x,

float y) {
2 r = _camera->getCameraToViewportRay (x, y); 3 CollisionClosestRayResultCallback cQuery = 4 CollisionClosestRayResultCallback (r, _world, 10000); 5 _world->launchRay(cQuery); 6 if (cQuery.doesCollide()) { 7 RigidBody* body = static_cast <RigidBody *> 8 (cQuery.getCollidedObject()); 9 p = cQuery.getCollisionPoint(); 10 return body; 11 } 12 return NULL; 13 } 14 15 bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { 16 // Omitido codigo anterior del metodo --------------------------17 if (mbleft || mbright) { // Con botones del raton, impulso -----18 float F = 10; if (mbright) F = 100; 19 RigidBody* body; Vector3 p; Ray r; 20 float x = posx/float(_win->getWidth()); // Pos x normalizada 21 float y = posy/float(_win->getHeight()); // Pos y normalizada 22 body = pickBody (p, r, x, y); 23 24 if (body) { 25 if (!body->isStaticObject()) { 26 body->enableActiveState (); 27 Vector3 relPos(p - body->getCenterOfMassPosition()); 28 Vector3 impulse (r.getDirection ()); 29 body->applyImpulse (impulse * F, relPos); 30 } 31 } 32 } 33 // Omitido resto de codigo del metodo --------------------------34 }

Para si hubo colisin con algn cuerpo que no sea esttico nalizar, ), se aplicar un impulso. La llamada a enableActiveState (lneas 24-25 permite activar un cuerpo. Por defecto, Bullet automticamente desactiva objetos dinmicos cuando la velocidad es menor que un determinado umbral. Los cuerpos desactivados en realidad estn se encuentran en un estado de dormidos, y no consumen tiempo de ejecucin salvo por la etapa de deteccin de colisin broadphase. Esta etapa automticamente despierta a los objetos que estuvieran dormidos si se encuentra colisin con otros elementos de la escena. En las lneas 27-29 se aplica un impulso sobre el objeto en la direccin del rayo que se calcul desde la cmara, con una fuerza proporcional a F . El impulso es una fuerza que acta en un cuerpo en un determinado intervalo de tiempo. El impulso implica un cambio en el momento, siendo la Fuerza denida como el cambio en el momento. As, el impulso aplicado sobre un objeto puede ser denido como la integral de la fuerza con respecto del tiempo. El wrapper de OgreBullet permite denir un pequeo subconjunto de propiedades de los RigidBody de las soportadas en Bullet. Algunas de las principales propiedades son la Velocidad Lineal, Impulsos y

Impulso
El impulso puede denirse como F dt = (dp/dt)dt, siendo p el momento.

[260]

CAPTULO 12. SIMULACIN FSICA

Figura 12.29: Conguracin de la malla esttica utilizada en el ejemplo. Es importante aplicar la escala y rotacin a los objetos antes de su exportacin, as como las dimensiones del objeto ball para aplicar los mismos lmites a la collision shape.

Fuerzas. Si se requieren otras propiedades, ser necesario acceder al objeto de la clase btRigidBody (mediante la llamada a getBulletRigidBody) y especicar manualmente las propiedades de simulacin.

12.9.

TriangleMeshCollisionShape

En este ejemplo se cargan dos objetos como mallas triangulares estticas. El resultado de la ejecucin puede verse en la Figura 12.28. Al igual que en el ejemplo anterior, se utiliza la funcionalidad proporcionada por el conversor demallas, pero generando una TriangleMeshCollisionShape (lnea 11-12 ).
Listado 12.14: Static Mesh
1 void MyFrameListener::CreateInitialWorld() { 2 // Creacion del track -----------------------------------------3 Entity *entity = _sceneManager->createEntity("track.mesh"); 4 SceneNode *node = _sceneManager->createSceneNode("track"); 5 node->attachObject(entity); 6 7 _sceneManager->getRootSceneNode()->addChild(node); 8 OgreBulletCollisions::StaticMeshToShapeConverter * 9 10 11 12 13 14 15 16 17 18 19 20 21 }

Figura 12.28: Resultado de la ejecucin del ejemplo de carga de mallas triangulares.

trimeshConverter = new OgreBulletCollisions::StaticMeshToShapeConverter(entity); OgreBulletCollisions::TriangleMeshCollisionShape *trackTrimesh = trimeshConverter->createTrimesh(); OgreBulletDynamics::RigidBody *rigidTrack = new OgreBulletDynamics::RigidBody("track", _world); rigidTrack->setShape(node, trackTrimesh, 0.8, 0.95, 0, Vector3::ZERO, Quaternion::IDENTITY); delete trimeshConverter; // (Omitido) Creacion del sumidero de forma similar ------------

12.10. Deteccin de colisiones

[261]

Es importante consultar en la posicin de los generadores de objetos en el espacio 3D (ver Figura 12.29), as como las dimensiones de los objetos que van a intervenir en la simulacin. Por ejemplo, las esferas se creaban con una forma de colisin de tipo SphereCollisionShape de 0.02 unidades de radio porque su dimensin en el espacio 3D es de 0.04 unidades (ver Figura 12.29). De igual modo, una de las posiciones de generacin es Vector3(-0.14, 1.07, -0.07) situada en el interior de una de las cajas.

12.10.

Deteccin de colisiones

Una de las formas ms sencillas de detectar colisiones entre objetos del mundo es iterar sobre los colectores de contactos (contact manifold ). Los contact manifold son en realidad caches que contienen los puntos de contacto entre parejas de objetos de colisin. El siguiente listado muestra una forma de iterar sobre los pares de objetos en el mundo dinmico.
Listado 12.15: DetectCollisionDrain.
1 void MyFrameListener::DetectCollisionDrain() { 2 btCollisionWorld *bulletWorld=_world->getBulletCollisionWorld(); 3 int numManifolds=bulletWorld->getDispatcher()->getNumManifolds(); 4 5 for (int i=0;i<numManifolds;i++) { 6 btPersistentManifold* contactManifold = 7 bulletWorld->getDispatcher()->getManifoldByIndexInternal(i); 8 btCollisionObject* obA = 9 static_cast<btCollisionObject*>(contactManifold->getBody0()); 10 btCollisionObject* obB = 11 static_cast<btCollisionObject*>(contactManifold->getBody1()); 12 13 Ogre::SceneNode* drain = _sceneManager->getSceneNode("drain"); 14 15 OgreBulletCollisions::Object *obDrain = 16 _world->findObject(drain); 17 OgreBulletCollisions::Object *obOB_A = _world->findObject(obA); 18 OgreBulletCollisions::Object *obOB_B = _world->findObject(obB); 19 20 if ((obOB_A == obDrain) || (obOB_B == obDrain)) { 21 Ogre::SceneNode* node = NULL; 22 if ((obOB_A != obDrain) && (obOB_A)) { 23 node = obOB_A->getRootNode(); delete obOB_A; 24 } 25 else if ((obOB_B != obDrain) && (obOB_B)) { 26 node = obOB_B->getRootNode(); delete obOB_B; 27 } 28 if (node) { 29 std::cout << node->getName() << std::endl; 30 _sceneManager->getRootSceneNode()-> 31 removeAndDestroyChild (node->getName()); 32 } 33 } 34 } 35 }

[262]

CAPTULO 12. SIMULACIN FSICA

Figura 12.30: Ejemplo de deteccin de colisiones empleando colectores de contactos.

En la lnea 2 se obtiene el puntero directamente a la clase btCollisionWorld, que se encuentra oculta en la implementacin de OgreBullet. Con este puntero se acceder directamente a la funcionalidad de Bullet sin emplear la clase de recubrimieneto de OgreBullet. La clase btCollisionWorld sirve a la vez como interfaz y como contenedor de las funcionalidades relativas a la deteccin de colisiones. ) se obtiene un punteMediante la llamada a getDispatcher (lnea 3 ro a la clase btDispather, que se utiliza en la fase de colisin broadphase para la gestin de pares de colisin. Esta clase nos permite obtener el nmero de que hay activos en cada instante. El bucle colectores de las lneas 5-34 se encarga de iterar sobre los colectores. En la lnea 6-7 se obtiene un puntero a un objeto de la clase btPersistentManifold. Esta clase es una implementacin de una cach persistente mientras los objetos colisionen en la etapa de colisin broadphase.

OgreBullet...
El listado anterior muestra adems cmo acceder al objeto del mundo de bullet, que permite utilizar gran cantidad de mtodos que no estn implementados en OgreBullet.

12.11. Restriccin de Vehculo

[263]

Los puntos de contacto se crean en la etapa de deteccin de colisiones na (narrow phase ). La cache de btPersistentManifold puede estar vaca o contener hasta un mximo de 4 puntos de colisin. Los algoritmos de deteccin de la colisin aaden y eliminan puntos de esta cach empleando ciertas heursticas que limitan el mximo de puntos a 4. Es posible obtener el nmero de puntos de contacto asociados a la cache en cada instante mediante el mtodo getNumContacts().

La cache de colisin mantiene punteros a los dos objetos que estn colisionando. Estos objetos pueden obtenerse mediante la llamada a mtodos get (lneas 8-11 ). La clase CollisionsWorld de OgreBullet proporciona un mtodo ndObject que permite obtener un puntero a objeto a partir de genrico ). un SceneNode o un btCollisionObject (ver lneas 15-18 La ltima parte del cdigo (lneas 20-32 ) comprueba si alguno de los dos objetos de la colisin son el sumidero. En ese caso, se obtiene el puntero al otro objeto (que se corresponder con un objeto de tipo esfera creado dinmicamente), y se elimina de la escena. As, los objetos en esta segunda versin del ejemplo no llegan a aadirse en la caja de la parte inferior del circuito.

Otros mecanismos de colisin. En la documentacin de Bullet se comentan brevemente otros mecanismos que pueden utilizarse para la deteccin de colisiones, como los objetos de la clase btGhostObject. Los objetos de esta clase pueden tener asociadas llamadas de callback de modo que se invoquen automticamente cuando los objetos se solapen en la etapa de deteccin de colisiones mediante el test de cajas AABB.

12.11.

Restriccin de Vehculo

En esta seccin estudiaremos cmo utilizar un tipo de restriccin especca para la denicin de vehculos. OgreBullet cuenta con abstracciones de alto nivel que trabajan internamente con llamadas a las clases derivadas btRaycastVehicle, que permiten convertir un cuerpo rgido en un vehculo. A continuacin estudiaremos algunos fragmentos de cdigo empleados en el siguiente ejemplo para la construccin del vehculo. Queda como ejercicio propuesto aadir obstculos y elementos de interaccin en la escena empleando mallas triangulares estticas.

[264]

CAPTULO 12. SIMULACIN FSICA

Figura 12.31: Ejemplo de denicin de un vehculo en OgreBullet.

Listado 12.16: Fragmento de MyFrameListener.h


1 2 3 4 5 6 7 8

OgreBulletDynamics::WheeledRigidBody OgreBulletDynamics::VehicleTuning OgreBulletDynamics::VehicleRayCaster OgreBulletDynamics::RaycastVehicle Ogre::Entity *mChassis; Ogre::Entity *mWheels[4]; Ogre::SceneNode *mWheelNodes[4]; float mSteering;

*mCarChassis; *mTuning; *mVehicleRayCaster; *mVehicle;

En el anterior archivo de cabecera se denen ciertas variables miembro de la clase que se utilizarn en la denicin del vehculo. mCarChassis es un puntero a una clase que ofrece OgreBullet para la construccin de vehculos con ruedas. La clase VehicleTuning es una clase de cobertura sobre la clase btVehicleTuning de Bullet que permite especicar ciertas propiedades del vehculo (como la compresin, suspensin, deslizamiento, etc). VehicleRayCaster es una clase que ofrece un interfaz entre la simulacin del vehculo y el RayCasting (usado para localizar el punto de contacto entre el vehculo y el suelo). La clase RaycastVehicle es una clase de sobre la clase base de Bullet btRaycastVehicle. Las cobertura lneas 5-7 denen los nodos y entidades necesarias para el chasisy las ruedas del vehculo. Finalmente, la varible Steering de la lnea 8 dene la direccin del vehculo. A continuacin estudiaremos la denicin del en el mtodo vehculo CreateInitialWorld del FrameListener. La lnea 1 del siguiente listado

12.11. Restriccin de Vehculo

[265]

dene el vector de altura del chasis (elevacin sobre el suelo), y la altura de conexin de las ruedas en l (lnea 2 ) que ser utilizado ms adelante. En la construccin inicial del vehculo se establece la ). direccin del vehculo como 0.0 (lnea 3 La lneas 5-9 crean la entidad del chasis y el nodo que la contendr. La lnea 10 utiliza el vector de altura del chasis para posicionar el nodo del chasis.
Listado 12.17: Fragmento de CreateInitialWorld (I).
1 2 3 4 5 6

const Ogre::Vector3 chassisShift(0, 1.0, 0); float connectionHeight = 0.7f; mSteering = 0.0; mChassis = _sceneManager->createEntity("chassis", "chassis.mesh"); SceneNode *node = _sceneManager->getRootSceneNode()-> createChildSceneNode ();

7 8 SceneNode *chassisnode = node->createChildSceneNode(); 9 chassisnode->attachObject (mChassis); 10 chassisnode->setPosition (chassisShift);

El chasis tendr asociada una forma de colisin de tipo caja (lnea ). Esta caja formar parte de una forma de colisin compuesta, que 1 se dene en la lnea 2 , y a la que se aade la caja anterior desplazada ). segn el vector chassisShift (lnea 3 En la lnea 4 se dene el cuerpo rgido del vehculo, al que se asocia la forma de colisin creada anteriormente (lnea 6 ). En la lnea 9 se establecen los valores de suspensin del vehculo, y se evita que el vehculo pueda desactivarse (lnea 8 ), de modo que el objeto no se dormir incluso si se detiene durante un tiempo continuado.
Listado 12.18: Fragmento de CreateInitialWorld (II).
1 BoxCollisionShape* chassisShape = new BoxCollisionShape(Ogre::

Vector3(1.f,0.75f,2.1f)); CompoundCollisionShape* compound = new CompoundCollisionShape(); compound->addChildShape(chassisShape, chassisShift); mCarChassis = new WheeledRigidBody("carChassis", _world); Vector3 CarPosition = Vector3(0, 0, -15); mCarChassis->setShape (node, compound, 0.6, 0.6, 800, CarPosition, Quaternion::IDENTITY); 7 mCarChassis->setDamping(0.2, 0.2); 8 mCarChassis->disableDeactivation();
2 3 4 5 6

En el siguiente fragmento se comienza deniendo algunos parme ). Estos parmetros son la rigidez, tros de tuning del vehculo (lnea 1 compresin y amortiguacin de la suspensin y la friccin de desli zamiento. La lnea 5 establece el sistema de coordenadas local del vehculo mediante los ndices derecho, superior y adelante. Las lneas 7 y 8 denen los ejes que se utilizarn como direccin del vehculo y en la denicin de las ruedas. El bucle de las lneas 10-16 construye los nodos de las ruedas, cargando 4 instancias de la malla wheel.mesh .

[266]

CAPTULO 12. SIMULACIN FSICA

El ejemplo desarrollado en esta seccin trabaja nicamente con las dos ruedas delanteras (ndices 0 y 1) como ruedas motrices. Adems, ambas ruedas giran de forma simtrica segn la variable de direccin mSteering. Queda propuesto como ejercicio modicar el cdigo de esta seccin para que la direccin se pueda realizar igualmente con las ruedas traseras, as como incorporar otras opciones de motricidad (ver Listado de FrameStarted ).

Listado 12.19: Fragmento de CreateInitialWorld (III).


1 mTuning = new VehicleTuning(20.2, 4.4, 2.3, 500.0, 10.5); 2 mVehicleRayCaster = new VehicleRayCaster(_world); 3 mVehicle = new RaycastVehicle(mCarChassis, mTuning,

mVehicleRayCaster);
4 5 6 7 8 9 10 11 12 13 14

mVehicle->setCoordinateSystem(0, 1, 2); Ogre::Vector3 wheelDirectionCS0(0,-1,0); Ogre::Vector3 wheelAxleCS(-1,0,0); for (size_t i = 0; i < 4; i++) { mWheels[i] = _sceneManager->createEntity("wheel"+i,"wheel.mesh"); mWheels[i]->setCastShadows(true); mWheelNodes[i] = _sceneManager->getRootSceneNode()-> createChildSceneNode(); mWheelNodes[i]->attachObject (mWheels[i]);

15 16 }

El siguiente fragmento de listado se repite para cada rueda, calculando el punto de conexin en funcin del ancho de cada rueda y la altura de conexin. Este punto es pasado al mtodo addWheel, junto con informacin relativa a ciertas propiedades fsicas de cada rueda. ) indica si la rueda aadida forma La variable isFrontWheel (ver lnea 3 parte del conjunto de ruedas delanteras (en este caso, nicamente las dos primeras ruedas tendrn esta variable a true en el momento de creacin.
Listado 12.20: Fragmento de CreateInitialWorld (IV).
1 Ogre::Vector3 connectionPointCS0 (1-(0.3*gWheelWidth),

connectionHeight, 2-gWheelRadius);
2 3 mVehicle->addWheel(mWheelNodes[0], connectionPointCS0,

wheelDirectionCS0, wheelAxleCS, gSuspensionRestLength, gWheelRadius, isFrontWheel, gWheelFriction, gRollInfluence);

12.12. Determinismo

[267] Finalmente el mtodo de callback del FrameStarted se encarga de modicar la fuerza que se aplica sobre el motor del vehculo cuando se utilizan los cursores superior e inferior del teclado. De igual modo, empleando los cursores izquierdo del teclado se modica la y derecho direccin del vehculo (ver lneas 11-15 ).
Listado 12.21: Fragmento de FrameStarted.
1 bool MyFrameListener::frameStarted(const Ogre::FrameEvent& evt) { 2 // Omitido el codigo anterior... 3 mVehicle->applyEngineForce (0,0); 4 mVehicle->applyEngineForce (0,1); 5 6 if (_keyboard->isKeyDown(OIS::KC_UP)) { 7 mVehicle->applyEngineForce (gEngineForce, 0); 8 mVehicle->applyEngineForce (gEngineForce, 1); 9 } 10 11 if (_keyboard->isKeyDown(OIS::KC_LEFT)) { 12 if (mSteering < 0.8) mSteering+=0.01; 13 mVehicle->setSteeringValue (mSteering, 0); 14 mVehicle->setSteeringValue (mSteering, 1); 15 } 16 17 // Omitido el resto del codigo... 18 }

12.12.

Determinismo

El determinismo en el mbito de la simulacin fsica puede denirse de forma intuitiva como la posibilidad de repeticin de un mismo comportamiento. En el caso de videojuegos esto puede ser interesante en la repeticin de una misma jugada en un videojuego deportivo, o en la ejecucin de una misma simulacin fsica en los diferentes ordenadores de un videojuego multijugador. Incluso aunque el videojuego siga un enfoque con clculos de simulacin centrados en el servidor, habitualmente es necesario realizar ciertas interpolaciones del lado del cliente para mitigar los efectos de la latencia, por lo que resulta imprescindible tratar con enfoques deterministas. Para lograr determinismo es necesario lograr que la simulacin se realice exactamente con los mismos datos de entrada. Debido a la precisin en aritmtica en punto otante, es posible que v 2 dt no de el mismo resultado que v dt + v dt. As, es necesario emplear el mismo valor de dt en todas las simulaciones. Por otro lado, utilizar un dt jo hace que no podamos representar la simulacin de forma independiente de las capacidades de la mquina o la carga de representacin grca concreta en cada momento. As, nos interesa tener lo mejor de ambas aproximaciones; por un lado un tiempo jo para conseguir el determinismo en la simulacin, y por otro lado la gestin con diferentes tiempos asociados al framerate para lograr independencia de la mquina.

[268]

CAPTULO 12. SIMULACIN FSICA

Figura 12.32: La gestin del determinismo puede ser un aspecto crtico en muchos videojuegos. El error de determinismo rpidamente se propaga haciendo que la simulacin obtenga diferentes resultados.

Una posible manera de realizar la simulacin sera la siguiente: el motor de simulacin fsica se ejecuta por adelantado en intervalos de tiempo discretos dt, de modo que se mantengan los incrementos del motor grco con un intervalo adecuado. Por ejemplo, si queremos tener 50fps y la simulacin fsica se ejecuta a 100fps, entonces tendramos que ejecutar dos veces la simulacin fsica por cada despliegue grco. Esto es correcto con esos clculos sencillos, pero qu ocurre si queremos dibujar a 200fps?. En ese caso tendramso que ejecutar la mitad de veces el simulador fsico, pero no podemos calcular por adelantado un valos de dt. Adems, podra ocurrir que no existiera un mltiplo cmodo para sincronizar el motor de simulacin fsica y el motor de despliegue grco. La forma de resolver el problema pasa por cambiar el modo de pensar en l. Podemos pensar que el motor de render produce tiempo, y el motor de simulacin fsica tiene que consumirlo en bloques discretos de un tamao determinado.

Puede ayudar pensar que el motor de render produce chunks de tiempo discreto, mientras que el motor de simulacin fsica los consume.

A continuacin se muestra un sencillo game loop que puede emplearse para conseguir determinismo de una forma sencilla. Los tiempos mostrados en este pseudocdigo se especican en milisegundos, y se obtienen a partir de una hipottica funcin getMillisecons(). La lnea 1 dene TickMs, una variable que nos dene la velocidad del reloj interno de nuestro juego (por ejemplo, 32ms). Esta variable

12.13. Escala de los Objetos

[269] no tiene que ver con el reloj de Bullet. Las variables relativas al reloj de simulacin fsica describen el comportamiento independiente y asn 2 ) y el reloj del motor de juego crono del reloj interno de Bullet (lnea ). (lnea 3
Listado 12.22: Pseudocdigo fsica determinista.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

const unsigned int TickMs 32 unsigned long time_physics_prev, time_physics_curr; unsigned long time_gameclock; // Inicialmente reseteamos los temporizadores time_physics_prev = time_physics_curr = getMilliseconds(); time_gameclock = getMilliseconds(); while (1) { video->renderOneFrame(); time_physics_curr = getMilliseconds(); mWorld->stepSimulation(((float)(time_physics_curr time_physics_prev))/1000.0, 10); time_physics_prev = time_physics_curr; long long dt = getMilliseconds() - time_gameclock; while(dt >= TickMs) { dt -= TickMs; time_gameclock += TickMs; input->do_all_your_input_processing(); } }

Como se indica en las lneas 6-7 , inicialmente se resetean los temporizadores. El pseudocdigo del bucle principal del juego se resume . Tras representar un frame, se obtiene el tiempo en las lneas 9-21 transcurrido desde la ltima simulacin fsica (lnea 11 ), y se avanza un paso de simulacin en segundos (como la llamada al sistema lo obtiene en milisegundos y Bullet lo requiere en segundos, hay que dividir por 1000). Por ltimo, se actualiza la parte relativa al reloj de juego. Se calcula en dt la diferencia entre los milisegundos que pasaron desde la ltima vez que se acualiz el reloj de juego, y se dejan pasar (en el bucle ) empleando ticks discretos. En cada tick denido en las lneas 17-21 consumido se procesan los eventos de entrada.

12.13.

Escala de los Objetos

Como se ha comentado en secciones anteriores, Bullet asume que las unidades de espacio se denen en metros y el tiempo en segundos. El movimieneto de los objetos se dene entre 0.05 y 10 unidades. As, la escala habitual para denir los pasos de simulacin suelen ser 1/60 segundos. Si los objetos son muy grandes, y se trabaja con la gravedad por defecto (9,8m/s2 ), los objetos parecern que se mueven a cmara lenta. Si esto ocurre, muy probablemente tengamos un problema relativo a la escala de los mismos. Una posible solucin puede pasar por aplicar una escala al mundo

[270]

CAPTULO 12. SIMULACIN FSICA

de la simulacin. Esto esquivale a utilizar un conjunto diferente de unidades, como centmetros en lugar de metros. Si se seleccionan con cuidado, esto puede permitir realizar simulaciones ms realistas. Por ejemplo, si queremos disear un videojuego de billar, escalamos el mundo en un factor de 100, de modo que 4 unidades equivaldrn a 4cm (dimetro de las bolas de billar).

12.14.

Serializacin

La serializacin de objetos en Bullet es una caracterstica propia de la biblioteca que no requiere de ningn plugin o soporte adicional. La serializacin de objetos presenta grandes ventajas relativas al preclculo de formas de colisin complejas. Para guardar un mundo dinmico en un archivo .bullet, puede utilizarse el siguiente fragmento de cdigo de ejemplo:
Listado 12.23: Ejemplo de Serializacin.
1 2 3 4 5

btDefaultSerializer* serializer = new btDefaultSerializer(); dynamicsWorld->serialize(serializer);

FILE* file = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer-> getCurrentBufferSize(),1, file); 6 fclose(file);

Aunque lo ms sencillo es serializar un mundo completo, es igualmente posible serializar nicamente algunas partes del mismo. El foramto de los archivos .bullet soporta la serializacin parcial de elementos empleando chunks independientes. En la posterior carga de los archivos .bullet, se debe utilizar la cabecera de BulletWorldImporter, creando un objeto de esa clase. El constructor de esa clase requiere que se le especique el mundo dinmico sobre el que crear los objetos que fueron serializados. El uso del importador puede resumirse en el siguiente fragmento de cdigo:
Listado 12.24: Importacin de datos serializados.
1 #include "btBulletWorldImporter.h" 2 btBulletWorldImporter* f = new btBulletWorldImporter(_dynWorld); 3 f->loadFile("testFile.bullet");

Apndice

Introduccin a OgreFramework
Sergio Fernndez Durn

C
A.1.

ada vez que creamos un nuevo proyecto con Ogre, existe un grupo de elementos que necesitamos instanciar para crear un primer prototipo. Este conjunto de clases y objetos se repiten con frecuencia para todos nuestros proyectos. En este captulo estudiaremos los fundamentos de OgreFramework, que ofrece una serie de facilidades muy interesantes.

Introduccin

OgreFramework fu creado por Philip Allgaier en 2009 y ofrece al programador una serie de herramientas para la gestin de Ogre como: Un sistema de Estado de Juego. Una interfaz grca de usuario. Diferentes modos de entrada. Carga de escenas. Manipulacin manual de materiales. El uso de este framework ayuda a separar la entidad del motor de renderizado de nuestro juego pudiendo combinarlo con nuevos mdulos como: el motor de fsicas o un middleware de comunicaciones. Estos factores pueden ayudar a gestionar mejor la coordinacin entre 271

[272]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

varios motores, como la gestin del tiempo entre el motor de fsicas y el motor de renderizado. Existen dos ramas del framework para Ogre, Basic y Advanced. La diferencia entre los dos es la cantidad de recursos que manejan. Basic OgreFramework contiene los recursos mnimos necesarios para crear una instancia del motor Ogre y que muestre una escena como ejemplo. Y Advanced OgreFramework incluye un conjunto completo de herramientas y clases para una gestin avanzada de nuestra aplicacin. OgreFramework est desarrollado en C++ sobre Ogre y es multiplataforma, sin embargo, es necesario realizar algunas modicaciones en el framework para que pueda funcionar en OSX. Una de las mayores ventajas de utilizar esta tecnologa es la de poder automatizar la carga inicial del motor y poder congurar Ogre con llamadas simples a OgreFramework.

A.2.

Basic OgreFramework

Una de las mejores formas de iniciarse con Ogre es mediante esta tecnologa. Con esta herramienta no es necesario conocer la arquitectura del motor para poder crear un primer ejecutable y ayuda a conocer cuales son sus funciones bsicas. Este paquete de herramientas incluye: Inicializacin de Ogre. Bucle de renderizado personalizable. Escena bsica. Gestin de teclado bsica. Crear capturas de pantallas (Screenshots). Informacin bsica de la escena (FPS, contador batch. . . ). Para conseguir la ltima versin de Basic OgreFramework clonaremos el proyecto con mercurial desde la siguiente direccin:
hg clone https://bitbucket.org/spacegaier/basicogreframework

Cuando descargamos el proyecto, podemos crear un ejecutable de OgreFramework directamente con los cheros descargados. Una vez hemos compilado y ejecutado el cdigo de ejemplo, nos encontraremos con la pantalla mostrada en la Figura A.1. Su estructura es muy sencilla y explicaremos con ms profundidad el funcionamiento del framework en la siguiente seccin.
Figura A.1: Resultado del primer ejemplo con Ogre Framework.

A.2. Basic OgreFramework

[273]

A.2.1.

Arquitectura

La rama Basic de OgreFramework contiene en exclusiva la instanciacin del motor de renderizado. Se basa en el patrn Singleton. Cada vez que queramos hacer uso de alguna llamada al motor ser necesario recuperar el puntero al Singleton del objeto. Dentro de la clase OgreFramework nos encontramos con el arranque de los siguientes gestores: OgreRoot, Camera, RenderWindow, ViewPort, SceneManager, Log, Timer, InputManager, etc. Todos estos gestores de la clase OgreFramework sern explicados con ms detalle en la siguiente seccin, donde hablaremos de la rama Advanced . Para poder crear un ejemplo basado en Basic OgreFramework es necesario: Llamar a las funciones de inicio, conguracin y ejecucin del motor. Un puntero a una instancia de OgreFramework. Una entidad y un nodo escena. Una variable booleana que gestione el bucle principal del juego. Ahora veremos los pasos necesarios para rellenar de contenido nuestra escena. Para ello crearemos nodos y escenas igual que las creamos en Ogre pero llamando al puntero de OgreFramework, como se muestra en el siguiente listado.
Listado A.1: Creacin de escena.
1 void ExampleApp::createScene() 2 { 3 OgreFramework::getSingletonPtr()-> 4 m_pSceneMgr->setSkyBox(true, "Examples/Sky"); 5 OgreFramework::getSingletonPtr()-> 6 m_pSceneMgr->createLight("Light")->setPosition(75,75,75); 7 8 m_pSinbadEntity = OgreFramework::getSingletonPtr()-> 9 m_pSceneMgr->createEntity("SinbadEntity", "Sinbad.mesh"); 10 m_pSinbadNode = OgreFramework::getSingletonPtr()-> 11 m_pSceneMgr->getRootSceneNode()->createChildSceneNode("

SinbadNode");
12 m_pSinbadNode->attachObject(m_pSinbadEntity); 13 }

Como podemos observar, para crear una entidad y un nodo, es necesario acceder al gestor de escena mediante el puntero Singleton a OgreFramework. Se realizar la misma accin para crear las luces de la escena y el Skybox. Esta restriccin nos ayudar a mantener separado el motor Ogre de nuestro modelo y permitir la integracin con otros mdulos de forma ms homognea para el desarrollador.

[274]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

Realmente, cuando accedamos a uno de los gestores de OgreFramework como el SceneManager, utilizaremos las mismas primitivas que utilizabamos en Ogre. Por lo tanto, podremos usar la documentacin estndar de Ogre. Para gestionar nuestro bucle del juego necesitaremos la variable booleana m_bShutdown la cual nos permitir cerrar la aplicacin en cualquier momento. Si se produce un error inesperado, tambin saldr del bucle principal. En cada iteracin del bucle: Se capturan las rdenes introducidas a travs de teclado y ratn para mostrar nuevos eventos en la siguiente iteracin. Se guarda el tiempo transcurrido desde el inicio. Se actualiza el motor Ogre con el tiempo del ltimo frame generado. Se renderiza un frame. Se calcula el tiempo transcurrido desde el ltimo frame generado.

A.3.

Advanced OgreFramework

Para poder realizar un proyecto ms complejo en Ogre, este framework nos sirve como ncleo. Este paquete de herramientas incluye lo siguiente: Inicializacin de OGRE. Carga de recursos bsicos. Gestin de dispositivos de entrada basado en OIS. Personalizacin del bucle de renderizado. Jerarqua basada en estados. Cargador de escenas mediante XML con DotSceneLoader. Interfaz grca de usuario basada en SdkTrays. Manipulacin de materiales en cdigo. Para conseguir la ltima versin de Advanced OgreFramework clonaremos el proyecto con mercurial desde la siguiente direccin:
hg clone https://bitbucket.org/spacegaier/advancedogreframework

Una vez hayamos descargado el proyecto, podremos generar un ejecutable sin realizar ninguna modicacin. Esta rama de OgreFramework nos proporciona tres estados distintos en la aplicacin: Menu, Pausa y Juego. Algo bsico para cualquier prototipo.

A.3. Advanced OgreFramework

[275]

Tambin nos proporciona un gestor de interfaz basado en SdkTrays (el mismo que utiliza Ogre para sus ejemplos) con el que podemos gestionar los estados del juego. La intefaz incluye por defecto un conjunto de paneles debug que permiten conocer los FPS, el nombre del estado actual, la posicin de la cmara, panel de ayuda, etc. . .
Figura A.2: Ejemplo bsico de Widgets.

Podremos agregar y editar Overlays a los estados Men para personalizar nuestra interfaz. Cada vez que entremos en un estado, se generarn los widgets que aparecen en pantalla y se crean los elementos de la interfaz especcos para ese estado. Cuando salimos o pausamos ese estado para entrar en uno nuevo, los elementos de la interfaz se destruyen y desaparecen de la escena. Podremos modicar los Widgets y elementos de la interfaz editando sus propiedades y materiales.

Figura A.3: Algunos de los widgets soportados en el men del ejemplo.

Dedicaremos un captulo para explicar detalladamente cmo se gestiona la interfaz mediante SdkTrays y cmo podemos crear nuevos elementos. Tambin explicaremos cmo personalizar el diseo de nuestra interfaz. Sin embargo, SdkTrays est diseado para crear una interfaz fcil y sencilla, si queremos realizar una interfaz ms compleja es mejor realizarlo con otra alternativa.
Figura A.4: SdkTrays facilita la construccin de interfaces sencillas.

En este ejemplo, todos los recursos de la escena han sido cargados desde un XML con la herramienta DotSceneLoader. Este chero contiene las propiedades de cada nodo y se carga de manera dinmica en nuestra escena.

[276]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

A.3.1.

Sistema de Estados

Cada estado creado en nuestra aplicacin incluye las siguientes acciones: entrar, pausar, resumir y salir. Para que todos los estados mantengan esta condicin se utiliza herencia de la clase AppState. La clase que gestiona todos los estados es AppStateManager cuya tarea es manejarlos y conectarlos. Para hacer esto, el manager tiene una pila de estados activos y siempre ejecuta el estado de la cima de la pila. En cualquier momento, se puede conectar otro estado de la pila, que ser usado hasta que sea eliminado de la misma. En este caso, el manager resume el estado que dej en pausa al introducir el anterior estado eliminado. En el momento en que la aplicacin no contiene ningn estado activo, el manager cierra la aplicacin.

A.3.2.

Arquitectura

La arquitectura de Advanced OgreFramework parece compleja pero, realmente, es bastante fcil de entender. Esta herramienta gestiona la aplicacin de Ogre como un conjunto de estados, que se van introduciendo en una pila. Esta gestin de estados es la que comnmente hemos utilizado para los proyectos de Ogre. OgreFramework En la clase OgreFramework podemos observar que contiene todos los elementos bsicos para iniciar una estancia de Ogre. OgreFramework contiene los siguientes gestores: Root, RenderWindow, ViewPort, Timer, Log, InputManager, SdkTraysManager. Si queremos aadir ms gestores como el gestor de sonido (SDL, OpenAL, etc. . . ) debemos iniciarlos en esta clase. El sistema se compone de una nica instancia de Ogre y es accesible desde los estados de la aplicacin. Para iniciar Ogre utilizaremos la funcin initOgre(), que crea los gestores necesarios para su funcionamiento como: Un gestor de registros LogManager. Crear el Root. Crea el RenderWindow y Viewport. Inicia los gestores de eventos de entrada mediante OIS. Carga los recursos e inicia el Timer. Establece el SDKTrayManager.

A.3. Advanced OgreFramework

[277]

Para actualizar cada frame del motor Ogre, la clase AppStateManager llamar la funcin updateOgre() para actualizar directamente Ogre. Este mtodo estar vaco para que cada estado se encargue de actualizar el motor de Ogre, pero es necesario ubicarlo aqu como tarea central del motor. DotSceneLoader Esta herramienta se usa para cargar las escenas en Ogre a partir de un chero XML. Estos cheros XML son procesados mediante RapidXML ; DotSceneLoader crea las estructuras necesarias para ser cargadas en el SceneManager de Ogre. Si deseamos aadir fsicas a un nodo, tendremos que aadir aqu su implementacin.
Listado A.2: Carga de escena DotScene.
1 DotSceneLoader* pDotSceneLoader = new DotSceneLoader(); 2 pDotSceneLoader->parseDotScene("CubeScene.xml", "General", 3 m_pSceneMgr, m_pSceneMgr->getRootSceneNode()); 4 Ogre::Entity* cube = m_pSceneMgr->getEntity("Cube");

Podemos ver que para crear una escena es necesario introducir 4 argumentos: el chero, el nombre del nodo, el SceneManager que se est gestionando en este estado y el nodo donde queremos introducirlo. Es muy interesante poder cargar las escenas desde un chero XML por que podremos crearlas y destruirlas de manera dinmica, permitiendo una mejor gestin de la memoria y del nivel del juego. Normalmente, se pueden agrupar las escenas de un nivel por bloques e ir cargando cada uno cuando sea necesario. Si, por ejemplo, nos encontramos con un juego tipo endless-running, es interesante ir destruyendo las escenas que quedan detrs del personaje ya que no vam a ser accesibles; tambin es interesante para ir auto-generando la escena de forma aleatoria hacia adelante. Cada vez que carguemos una escena, podremos recuperar una entidad como se describe en el ejemplo; por un nombre bien conocido. Este nombre estar asignado en el chero XML y podremos recuperar el nodo desde el propio juego. De esta manera podremos cambiar las propiedades o materiales de dicha entidad al vuelo como, por ejemplo, aadir un cuerpo rgido al motor de fsicas y conectarlo a la entidad. AppState En este archivo se denen dos clases. La primera clase ser la que herede el AppStateManager que gestiona los estados, pero est denido en esta clase por cuestiones de diseo. Esta contiene los mtodos necesarios para la gestin de los estados, estos mtodos son abstractos y estn denidos en la clase AppStateManager. La segunda clase ser AppState la cul ser la clase de la que hereden todos los estados que se implementen en el juego. Esta clase contiene una serie de mtodos para mantener la consistencia entre

[278]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

estados y poder tratar cada uno como estado independiente. En l se incluyen los mtodos: enter, exit, pause, resume y update. Estos mtodos nos permitirn sobre todo mantener la interfaz organizada en cada estado como, por ejemplo, el track de msica que se est escuchando en cada estado. Cuando creamos un estado nuevo y lo agregamos a la pila de estados. AppStateManager Esta clase ser la encargada de gestionar todos los estados. Tendr los mecanismos para pausar, recuperar y cambiar un estado en cualquier instante del juego. Hereda directamente del AppStateListener e implementa sus mtodos abstractos. Contiene dos vectores: Un vector para todos los estados existentes. Un vector para los estados activos. Para cada estado existirn una serie de valores como su nombre, informacin y su estado. Cada vez que se cree un estado, se llamar al mtodo manageAppState() para que introduzca dicha informacin al estado y lo inserte en la pila de estados existentes. En esta clase se encuentra el bucle principal del juego, dentro del mtodo start(). Dentro de este mtodo podemos destacar el clculo del tiempo de un frame a otro. Aqu podremos realizar las modicaciones necesarias si necesitamos coordinar el motor de renderizado con el motor de fsicas. Para poder arreglar el problema en el desfase de tiempo entre ambos motores se ajusta un valor delta que discretiza el tiempo entre un frame y otro. Esta tcnica nos ayudar a manejar correctamente el tiempo en ambos motores para que se comporte de manera natural.
Listado A.3: Bucle principal del juego.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

double t = 0.0; const double dt = 0.01; double currentTime = tiempo_actual_en_segundos(); double accumulator = 0.0; while ( !quit ) { double newTime = time(); // Tiempo actual en segundos double frameTime = newTime - currentTime; // Tiempo de un frame if ( frameTime > 0.25 ) frameTime = 0.25; // Tiempo maximo de espera entre frames currentTime = newTime; accumulator += frameTime; while ( accumulator >= dt ) { updateOgre(dt); accumulator -= dt; } const double alpha = accumulator / dt; renderOneFrame(); }

A.3. Advanced OgreFramework MenuState

[279]

La clase MenuState ser una de las implementaciones de la clase AppState.Por herencia se asegura que todos los estados tienen los mismos mtodos comunes y funciones como enter(), exit(), pause(), resume() y update(). Estos mtodos se ejecutarn automticamente por el AppStateManager. Esto es, si el estado actual fue pausado, ejecutar el mtodo resume y seguir la ejecucin del bucle principal. Igual para el resto de estados. En todos los estados se escribir la macro DECLARE_APPSTATE_CLASS(MenuState) que insertar el nombre del estado para poder ser recuperado posteriormente. Dentro de la funcin enter() de MenuState se crea un SceneManager, se crea la cmara, se construye la interfaz grca de usuario y se llama al creador de escena. En este caso el creador de escena no tendr nada puesto que ser un estado en el que se base en la interfaz grca creada por SdkTrays y no en Ogre. En el mtodo exit() estarn todos los destructores de escena, interfaz y cmara. De esta forma aseguramos la integridad entre estados. Los manejadores de entrada (teclado/ratn) tambin estarn presentes en todos los estados y servirn para capturar los eventos que se realicen en la interfaz. La funcin update() actualiza los elementos de la interfaz como, por ejemplo, si el ratn est encima de un botn cambia la imagen; si, por otro lado, se pulsa el botn, la imagen cambia de nuevo. Adems este mtodo capturar si se ha enviado la orden de salir del sistema para nalizar la aplicacin. Y por ltimo, el mtodo buttonHit() es un callback que se accionar cuando se pulse un botn. Dentro de este mtodo podremos identicar que botn se ha accionado y realizar una accin consecuente con ello.

GameState Toda la lgica del juego est dentro del estado GameState. Aqu es donde enlazaremos todos nuestros elementos de nuestro juego, como por ejemplo: el motor de fsicas, el controlador de nuestro personaje principal, mdulos de inteligencia articial, etc. En el caso de ejemplo de OgreFramework, incluye una escena mnima que carga una escena con DotSceneLoader y rellena de contenido la pantalla. Para crear los elementos necesarios de la interfaz se invoca a builGUI() para insertar todos los elementos necesarios del estado mediante el gestor SdkTraysManager que explicaremos en la siguiente seccin. Para capturar los eventos de entrada por teclado, se utilizarn los mtodos keyPressed() y keyReleased() para realizar los eventos correspondientes a si se pulsa una tecla o se ha dejado de pulsar respectivamente. En nuestro caso, tendremos una serie de condiciones para cada tecla que se pulse, las teclas son capturadas mediante las macros denidas en la librera OIS.

[280]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

A.4.

SdkTrays

Tanto los ejemplos que vienen con el SDK de Ogre (SampleBrowser ), como OgreFramework utilizan SdkTrays. Este gestor de la interfaz se construy con el propsito de ser sencillo, crear interfaces de una manera rpida y sin tanta complejidad como CEGUI. El sistema de SdkTrays est basado en Ogre::Overlay por lo que nos garantiza su portabilidad a todas las plataformas.

A.4.1.

Introduccin

El sistema de interfaz de SdkTrays se organiza en una serie de paneles (trays), que se localizan en nueve de posiciones de nuestra pantalla. Cada introducimos un nuevo Ogre::Overlay en nuestra escena, debemos calcular las coordenadas (x,y) del frame actual, aadiendo complejidad a la hora de disear una interfaz. Cuando creamos un widget nuevo con SdkTrays, debemos pasarle una posicin de las nueve posibles y el tamao. Si ya existe una un widget en esa regin, el nuevo widget se colocar justo debajo, manteniendo las proporciones de la pantalla y redimiensionando el panel actual donde se encuentra dicho widget.

A.4.2.

Requisitos

SdkTrays necesita la biblioteca OIS para la captura de datos de entrada mediante ratn o teclado. Una vez que se han incluido estas dependencias al proyecto simplemente es necesario incluir SdkTrays.h en cada clase. Y tambin es necesario incluir el chero SdkTrays.zip a nuestro directorio de recursos, normalmente en /media/packs.

A.4.3.

SdkTrayManager

Para utilizar SdkTrays, es necesario crear un SdkTrayManager. Esta es la clase a travs de la cual se van a crear y administrar todos los widgets, manipular el cursor, cambiar la imagen de fondo, ajustar las propiedades de los paneles, mostrar dilogos, mostrar / ocultar la barra de carga, etc. El SdkTrayManager requiere SdkTrays.zip, por lo que slo se puede crear despus de cargar ese recurso. Es recomendable asegurarse de que est utilizando el espacio de nombres OgreBites para poder incluir las macros de localizacin. Estas macros permiten crear un widget en las esquinas, en la parte central de la pantalla y en la parte central de los bordes.

A.4.4.

Widgets

Existen 10 tipos de widgets bsicos. Cada widget es slo un ejemplo de una plantilla de OverlayElement. Cada vez que se crea un widget es necesario introducir las medidas en pixeles. Cada widget est

A.4. SdkTrays

[281] identicado con un nombre y se gestionar su creacin y destruccin mediante SdkTrayManager. Algunos de los widgets predenidos que podemos crear son los siguientes: Button, TextBox, SelectMenu, Label, Separator, Slider, ParamsPanel, CheckBox, DecorWidget, ProgressBar, FrameStats, Loading Bar, Question Dialog.

A.4.5.

SdkTrayListener

Esta clase contiene los controladores para todos los diferentes eventos que pueden disparar los widgets. La clase SdkTrayManager es, en s misma, un SdkTrayListener porque responde a los eventos de los widgets. Algunos widgets dan la opcin de no disparar un evento cuando cambia su estado. Esto es til para inicializar o restablecer un widget, en cuyo caso no debe haber una respuesta de cualquier tipo.

A.4.6.

Skins

SdkTrays no est orientado a una personalizacin profunda de los widgets como en CEGUI. Pero eso no signica que no podamos cambiar su apariencia del modelo estndar. Los recursos de las imgenes que utilizan los widgets se encuentran en el chero SdkTrays.zip. Si descomprimimos los recursos y modicamos el contenido, podemos personalizar la apariencia de los widgets. Las imgenes que se muestran tienden a ser muy pequeas con formas muy concretas. Este tipo de imgenes se utiliza para reducir el espacio necesario para cada widget y que sea reutilizable por recursos. Si queremos modicar la apariencia de un widget es recomendable seguir las mismas formas y cambiar slo los colores o tambin podemos optar por cambiar la apariencia a colores slidos/planos. Las imgenes del paquete SdkTrays.zip son PNG, por lo que podemos crear transparencias si lo deseamos o sombreados. La personalizacin es limitada, pero con diseo y creatividad se pueden conseguir apariencias bastante diferentes de la original de OgreFramework.

A.4.7.

OgreBites

Podemos observar como se distribuyen los widgets por regiones en la pantalla. Estas posiciones vienen dadas por el espacio de nombres OgreBites, la cual incluye una serie de macros que instancia los widgets en la regin deseada. Observamos adems que si por ejemplo agregamos seis widgets en la parte inferior derecha, los widgets se agrupan en un columna tipo pila. Este orden es el mismo que nosotros agregaremos en las lineas de cdigo y las macros para instanciar los widgets son las siguientes:

[282]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

TL_TOPLEFT, TL_TOPCENTER, TL_TOPRIGHT, TL_LEFT, TL_CENTER, TL_RIGHT, TL_BOTTOMLEFT, TL_BOTTOMCENTER, TL_BOTTOMRIGHT.

A.5.

btOgre

btOgre es un conector ligero entre BulletOgre. Este conector no proporciona un RigidBody ni CollisionShape directamente. En lugar de eso, se accede directamente al motor correspondiente. La nica accin que realiza btOgre es la de conectar los btRigidBodies con SceneNodes. Tambin puede convertir las mallas (mesh ) de Ogre a guras convexas en Bullet, proporcionando un mecanismo de debug de Bullet como observamos en la imagen y herramientas de conversin de un vector de Bullet a un quaternio de Ogre (ver Figura A.5).

Figura A.5: Modo Debug con simulacin fsica en btOgre.

A.5. btOgre

[283]

Listado A.4: Conguracin de Bullet.


1 //Creamos una Entidad y un Nodo en Ogre. 2 m_pSphereEntity = OgreFramework::getSingletonPtr()-> 3 m_pSceneMgr->createEntity("SphereEntity", "Sphere.mesh"); 4 m_pSphereNode = OgreFramework::getSingletonPtr()-> 5 m_pSceneMgr->getRootSceneNode()->createChildSceneNode("SphereNode 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

"); m_pSphereNode->attachObject(m_pSphereEntity); //Creamos la forma de la malla en Bullet. BtOgre::StaticMeshToShapeConverter converter(m_pSphereEntity); m_pSphereShape = converter.createSphere(); // Insertamos la masa al cuerpo rigido. btScalar mass = 5; btVector3 inertia; m_pSphereShape->calculateLocalInertia(mass, inertia); // Creamos un estado de BtOgre (conectamos Ogre y Bullet). BtOgre::RigidBodyState *state = new BtOgre::RigidBodyState( m_pSphereNode); // Creamos el Body. BtOgre::btRigidBody m_pRigidBody = new btRigidBody(mass, state, m_pSphereShape, inertia); // Mundo fisico de Bullet (btDynamicsWorld). m_pDynamicsWorld->addRigidBody(m_pRigidBody);

En este ejemplo comprobamos como btOgre conecta el Nodo de Ogre con la forma convexa de Bullet. Cada vez que se aplique un cambio en el mundo fsico de Bullet se vern sus consecuencias en el Nodo de Ogre. Esto permite la integracin de los dos motores y el acceso independiente a las propiedades del objeto en ambos mundos. Cada vez que actualicemos el bucle principal del juego ser necesario hacer una llamada a stepSimulation con el tiempo calculado entre frame y frame.
Listado A.5: Conguracin de la escena.
1 2 3 4 5 6 7 8 9

// Creamos el objeto debug para Bullet BtOgre::DebugDrawer m_pDebugDrawer = new BtOgre::DebugDrawer(OgreFramework::getSingletonPtr()-> m_pSceneMgr->getRootSceneNode(), m_pDynamicsWorld); m_pDynamicsWorld->setDebugDrawer(m_pDebugDrawer); // Actualizamos el motor Bullet m_pDynamicsWorld->stepSimulation(timeSinceLastFrame); m_pDebugDrawer->step();

[284]

APNDICE A. INTRODUCCIN A OGREFRAMEWORK

A.6.

Referencias

http://www.ogre3d.org/tikiwiki/Basic+Ogre+Framework http://www.ogre3d.org/tikiwiki/Advanced+Ogre+Framework http://bitbucket.org/spacegaier/basicogreframework http://bitbucket.org/spacegaier/advancedogreframework http://gafferongames.com/game-physics/fix-your-timestep/ http://ogrees.wikispaces.com/Tutorial+Framework+Avanzado+ de+Ogre http://www.ogre3d.org/tikiwiki/SdkTrays http://www.ogre3d.org/tikiwiki/OgreBites http://github.com/nikki93/btogre

Bibliografa

[1] www.cegui.org.uk. [2] E. Akenine-Mller, T. Haines and N. Hoffman. Real-Time Rendering. AK Peters, Ltd., 2008. [3] T. Akenine-Mller, E. Haines, and N. Hoffman. Real-Time Rendering. AK Peters, 3rd edition, 2008. [4] T.H. Cormen, C.E. Leiserson, R.L. Rivest, and C. Stein. Introduction to Algorithms, Third Edition. 2009. [5] Chris Dallaire. Binary triangle trees for terrain tile index buffer generation. 2006. [6] D.S.C. Dalmau. Core techniques and algorithms in game programming. New Riders Pub, 2004. [7] W.H. De Boer. Fast terrain rendering using geometrical mipmapping. Unpublished paper, available at http://www. ipcode. com/articles/article geomipmaps. pdf, 2000. [8] X. Dcoret, F. Durand, F.X. Sillion, and J. Dorsey. Billboard clouds for extreme model simplication. In ACM Transactions on Graphics (TOG), volume 22, pages 689696. ACM, 2003. [9] M. Duchaineau, M. Wolinsky, D.E. Sigeti, M.C. Miller, C. Aldrich, and M.B. Mineev-Weinstein. Roaming terrain: real-time optimally adapting meshes. In Visualization97., Proceedings, pages 8188. IEEE, 1997. [10] D.H. Eberly. 3D Game Engine Architecture. Morgan Kauffmann, 2005. [11] C. Ericson. Real-time collision detection, volume 1. Morgan Kaufmann, 2005. [12] Randima Fernando. GPU Gems: Programming Techniques, Tips and Tricks for Real-Time Graphics. Pearson Higher Education, 2004. 285

[286] [13] Randima Fernando and Mark J. Kilgard. The Cg Tutorial: The Denitive Guide to Programmable Real-Time Graphics. AddisonWesley Longman Publishing Co., Inc., Boston, MA, USA, 2003. [14] Khronos Group. COLLADA Format http://www.khronos.org/collada/, 2012. Specication.

BIBLIOGRAFA

[15] H. Hoppe. Efcient implementation of progressive meshes. Computers & Graphics, 22(1):2736, 1998. [16] IberOgre. Formato OGRE 3D. http://osl2.uca.es/iberogre, 2012. [17] InniteCode. Quadtree Demo with source http://www.innitecode.com/?view_post=23, 2002. code.

[18] D. Johnson and J. Wiles. Effective affective user interface design in games. Ergonomics, 46(13-14):13321345, 2003. [19] G. Junker. Pro Ogre 3D Programming. Apress, 2006. [20] F. Kerger. Ogre 3D 1.7 Beginners Guide. Packt Publishing, 2010. [21] D. Luebke and C. Georges. Portals and mirrors: Simple, fast evaluation of potentially visible sets. In Proceedings of the 1995 symposium on Interactive 3D graphics, pages 105ff. ACM, 1995. [22] M. McShaffry. Game coding complete. "Paraglyph Publishing, 2003. [23] Assembla NocturnaIR. El Formato http://www.assembla.com/wiki/show/reubencorp/ El_formato_COLLADA, 2012. [24] ATI NVidia. Arb occlusion query, 2001. [25] E. Pipho. Focus on 3D models, volume 1. Course Technology, 2002. [26] William T. Reeves. Particle systems - a technique for modelling a class of fuzzy objects. ACM Transactions on Graphics, 2:91108, 1983. [27] P. Shirley and S. Marschner. Fundamentals of Computer Graphics. AK Peters, 3rd edition, 2009. [28] D. Shreiner. OpenGL Programming Guide: The Ofcial Guide to Learning OpenGL, Versions 3.0 and 3.1 (7th Edition). AddisonWesley, 2009. [29] S.J. Teller and C.H. Squin. Visibility preprocessing for interactive walkthroughs. In ACM SIGGRAPH Computer Graphics, volume 25, pages 6170. ACM, 1991. [30] T. Theoharis, G. Papaioannou, and N. Platis. Graphics and Visualization: Principles & Algorithms. AK Peters, 2008. [31] T. Ulrich. Rendering massive terrains using chunked level of detail control. SIGGRAPH Course Notes, 3(5), 2002. Collada.

Bibliografa

[287] [32] Wang and Niniane. Let there be clouds! Game Developer Magazine, 11:3439, 2004. [33] H. Zhang, D. Manocha, T. Hudson, and K.E. Hoff III. Visibility culling using hierarchical occlusion maps. In Proceedings of the 24th annual conference on Computer graphics and interactive techniques, pages 7788. ACM Press/Addison-Wesley Publishing Co., 1997.

Ciudad Real, 12 de Julio de 2013

Vous aimerez peut-être aussi