Menú Cerrar

En busca del fuego

En busca del fuego

Con este primer post del año inicio una pequeña serie dedicada a efectos visuales clásicos. La mayoría de estos efectos se basan en las matemáticas de fractales. Para explicar lo que son los fractales hay gran cantidad de webs sobre matemáticas que lo explican mucho mejor que yo. Me centraré en la base para crearlos mediante código, en este caso como crear fuego en el canvas de HTML5.

Antes de nada aclarar que dependiendo del entorno se pueden encontrar librerías y códigos para adaptar a las necesidades o listos para utilizar. Yo siempre he preferido entender las cosas y una vez entendido utilizar lo que mejor quede.

El fuego:

1

 

Es necesaria una paleta de colores, en este caso con el clásico tamaño de 256, aunque no es una ley inamovible. La paleta es un array de arrays ([rojo, verde, azul, alfa]) y el indice de cada color en ese array es lo que se utiliza para saber que color tiene cada pixel, en el array fuego. Cuantos más colores más posibilidad de hacer la diferencia entre colores más suave y amplia. La paleta es la que hará que el fuego sea creíble, naturalmente si se quiere un fuego menos natural (azul, verde, fucsia, etc) sólo hay que jugar con los colores. En este ejemplo se definen 4 rangos de 64 colores, en el primero comprende desde negro a rojo, el segundo de rojo a amarillo, amarillo a blanco y en el último todos los colores son blanco (#ffffff). En este ejemplo es necesario tener 64 colores con el blanco repetido pero esto se puede adaptar y mejorar como se quiera.

El array fuego será el que contendrá los indices de los colores según la paleta. Tendrá el mismo tamaño que el canvas. Al principio se establece todo en negro. Los colores de este array se irán pasando fotograma tras fotograma al array del ImageData creado y escrito después en el canvas, que será lo que realmente se vea por pantalla.

La función randomLimite servirá para que la generación de la última línea genere los pixeles blancos al azar. La última línea es la semilla y contendrá pixeles blancos o negros.

La función quema es la principal y su repetición es lo que anima el fuego, en este caso se llamará utilizando window.requestAnimationFrame. Hay un control de fotogramas por segundo (fps) que en el ejemplo los deja en 25. Se tiene que tener en cuenta que window.requestAnimationFrame puede repetir la función que se le indique hasta 60 veces por segundo y con los fps se pretende que sean menos veces, se puede eliminar este control si se quiere, la diferencia es poco apreciable para el ojo humano.

Paso a explicar el bucle principal que se encarga de que el fuego cobre vida. Hay que tener en cuenta que el único momento en el que se utiliza el azar es en la generación de la última línea, la de abajo del todo. En este ejemplo no muestro la última línea en la pantalla ya que son puntos blancos sobre fondo negro y no pega con el fuego, pero el bucle la recorre. El bucle recorre el array fuego de abajo a arriba, ya que en las pruebas que he hecho, hacerlo de arriba a abajo daba peor resultado. Para establecer el color de cada pixel hay que sacar la media de la suma de los indices de los colores en la paleta de ese pixel, más el pixel que tendrá inmediatamente debajo, más el pixel de debajo a la izquierda y el de la derecha, después se divide entre la cantidad de pixeles sumados y se redondea para poder sacar un número entero entre 0 y 255 que se pueda utilizar como indice de la paleta. Resumiendo ((X,Y)+(X,Y+1)+(X-1,Y+1)+(X+1,Y+1))/4. El divisor será en la mayoría de las veces 4 pero hay que tener en cuenta los casos en los que el pixel está en uno de los bordes, en cuyos casos no existe el pixel correspondiente de debajo que queda fuera, en estos casos el divisor será 3.

Esquema de píxeles para generar fuego

Lo más fácil y claro sería hacer dos bucles for para recorrer el array. Uno para las filas (Y) que repitiera tantas veces como el alto del canvas y otro dentro con las columnas (X) repitiendo tantas veces como el ancho. Esta forma de hacerlo resulta poco eficaz ya que se recorre el array fuego para tratar los pixeles y después se vuelve a recorrer con otro bucle para coger cada color y «pintarlo» en el array del objeto ImageData, que después será escrito en el canvas. El ejemplo recorre el bucle con un while y va rellenando el array del ImageData al mismo tiempo. Cada pasada trata un pixel de abajo a arriba controlando si se está en un borde para no sumar el pixel que quede fuera, dando error si no se hiciera así. Si se encuentra en la última línea genera todos los pixeles blancos «semilla» al azar.

Al final de la función quema escribe el ImageData en el canvas y regenera la semilla para la línea de abajo.

Este ejemplo para crear fuego es muy básico, se puede modificar y adaptar como se quiera, jugar con los colores, meter algún que otro random más, etc.