A todos nos gusta ver paisajes bonitos en los videojuegos, unas montañas, vegetación, una puesta de sol, y como no, un lago/río/mar donde podamos ver el sol y las montañas reflejadas. Eso vende y los desarrolladores lo saben, por supuesto.
Para conseguir un efecto de agua realista, el reflejo es fundamental, y es de lo que vamos hablar en este artículo. No solo necesita que sea bonito, sino que el consumo de recursos sea razonable. A nadie le gusta tampoco ver paisajes bonitos si estos se ven a 2 frames por segundo. Por lo tanto, asumiendo que todo es mejorable y la perfección no existe, hay que llegar a un equilibrio entre la calidad del efecto y los recursos a consumir.
El modelo real
La luz rebota en las superficies hasta llegar a nuestro ojo.Lo primero es ver cual es el comportamiento del reflejo en el mundo real. En la imagen de la izquierda tenemos una montaña, un lago y nosotros estamos al otro lado. Como podemos ver, la luz rebota contra la montaña, esta a su vez contra el lago, y después llega a nuestros ojos. Debido al rebote, nosotros vemos la montaña boca abajo en el reflejo del lago, y debido al material en el cual rebota, hay una parte de luz que se pierde, por lo que el reflejo se ve más oscuro dependiendo de la potencia de la luz y el tipo de agua y su color. De momento lo vamos a simplificar al máximo, sin tener en cuenta las olas o la transparencia del agua, pero ya se puede intuir dos factores importantes. Primero, el angulo de visión cambia hacia arriba, con lo que puedes ver cosas que desde donde estas no verias. Y segundo, hay una pedida de luz, con lo que las cosas se deberían ver más oscuras que a simple vista.
El truco
El comportamiento de la luz en el modelo real es tan complejo que resulta imposible implementarlo para funcione en tiempo real y simular el comportamiento del modelo anterior. Por lo que el modelo se simplifica hasta ser perfectamente viable en un videojuego. El truco consiste en renderizar sobre una textura el reflejo del agua antes del renderizado principal. A esto se le llama prerenderizado, y se utiliza en muchos otros efectos.
La cámara que renderiza el reflejo está en una posición ‘espejo’ de la principal respecto al agua.La cámara que renderiza el reflejo se posiciona boca abajo, ya que el reflejo debe estar así, y a la misma distancia debajo del agua que lo está la cámara principal de esta, como se ilustra en la imagen de la derecha. Se podría decir que la posición de la cámara que renderiza el reflejo está en una posición espejo respecto al agua con la principal. Se mueve con ella, se gira con ella, pero siempre al revés. Como podéis intuir, esto implica que para realizar un solo frame hay que renderizar la escena dos veces, pero existen técnicas de optimizaciónque quitan mucho peso al prerenderizado del reflejo, que comentaremos más adelante.
El reflejo se proyecta sobre el agua como si se tratase de una cámara de cine.Pero una vez tenemos la imagen del reflejo en una textura, ¿Que hacemos con ella? Pues basta con proyectarla sobre el agua tal cual, como si la cámara de renderizado principal se tratara de una cámara de cine y el agua fuese un lienzo. Con esto cubrimos el primer punto del modelo real, el reflejo, pero ¿que hay del segundo? la perdida de luz debido al rebote. Lo que se hace es combinar el color de cada pixel del reflejo con el del agua, a nivel computacional es solo una multiplicación, y si por ejemplo tenemos un color de agua azul oscuro, el reflejo lo veremos mucho mas oscuro, con lo que también resolvemos el segundo punto.
El reflejo estático
Ejemplo de textura cúbica.Debido a los recursos necesarios para implementar un reflejo en tiempo real, lo que se suele utilizar en los juegos es el reflejo estático. Esto quiere decir que no se renderiza el reflejo en cada frame, sino que se renderiza el entorno una sola vez, durante el desarrollo del juego y se confecciona una textura cúbica. Consiste en una textura con forma de cubo, donde se renderiza lo que se ve desde un punto tanto hacia los cuatro lados, como arriba o abajo(en este caso, el abajo no nos haría falta). Es lo mismo que se utiliza, por ejemplo, para representar el cielo, mireis donde mireis veis la textura, porque es un cubo que os envuelve.
El agua de Mass Effect 3 está hecha con reflejo estático.En esta ocasión sí que es necesario calcular el rebote de la luz, pero se hace en sentido contrario, desde la cámara al agua, y desde el agua a la textura. Se hace el calculo por cada pixel del agua que se tenga que dibujar en un frame. El resultado es también bastante espectacular, no tanto como un reflejo en tiempo real, pero sí mucho menos costoso a nivel de recursos. ¿Pero no se nota el pegote? Bueno, lo que se suele hacer es que la textura cúbica se difumina, y queda emborronada, de forma que solo se distinguen las formas grandes, y no salta a la vista que los reflejos no coinciden, y por supuesto, los personajes no se reflejan, como si fuesen vampiros.
Optimización del reflejo en tiempo real
El reflejo en el agua real suele ser borroso.Esta claro, renderizar 1 vez por frame es mucho más rápido que hacerlo 2 veces, pero la cuestión es, ¿Es necesario que el renderizado del reflejo sea tan costoso como el principal? La respuesta es NO. Y no solo eso, si se hace de forma inteligente puede ser incluso mejor. Si miramos la imagen de la derecha, podemos ver como el reflejo de los edificios en el agua es borroso. Tanto, que prácticamente no podemos distinguir los coches, solo podemos apreciar los edificios y a duras penas los árboles. Por lo tanto, ¿ Deberíamos difuminar la imagen del reflejo antes de proyectarla en el agua? No hace falta, mejor la renderizamos a baja resolución. Y si no se van a ver los coches, ¿Para que dibujarlos? Si la imagen de la derecha perteneciese a un juego, podríamos simplemente dibujar los edificios y los arboles en el reflejo, y alguien que no se fije especialmente en ello, ni se daria cuenta.
Así que, contra menos cosas dibujemos y a menos resolución, más rapido se realizará el renderizado del reflejo, hasta no ser más que una pequeña fracción de lo que consume el renderizado principal.
Ejemplos prácticos
¿Veis los guerreros reflejados en el agua?Ahora vamos a ver unos ejemplos de efectos de agua en varios videojuegos, a ver si sabéis valorar cómo lo hacen y las optimizaciones que utilizan.
Empecemos con Dark Souls, el RPG de From Software. ¿Que tipo de reflejo creéis que utiliza? ¿estático o en tiempo real? Como podéis ver en la imagen de la izquierda, los guerreros se ven claramente reflejados, así como la rata gigante. Es difícil verlo en una imagen, pero utiliza el reflejo en tiempo real. También se puede apreciar que el reflejo se ve más oscuro y borroso, por lo que probablemente lo esté renderizando a menor resolución. Otras optimizaciones que utiliza es el renderizado de personajes según la distancia. Si la rata o el otro guerrero estuviese lo suficientemente lejos del jugador, su reflejo simplemente desaparecería. Es curioso de lo que no te das cuenta cuando no gastas especial atención en ello.
Geralt no se refleja, ¿es un vampiro?
El siguiente juego que vamos a mirar es The Witcher 2, en su versión ‘enhanced’ para Xbox 360. Es efecto del agua es muy bueno, pero el reflejo es estático. ¿Veis esos reflejos en el agua? ¿De donde vienen exactamente? ¿Veis alguna fuente de luz? No se corresponden exactamente con nada en concreto, pero ¿a que da el pego? Solo con haber hecho eso ya se han quitado un gran peso de encima. Imaginaos renderizar toda esa vegetación dos veces. Solo un PC bien armado lo podría hacer.
Esto no quiere decir que no esté trabajado el efecto, al contrario. Realizar una textura cúbica puede llevar más trabajo que el reflejo en tiempo real, ya que este se implementa una vez y vale para todo, en cambio la textura cúbica hay que realizarla para cada entorno. Sería un cante ver en esa escena un montón de arboles reflejados ¿verdad?
Que bien se ve todo reflejado. Casi como un espejo.Por último, vamos a romper un poco y nos vamos a un juego más antiguo. Por ejemplo, Naruto: Rise of a Ninja. Claramente es un reflejo en tiempo real, lo veis ¿no? Pero ¿sabríais ver las optimizaciones que realiza? Yo diría que el reflejo está a menor resolución y que renderiza los objetos según la distancia y el tipo de objeto. Por ejemplo, hay un arbusto al fondo que no se ve reflejado ¿lo veis?, pero en cambio la pared, que está mucho más lejos, sí que se dibuja. También podemos ver como el personaje que está mas a la derecha no se dibuja. Por lo tanto, utiliza un nivel de detalle diferente para el agua que para el renderizado principal.
Lo dejamos aquí. A partir de ahora podréis valorar mejor este efecto en particular en los juegos. Fijaos en vuestros juegos favoritos, seguro que os dais cuenta de cosas de las que no os habíais percatado.