Todo aporte que puedan hacer siempre será bienvenido :)
Intentaré hacer un punteo breve de los temas que se estuvieron tratando en las clases de consulta.
Skybox
Es una técnica que consiste en encerrar la escena en un cubo sobre el que se mapea una textura especialmente diseñada. Si buscan skybox en Internet van a encontrar ejemplos de estas texturas y tutoriales de cómo implementarlo.
Cosas que tienen que tener en cuenta:
- La cámara tiene que estar situada en el centro del cubo. La textura se fabrica con esta hipótesis para que no se noten las aristas y vértices del cubo.
- Se puede dibujar antes que el resto de la geometría de la escena usando un cubo "relativamente pequeño" y desactivando el z-buffer. De esa forma se asegura que el cubo va a estar dibujado en el fondo.
- No tiene sentido que las lucen cambien el color del skybox, por lo que se pueden desactivar las luces.
Lens Flare
Por más que es un artefacto de las cámaras fotográficas, a menudo es utilizado a propósito para aumentar el realismo de las imágenes.
Aunque es un efecto relacionado con la luz, hay que implementarlo a parte de las luces de OpenGL.
El efecto se logra dibujando geometría en ciertos puntos de la escena (depende de la posición de la luz y de la posición/orientación de la cámara) con una textura específica.
Hay varios tutoriales a la vuelta, pueden ver uno aquí.
Height map
El mapa de alturas representado como una imagen en tonos de grises tiene una interpretación concreta.
Cada pixel contiene la altura de un vértice en una malla poligonal. Con una imagen de 512x512 se puede generar una malla de 511x511 quads.
En el contexto del obligatorio se tendría que hacer un doble FOR para crear la malla poligonal.
Es razonable que se utilice alguna de estas primitivas:
- GL_TRIANGLES
- GL_TRIANGLE_STRIP
- GL_QUADS
- GL_QUAD_STRIP
Para cargar el mapa de alturas se puede utilizar la misma librería para el cargado de texturas.
Una funcionalidad estándar de dichas librerías es que se puede acceder a la información individual de cada pixel.
En el caso de que la imagen sea en tonos de grises, cada pixel es representado en 8 bpp (256 valores distintos). Ese valor ya puede ser interpretado como altura.
En el caso de que la imagen tenga 24 bpp o 32 bpp, para que los pixels sean grices se tiene que cumplir que los tres componentes de color tengan el mismo valor. En este caso se puede utilizar cualquiera de los tres componentes como altura.
En respuesta a Mauricio Eguia
Re: Temas que hablaron en las clases de consulta
Yo generé un mapa de alturas con hme y lo guardé en formato BMP. Lo que hago es leer ese BMP e ir guardando la cantidad de azul, verde y rojo que tiene cada píxel. Probé de imprimir esos valores y en general, son distintos entre ellos. Es decir, para un mismo píxel obtengo valores distintos de azul, verde y rojo, lo cual me parece razonable. La duda está en cuál de esos valores tengo que tomar como la altura. En una página de internet leí que se tomaba el color azúl, pero me queda la duda. Además, independientemente de eso, el terreno me queda con una "fila de picos" y el resto todo plano. A lo mejor es por la escala que tomé. Consideré que el valor 255 se correspondía con la altura 20.
En respuesta a Marcela Viera Pereira
Re: Temas que hablaron en las clases de consulta
de Mauricio Eguia -
Los grises cumplen que R=G=B.
Mandame un mail con el archivo de imagen que estás utilizando e intentaré averiguar lo que te está pasando.
Cargado de modelo y dibujado
Para que no pierdan tiempo en buscar/probar otros cargadores, pueden utilizar el assimp.
Cargar un modelo se hace en una línea, especificando la ruta hasta el archivo del modelo.
Para dibujar el modelo, no está permitido utilizar cualquier funcionalidad que transforme en trivial dicha tarea.
El estudiante tiene que trabajar directamente con la información almacenada en las estructuras de la librería, dibujando cada polígono con la información que sea necesaria (color, texturas, normales, etc).
En la documentación de la librería hay ejemplos de cómo hacerlo.
Bounding volume
Para no tener que hacer chequeo de colisión entre cada polígono de un modelo contra todos los de otro modelo, se suele utilizar un volumen que envuelva una porción de la geometría para disminuir la cantidad de cuentas.
Se puede utilizar una caja orientada según los ejes (AABB) o una esfera (entre otros).
Después de que los envolventes están en contacto, se puede pasar a hacer un chequeo "polígonos contra polígonos".
En el contexto del trabajo obligatorio basta con que la colisión sea convincente. No es necesario calcular las colisiones con demasiada precisión para generar dicha impresión.
Interacción entre la nave y la malla poligonal
Cuando se detecta una colisión entre la nave y la malla poligonal ... se gana o se pierde!
No es necesario programar una respuesta a la colisión.
En el caso que se pierda, se puede dibujar una explosión en el lugar en donde la nave colisiona con la malla.
Otra alternativa que comenté en la clase de consulta fue de que, como el modelo de la nave está hecho de polígonos, se pueden desplazar cada polígono de forma independiente para que parezca que se desintegra.
Si implementan otro efecto que sea interesante visualmente, va a ser tenido en consideración para la nota.
Hilos
No es necesario utilizar hilos.
Tiendo a pensar que va a ser mayor el esfuerzo que el beneficio.
Por lo general, cuando se trata de aplicaciones gráficas no es interesante actualizar el sistema más veces de lo que se dibuja (se hacen cálculos que luego no se ven). Tampoco es razonable dibujar más veces de las que se actualiza el sistema (se dibuja dos veces la misma escena).
Con esta forma de analizar el problema se llega a la conclusión de que 1 update x 1 render es la combinación más conveniente.
Problemas de performance
Los motivos que llevan a tener problemas de desempeño son varios y depende de la aplicación.
Si se usa un modelo con muchos polígonos puede llegar a ser un problema.
La solución es cambiar de modelo. He notado que varios grupos usaron modelos de la NASA, una alternativa es http://www.celestiamotherlode.net/catalog/spacecraft.php
Pueden hacer búsquedas en internet agregando "low poly". Es un término utilizado en modelado 3D para indicar que el modelo tiene poca resolución en cantidad polígonos.
Siempre que no se generen artefactos al dibujar la geometría, se puede hacer backface culling para dibujar menos geometría (puede bajar considerablemente la cantidad de accesos al buffer de color).
Es aconsejable utilizar display list y vertex array si se quiere mejorar el rendimiento de la aplicación.
El cambio de modo inmediato a usar display list es casi trivial, para usar vertex array hay que hacer más cambios pero se consigue mejor performance.
Si se utilizan display lists, siempre que la geometría a dibujar no cambie no es necesario compilar una nueva lista. El compilado de una lista nueva es un desperdicio si no es necesario hacerlo.
Por ejemplo: si en cada frame reservan un identificador de display list y compilan una nueva lista (sin liberar la memoria de las listas que ya no se utilizan), al poco tiempo habrán dejado suficiente memoria colgada como para que la aplicación se tranque.
Las texturas se deberían cargar una vez por aplicación y luego utilizar los identificadores de texturas para hacer los glBindTexture que sean necesarios.
Cargar una imagen desde el disco duro tiene un costo considerable, además de que pasar la información a OpenGL para que lo utilice como textura lleva su tiempo.
Para pasar una imagen a OpenGL de 512x512 con 32bpp (tiene canal alpha) es necesario pasar 1MB hacia la tarjeta de video, mientras que si la imagen es de 1024x1024 son 4MB.
En el caso de que la imagen sea construida por la aplicación, sólo estarán ahorrando el tiempo de cargado desde el disco dura.
En una aplicación (y en particular una orientada a objetos) el reservado y liberado de memoria es un factor crítico de la performance.
Utilizar un pool de objetos puede ser una alternativa cuando se crean muchos objetos con un tiempo de vida corto.
Textura en la malla poligonal
Aplicar toda una textura (en particular cuando siempre es la misma textura) a un polígono no genera el mejor de los efectos.
Lo que termina pasando es que al estar lejos de la malla se notan patrones en la repetición de la textura y eso lleva a que se puedan distinguir los polígonos de forma individual.
Una alternativa sin utilizar más de una textura es aplicar toda la textura a un conjunto de polígonos.
Por ejemplo, si se aplica la textura a 100 polígonos (10x10) se pueden asignar coordenadas del estilo [0, 0.1, 0.2, ... , 1] a los vértices de los polígonos.
Si se está utilizando GL_REPEAT (la textura es tileable, ejemplo) o GL_MIRRORED_REPEAT en la función glTexParameterf, se pueden utilizar coordenadas afuera del rango [0,1].
La cantidad de polígonos a los que se le aplique la misma textura queda a criterio de los estudiantes.
No importa cual sea la primitiva utilizada para dibujar la malla poligonal, siempre se puede trabajar de esa forma (por más que la primitiva sea GL_QUAD_STRIP o GL_TRIANGLE_STRIP).