Esta va a ser la primera entrada algo
técnica del blog. Tampoco mucho, la mayoría de conceptos se pueden
entender siguiendo la lectura, aunque con conocimientos sobre
generación de sombras y algo de Unity se saca todo el jugo.
En la primera
parte del artículo sobre las sombras del veneno, hablaba sobre
la idea de que la sombra de un objeto fuera diferente a la que se
espera que proyecte como recurso gráfico y narrativo.
Todo tenía buena pinta, pero llega el
momento de ¿y eso cómo lo hago?. Partimos de la primera idea, que
el héroe tuviera la sombra de otro ser. Por ejemplo que la sombra
tuviera alas, como si fuera un Ángel.
Estuve dando vueltas a esto. Una idea
es hacer un modelo del personaje con alas, hacer una capa de render
donde se pinte ese modelo alado, y en los shaders de esta pasada
ignorar el modelo y usarlo solamente para pintar la sombra. Y en una
segunda capa cambiar el modelo por el personaje normal y pintarlo,
esta vez sin sombra.
Técnicamente es posible, y puede que
use esta técnica alguna vez para lograr algún efecto, pero es una
técnica compleja. Hay que tener los 2 modelos, tener los dos
animados, animar los dos a la vez (es decir si el modelo normal
levanta el brazo, que el modelo alado también lo levante para que la
sombra salga con el brazo levantado), sincronizar el movimiento de
ambas, hay que crear la forma de hacer esas 2 pasadas de render y
hacer los shaders apropiados. Y además el cambio de un modelo a otro
y tener 2 pasadas puede ser computacionalmente crítico. Sobre todo
en dispositivos móviles, donde la memoria de vídeo está bastante
limitada.
La segunda forma de hacer esto es
pre-calcular la sombra para la animación interna y poner un objeto
plano que sea la sombra. Lleva más trabajo previo, pero es
computacionalmente más barato. La idea sería tener una imagen de la
sombra para cada frame de animación interna. Se podría incluso
pintar a mano sin llegar a modelar la versión del héroe con alas.
Habría que cambiar la imagen de la sombra con cada frame de
animación y moverla y colocarla de forma correcta según el
movimiento externo del personaje.
Y aquí vienen los líos. Lo primero,
¿dónde está el suelo?. Si el personaje no se moviera del suelo
podríamos poner la sombra a sus pies, pero el personaje salta y
sería muy raro que la sombra “saltase” con el personaje ¿no?.
Así que tenemos que calcular la altura del suelo para colocar allí
la sombra (realmente un poquito más arriba para evitar parpadeos por
problemas de precisión). Si tuviéramos todo el suelo de la pantalla
sería pan comido, un valor fijo, pero vamos a suponer que vamos a
querer plataformas a varias alturas, cuestas... un escenario
complejo. Podríamos tomar la altura del suelo tirando un rayo desde
el personaje hacia abajo (con una máscara para solo comprobar
colisiones contra suelo, aunque esto también lleva a errores), y
donde colisione es suelo. El mayor problema viene cuando la sombra no
está entera sobre un solo suelo. Por ejemplo si estamos saltando
hacia un precipicio para llegar a una plataforma, puede que media
sombra quede en el suelo y media en el aire, pero es muy extraño ver
una sombra flotando en el aire. Esto se podría solucionar
comprobando bit a bit en la sombra si está sobre el terreno, pero
así no ganamos respecto a calcularlas respecto a tiempo real. Se
pueden hacer muchas mejoras, algoritmos excelentes, usar herencia de
polígonos contenedores en la sombra por ejemplo. Pero lo que quiero
hacer ver es que lo que parecía una solución muy sencilla se
complica mucho.
Y aquí llegamos a las simplificaciones
que asumí y la solución que tomé al final. Hay que tener en cuenta
que tenía que entregar el juego para la asignatura, con poco tiempo
y tenía que hacer un balance para conseguir los efectos que quería
sin morir en el intento. Lo primero decidí cambiar quien tiene la
sombra extraña, y ya no es el héroe sino el veneno. Esto es porque
el veneno no tiene animación interna. No mueve brazos ni nada así,
por lo que solo hay que ver donde va la sombra, si es más grande o
más pequeña (según la altura del veneno o su distancia a la luz),
pero puede hacerse siempre con la misma imagen. Ya comenté en el
artículo anterior las 4 sombras y las situaciones en que se daban.
La solución por la que opté al final
fue usar un proyector. Es un componente de Unity que permite
proyectar una imagen. Se configura de forma similar a una cámara,
con planos de proyección, aspect-ratio, etc y le ponemos la imagen
que queremos que proyecte como un material (así que podría ser
textura, textura procedural, video...). Este sistema se está usando
mucho en juegos para móviles, por ejemplo creo que se usa en el
juego Angry Birds Go, por como se ven las sombras.
Tiene sus cosas buenas y malas. Lo
bueno es que la sombra queda automáticamente donde debería. Es
decir, si hay unos escalones, se va adaptando a esa forma, o si hay
objetos entre el proyector y el suelo. Que la sombra sea correcta o
creíble depende de la imagen que nosotros le pongamos. Es un método
computacionalmente mucho más barato que calcular las sombras en
tiempo real, y por eso se usa mucho en móviles. No tiene en cuenta
la luz, es ideal para una escena iluminada por luz direccional. Ya
que si tenemos una luz puntual o varias tendríamos que ir cambiando
la orientación del proyecto. Pero no tiene en cuenta oclusiones, si
el personaje se mete debajo de un saliente o se acerca a una pared y
no le da la luz emitirá sombra igualmente. Pero bueno, la mayoría
de métodos de iluminación en tiempo real son locales y no tienen
esto en cuenta tampoco.
El otro gran problema lo podemos tener
con la orientación. Si ponemos el proyector en el objeto de nuestro
personaje, se moverá con él. Imaginemos por ejemplo que ante cierto
golpe el veneno gira dando una vuelta de campana, el proyector
también giraría y la sombra pasaría a desaparecer del suelo para
proyectarse por paredes y techo, como si el sol estuviera girando
alrededor. Por eso es recomendable aislar el proyector del modelo,
ponerlo en otro objeto, preferiblemente el padre del objeto que tenga
el modelo y realizar las traslaciones en el objeto proyector, pero
las rotaciones en el objeto del modelo.
Conclusiones: El proyector es un gran
elemento para hacer sombras sencillas, sin animación interna, a bajo
coste. Tenemos libertad creativa en esas sombras, y todo desde la
interfaz de alto nivel. Pero si hago algo parecido para el personaje
principal tendré que usar otro método a bajo nivel.
No hay comentarios :
Publicar un comentario