XNA Demos (II): Reflexiones en tiempo real con cubemaps

descargar_codigoUno de los efectos más buscados en los videojuegos desde la transición del género a las 3D ha sido la posibilidad de generar reflexiones (como espejos o superficies metálicas) de una manera realista y convincente. Debido a la poca flexibilidad del renderizado por raster (sólo se dibujan los píxeles visibles por el volumen generado a partir de las matrices de vista y proyección), siempre se ha recurrido a “trucos” para simular el efecto. Por ejemplo, los motores con geometría basada en CSG aprovechan el uso de los portales para, creando una máscara mediante el uso del stencil buffer, redibujar los objetos visibles tal y como se verían reflejados.

Con el aumento de la potencia de las GPUs y el abaratamiento de la VRAM, se ha optado por utilizar un tipo especial de textura llamado “cubemap”, que como el nombre indica, almacena las 6 caras de un cubo. De esta manera, se puede representar todo el entorno que rodea a un punto determinado, y se pueden crear offline (con un editor gráfico, para dibujar por ejemplo un skybox que dé profundidad a la escena) o en tiempo de ejecución.

cubemapCubemap estático de la demo, reescalado

Uno de los motores que más emplean el uso de cubemaps es Source, si bien los utiliza sólo en su versión estática; al compilar un mapa, y mediante un comando especial, se ordena que se generen los cubemaps en determinados puntos designados por el diseñador. El problema de este método es que las reflexiones sólo mostrarán los objetos estáticos del mapa, así que si creamos una superficie totalmente reflectante y situamos al jugador delante suyo, no habrá cambio alguno.

Un método más realista es actualizar los cubemaps dinámicamente, para que reflejen todos los cambios de la escena. Sin embargo, éste método también tiene sus desventajas: hay que dibujar la escena 7 veces (una por cada cara del cubemap y otra para el resultado final), así que hay que pensar en métodos para rebajar la carga: usar sólo un cubemap dinámico al tiempo, actualizar únicamente 2 caras a cada frame…

Por último, la demo también incluye un efecto de refracción, con una constante de transmisión del medio de 0.66, para simular vidrio. La única diferencia entre los dos shaders es la instrucción usada para calcular el vector que se empleará para obtener el téxel del cubemap, que en un caso es reflect y en el otro refract.

reflex_refract Vectores de reflexión y refracción.

01/01/2010: actualizado el código para mejorar el rendimiento del Cubemap dinámico.

Disponible el vídeo del webcast

Ya está publicada la grabación en vídeo del webcast sobre programación 3D con XNA que di el miércoles pasado. Podéis verlo aquí, y descargar los materiales necesarios para desarrollar el ejemplo aquí.

La verdad que me gustaría continuar con estas aportaciones para tratar de darle un empujón a XNA. Si tienes alguna idea o sugerencia que te gustaría ver desarrollada, contacta conmigo y trataré de encajarla en la temática de los siguientes eventos 😀

XNA Demos (I) – Bloom

Tras un período de semi-abandono del blog (¿alguien me puede vender algo de tiempo libre?), he terminado y documentado de una vez por todas la primera de una serie de demos en la que llevo trabajando unas semanas.

Uno de los aspectos que más me gusta de XNA que al incorporar una capa de abstracción a bajo nivel, evita perder tiempo en tareas tediosas como la programación de cargadores, gestores de recursos y demás parafernalia, permitiendo centrar el proceso de desarrollo adecuadamente.

Aprovechando este potencial, y con cierta curiosidad por conocer las diferencias entre HLSL y GLSL, me he decidido a dejar de lado OpenGL una temporada (¡y eso que soy un fan acérrimo!) y continuar empleando XNA para la programación de shaders. El primer resultado os lo traigo hoy, en forma de un shader de bloom basado en los métodos descritos en la sección “Making Your Whites Whiter and Your Brights Brighter” del libro OpenGL SuperBible, 4ª edición, páginas 630-638.

El proceso para obtener este efecto consiste en renderizar la escena a un RenderTarget2D, y a partir de esta copia realizar sucesivas acciones. En primer lugar se reescala hasta obtener una textura de 2×2 píxeles de la que se extrae la luminancia media de la escena; este valor se emplea para descartar los píxeles demasiado oscuros, y mediante sucesivas operaciones de reescalado y desenfoque gaussiano, se obtienen cuatro imágenes que superpuestas dan el resultado final. A continuación hay un diagrama que explica el proceso con más claridad (porque una imagen vale más que mil palabras 😉 ).

diagrama_bloom

El código fuente del proyecto lo podéis descargar de este enlace. En el archivo comprimido se incluye una explicación de los controles para manejar el programa y una copia de la licencia: GPL v3 para el código y Creative Commons by-sa para el contenido (modelo de la esfera y textura).

¡Espero que os sea útil!