22. Bounding volumes y reestructuración |
![]() |
![]() |
Videojuegos - Curso de Programación de juegos | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Escrito por Vicengetorix | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() La pregunta inmediata es ¿para qué calculamos los "bounding volumes"?. Pues para, en un futuro, poder hacer "frustum culling" (descartar lo que no se ve) o calcular algún tipo de choque entre modelos. Son dos ejemplos. Calcularemos el "bounding box" (cubo dentro del cual está el modelo) y la "bounding sphere" (lo mismo pero una esfera). Calcularemos los dos en tiempo de carga del modelo y dibujaremos, más tarde, el cubo y la esfera contenedora (o delimitadora con traducción exacta) alrededor del modelo. La reestruccturación del código es la parte más necesaria. Hasta ahora ha sido cómodo mantener todo en un solo fichero de código pero ya empieza a ser complicado encontrar las cosas y además va siendo hora de normalizar la forma de trabajo (no mucho). Sacaremos del fichero principal todo menos la función Pinta() y añadiremos a este fichero principal una función Inicia() para inicializaciones (será llamada desde IniciaGL() ) y una función Cierra() para liberar memorias y esas cosas (será llamada desde ProcesaMensajes(...) ). Crearemos un fichero de cabecera (.h) llamado USW.h donde irá casi todo el resto del código, incluida WinMain, las funciones IniciaGL, ProcesaMensajes, CreaVentana, las funciones matemáticas, etc. Obviamente habrá que incluir este fichero al principio del programa principal. Creamos también un fichero llamado USWmodelo.h en el que crearemos una clase para manejar la carga y pintado de modelos y asà poder cargar los que queramos. Hacemos lo mismo con un fichero llamado USWshader.h pero con una clase para gestionar los shaders. Las funciones, estructuras y variables que tenÃamos para la carga de modelos serán incluidas en el fichero USWmodelo.h y las referentes a shaders en USWshaders.h. Veamos USWmodelo.h. Contiene la clase modeloCOB, además de las estructuras y el código para carga y pintado de modelos que vimos en anteriores capÃtulos. La definicion de la clase es esta.
Si os fijais, vereis que hay muy pocas cosas nuevas, en realidad solo una, aparte de que está todo incluido en una clase. Lo único nuevo es la última definición. Es para almacenar los datos de los "bounding volumes" que vamos a calcular. La estructura se define en la zona de definiciones globales del fichero.
Los 6 primeros miembros de la estructura son para los datos que definen la "bounding box". La "caja delimitadora" será definida por dos vértices opuestos del cubo. Con estos dos vértices podremos componer toda la caja (está alineada con los ejes). Los vértices serán maxX,maxY,maxZ y minX,minY,minZ. El último miembro es el radio de la "bounding sphere", la esfera delimitadora del modelo. Solo necesitamos el radio porque vamos a asumir que los modelos que cargamos están todos centrados en el centro de coordenadas con lo que asumiremos como centro de la esfera contenedora la posición del modelo. Acordaos de centrar los modelos antes de salvarlos. Los datos los conseguiremos al cargar el modelo en la función CargaModelo(...), que ahora es parte de la clase modeloCOB. Incluiremos una variable para almacenar datos temporales para el cálculo del radio.
Luego, cada vez que cargamos un vértice, miraremos si tiene las coordenadas más pequeñas o más grandes para cada eje y, si es asÃ, las guardaremos. Al final tendremos las coordenadas más grandes y más pequeñas de todo el modelo, la "bounding box". También iremos comprobando la distancia de cada vértice al centro de coordenadas (0,0,0) para, al final, quedarnos con la mayor, el radio de la "bounding sphere". Con el primer vértice inicializamos las variables.
Recuerdo que este código va introducido en el bucle en el que cargamos los vértices y se repite con cada vértice. Al final de la carga tendremos los datos de los "bounding volumes" a nuestra disposición para lo que queramos usarlos. Haremos una última modificación de esta función para resolver un problema. En los modelos sin textura no se cargaban bien las coordenadas de textura aunque las tuviera definidas y era por que no se inicializaban las variables tOffset y tRepite. Si el modelo no tenÃa textura se quedaban sin definir (tÃpico fallo). Luego al multiplicar y sumar estas variables a las coordenadas de textura daban resultados inpredecibles. La solución es simplemente inicializarlas siempre, haya o no textura.
Con esto hemos terminado con el fichero USWmodelo.h. Vamos ahora con el fichero USWshader.h. Básicamente contiene la clase shader que gestiona la carga de los shaders. Cada objeto de tipo shader que creemos nos permitirá tener un fragment y un vertex shader que podremos usar facilmente. El código es el de el anterior capÃtulo pero incluido en una clase. La definición de la clase es esta.
El único cambio es en el destructor de la clase. En el anterior capÃtulo se me olvido la parte en que se eliminan los shaders y el programa (mis disculpas). En todo caso el código es auto explicativo.
No me extiendo más en este fichero; no creo que sea necesario. Echadle un vistazo al fichero. El fichero más importante, y el primero que hay que incluir, es USW.h. Sobre este fichero no hay gran cosa que decir porque el código que tiene no ha cambiado, solo se ha movido aquà para hacer más paqueño el ".CPP". Solo queda el fichero usw22.cpp. Aquà está la función Inicia() en la que no hay código nuevo pero hemos incluido en ella la ultima parte de lo que estaba en la función IniciaGL(). En ella cargaremos texturas, modelos, shaders, ..., definiremos luces, lo que sea antes del bucle principal. Esta función se ejecuta una vez al iniciar el programa (de hay su nombre). El único cambio reseñable es la forma de cargar el modelo. Ahora lo haremos como una función miembro de un objeto en vez de como una función independiente.
Como habréis notado, cargamos un modelo nuevo. Al final está el link La función Cierra() se ejecutará una vez antes de salir del programa. Aquà eliminaremos objetos y liberaremos memoria. De momento solo las texturas. En la parte de las definiciones globales, arriba, primero incluiremos los anteriores ficheros que hemos creado.
Las dos variables del tamaño de la ventana las dejo las primeras porque se van a usar en USW.h. Las dejo aquà para cambiarlas más fácil si se quiere. Creo un objeto de la clase modeloCOB para nuestro modelo.
A partir de ahora podremos cargar facilmente muchos modelos, simplemente creando un objeto de esta clase por cada modelo que se quiera cargar. Añado una variable para usar la tecla "B" (la usaremos para cambiar entre pintar bounding box o bounding sphere).
Y otra como indicador de lo que se está pintando.
Llegamos por fin a la función Pinta(), la de toda la vida. El primer cambio es que la función PintaModelo() es miembro de un objeto.
Tras pintar el modelo pinto el "bounding box" o la "bounding sphere" en base a la variable "bound", definida antes, alrededor del modelo. Para la esfera usaremos las "Quadrics" de la librerÃa GLU. Para la caja usaremos lÃneas, aunque no pintaremos todas, no es necesario para verla.
Por fin, solo queda el código para cambiar entre esfera y caja con la tecla "B" (cambiando la variable "bound"), y escribir en pantalla un mensaje del uso de esta tecla.
Al final, el programa ejecutándose debe verse asÃ: ![]() Los ficheros de código serÃan estos: usw22.cpp . USW.h . USWmodelo.h . USWshader.h . El modelo es este: cosa.cob . Con los billboard se podrÃa haber hecho lo mismo que con los modelos y los shaders, encapsularlos en una clase para usarlos fácilmente. Tal vez más adelante. ¡Sólo los usuarios registrados pueden escribir comentarios!
3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved." |