El camuflaje activo es un concepto de ciencia ficción, que generalmente se ve en la forma de un traje que permite que el usuario se vuelva casi invisible. Se puede ver en películas como Predator y Die Another Day, y juegos como Halo y Crysis..
Este tutorial le muestra cómo lograr ese efecto en Flash al animar un filtro de desplazamiento utilizando una secuencia de mapas de bits. El efecto no solo es genial, sino que esta técnica rara vez se ve en los tutoriales en línea..
Echemos un vistazo al resultado final en el que trabajaremos:
El mapeo de desplazamiento es un mapa de textura que se utiliza para modular la fuerza de desplazamiento. Desplazamiento significa literalmente mover los píxeles de una superficie fuera de lugar. En la mayoría de las aplicaciones 3D, los píxeles se desplazan a lo largo de la superficie normal. En Adobe Flash, el desplazamiento ocurre en el espacio 2D, a lo largo de las coordenadas X e Y de una imagen.
Los filtros de desplazamiento en Flash suelen animarse cambiando dinámicamente su intensidad (los parámetros scaleX y scaleY), cambiando la posición del mapa de bits de desplazamiento (el parámetro mapPoint) o manipulando los canales de color. Este tutorial explicará con más detalle estas técnicas, pero también estudiaremos una diferente, que utiliza una secuencia de mapa de bits para dibujar un nuevo mapa de desplazamiento en cada cuadro..
Ejemplo de desplazamiento a lo largo de la superficie normal..
Ejemplo de mapeo de desplazamiento en flash, a lo largo de los ejes X e Y.
Abra un nuevo documento en Flash y configure el tamaño a 550x368 para que coincida con nuestra imagen de fondo. Establecer la velocidad de fotogramas a 48 fps. El filtro de desplazamiento realmente se ejecutará a 12 fps, pero en caso de que desee una animación adicional más adelante, se verá más suave a 48 fps.
Haga clic en Archivo> Configuración de publicación> Configuración de ActionScript 3.0 y desactive "declarar automáticamente instancias de la etapa".
Importar rainforest.jpg al escenario..
Presione Ctrl + K para alinear y hacer coincidir el tamaño del lienzo. Esta será nuestra imagen de fondo..
Ahora, con la imagen seleccionada, presione F8 para convertirla en un símbolo. Seleccione "Clip de película" en el menú de tipo.
Si la ventana de propiedades está cerrada, presione Ctrl + F3 para abrirla. Vamos a nombrar el clip de película que se acaba de crear. En el campo de nombre de instancia, escriba "bkgd_mc".
Ahora presione Ctrl + F8 para crear un nuevo clip de película por completo. No estamos nombrando esto todavía. Primero vamos a importar la secuencia de mapa de bits dentro de este clip de película. Vaya a Archivo> Importar> Importar a escenario. Seleccione la primera imagen de la secuencia, que se llama "pred0001.jpg". Flash le preguntará si desea importar todas las imágenes en esta secuencia. Haga clic en sí.
Notará que cada mapa de bits se coloca en un fotograma clave a lo largo de la línea de tiempo del clip de película. Comenzando en el fotograma 1, seleccione la imagen y presione F8 para convertirla en clip de película. Haga esto en cada cuadro hasta el final de la secuencia. Hágalo en orden, de lo primero a lo último, y asegúrese de no omitir ningún fotograma, de lo contrario, estropeará la animación..
Una vez que haya terminado, cada fotograma clave debe tener un clip de película que contenga un fotograma de la cara del personaje. Selecciona el cuadro uno de nuevo y presiona enter para ver la animación.
Seleccione el clip de película en el fotograma 1. Haga clic con el botón derecho y distribúyalo en capas. Una vez más, hágalo en todos los clips de película en todos los marcos. Cuando hayas terminado, ya no podrás ver la animación, solo la imagen en la capa superior.
Presione Ctrl + L para abrir la biblioteca y arrastre "Símbolo 2" al escenario. En la pestaña de propiedades nombre esta instancia "displ_mc". Este clip de película se utilizará en nuestro filtro de desplazamiento..
Vamos a escribir el código para nuestro filtro de mapa de desplazamiento dentro de un archivo de clase de documento. Cree un nuevo archivo de ActionScript y asígnele el nombre "pred_as3". Ahora pega este código:
paquete import flash.display.MovieClip; importar flash.display.BitmapData; importar flash.display.IBitmapDrawable; importar flash.display.BitmapDataChannel; importar flash.filters.DisplacementMapFilter; importar flash.filters.DisplacementMapFilterMode; importar flash.geom.Point; import flash.events.Event; clase pública pred_as3 extiende MovieClip
Regrese al documento flash y nombre la clase pred_as3.
Como puede ver, ya hemos importado todas las clases que necesitaremos en este tutorial, ahora continuemos escribiendo la clase de documento. Agregue este código a él:
private var clipcont = new Array (); // todos los cuadros animados se almacenarán en esta matriz private var count: Number; // parte del bucle enterframe; indica qué fotograma de animación se mostrará privado var timer: uint = 0; // establece la velocidad de la animación public var displ_mc: MovieClip; public var bkgd_mc: MovieClip;
Estamos indicando algunas variables que se utilizarán más adelante. Deben declararse antes que el constructor de la clase si van a ser utilizados por más de una función en la clase de documento..
Justo debajo de la última línea, comenzamos a escribir los parámetros y el constructor del filtro de mapa de desplazamiento..
fuerza privada var1: int = 120; // el valor de scaleX y scaleY: establece la intensidad del filtro de desplazamiento private var mapBitmap: BitmapData = new BitmapData (320,240); // el tamaño del mapa de desplazamiento en píxeles private var mapPoint: Point = new Point (0,0 ); // la posición del mapa de bits de desplazamiento privado var componentX = BitmapDataChannel.GREEN; // el canal de color que se usa; realmente no importa ya que está en tonos de gris; private var componentY = BitmapDataChannel.GREEN; private var spe: int = 1; // cambia la intensidad del filtro de desplazamiento // todas las variables se aplican a un nuevo filtro private var filter: DisplacementMapFilter = nuevo DisplacementMapFilter (mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY); private var filterList = new Array (); // una matriz de lista de filtros.
Así que hemos establecido parámetros para la fuerza, el tamaño, la posición y el canal RBG. Echemos un vistazo más de cerca a cada uno de estos parámetros ...
Como se mencionó anteriormente, el desplazamiento en flash solo es posible a lo largo de los ejes X e Y. Los parámetros que establecen la resistencia de desplazamiento para X e Y son escalaX
y escalable
respectivamente. En este tutorial usaremos la misma fuerza en los ejes X e Y, por lo que usaremos la misma fuerza variable1 para ambos parámetros. A continuación se muestra un ejemplo de desplazamiento a lo largo del eje horizontal, con scaleY establecido en cero (imagen izquierda), y el eje vertical, con scaleX establecido en cero (derecha).
Observe cómo el tamaño se establece en 320x240. Ya sabemos el tamaño de los mapas de bits en la animación y el constructor debe tener el mismo tamaño que ellos. Si el valor en el constructor es mayor que el de los mapas de bits, habrá un desplazamiento en áreas donde no debería ocurrir. El gris # 808080 alrededor de la cabeza del personaje es un color neutro, por otro lado, cualquier área que esté vacía o un mapa de bits transparente desplazaría la imagen de fondo.
Ejemplo de que el valor establecido en el constructor es más grande que el mapa de desplazamiento real: las áreas vacías desplazan el fondo.
El filtro de desplazamiento utiliza solo uno de los 3 canales RGB en un mapa de bits para cada eje. Cuando se utiliza un mapa de bits de color como un mapa de desplazamiento, cada canal dará resultados muy diferentes, como se muestra en el siguiente ejemplo. En este tutorial estamos usando una imagen en tonos de gris, por lo que el canal es irrelevante. ComponentX y componentY están configurados en verde, pero el mismo efecto se obtendría usando los canales rojo o azul.
Los diferentes resultados obtenidos utilizando el canal verde, el canal rojo o el canal azul..
El parámetro mapPoint establece la posición del mapa de desplazamiento. La posición es relativa al objeto al que se aplica, y no al escenario. Al establecer la posición en (0,0), el mapa de desplazamiento aparece en la esquina superior izquierda de nuestra imagen de fondo, que no siempre coincidirá con la esquina superior izquierda del escenario, como se muestra a continuación.
El parámetro mapPoint es relativo al objeto, no al escenario..
Ahora apliquemos el filtro de desplazamiento a nuestra imagen de fondo "displ_mc". El filtro de desplazamiento se inserta en una serie de filtros, y lo hacemos dentro del constructor de clases. También estamos agregando nuestros dos clips de película principales al escenario con el método addchild. En AS3, el constructor de la clase es la primera función que se ejecuta en una clase de documento y se llama automáticamente, por lo que es mejor que cualquier función o método que deba ejecutarse durante la carga se llame desde un constructor de clase..
función pública pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // agregar las dos instancias de Clip de película a la etapa filterList.push (filtro); // agregar el filtro de mapa de desplazamiento a la matriz. bkgd_mc.filters = filterList; // aplica el conjunto de filtros al clip de película de destino. storeClips ();
La última línea de código está llamando a una función que aún no se ha escrito. Como su nombre indica, esta función almacenará todos los clips de película animados en una matriz. Así que sigamos adelante y escribamos eso ahora..
Así que creamos un filtro de mapa de desplazamiento y lo aplicamos al clip de película, pero aún no hemos agregado ningún mapa de bits al filtro. Vamos a hacer esto en dos pasos: primero vamos a almacenar la animación en una matriz, luego agregaremos esta animación al filtro.
private function storeClips (): void // almacena la animación en una matriz count = displ_mc.numChildren; // el número total de clips de vídeo dentro de displ_mc para (var i: int = 0; i < displ_mc.numChildren; i++)//finds all movieclips inside displ_mc clipcont.push(displ_mc.getChildAt(i));// frames are pushed inside the clipcont array
Esta función utiliza un para
bucle para escanear todos los clips de película dentro de displ_mc. Queremos los cuadros de animación que se convirtieron a clips de película anteriormente en este tutorial. ¿Recuerdas cuando te dije que los convirtiera cuadro por cuadro? Hicimos eso para que los marcos se pudieran ordenar correctamente y luego se accediera usando el método getChildAt (). Como no nombramos ninguno de esos casos, Flash los clasifica internamente por orden de creación. Si los mapas de bits se convirtieran aleatoriamente en clips de película, la animación nunca se reproducirá correctamente. Por lo tanto, ahora se pueden insertar los cuadros en la matriz clipcont, uno por uno.
El código hasta ahora debería verse así:
paquete import flash.display.MovieClip; importar flash.display.BitmapData; importar flash.display.IBitmapDrawable; importar flash.display.BitmapDataChannel; importar flash.filters.DisplacementMapFilter; importar flash.filters.DisplacementMapFilterMode; importar flash.geom.Point; import flash.events.Event; public class pred_as3 extiende MovieClip private var clipcont = new Array (); // todos los cuadros animados se almacenan en esta matriz private var count: Number; // parte del bucle enterframe; indica qué fotograma de animación se muestra privado var timer: uint = 0; public var displ_mc: MovieClip; public var bkgd_mc: MovieClip; fuerza privada var1: int = 120; // establece la intensidad del filtro de desplazamiento private var mapBitmap: BitmapData = new BitmapData (320,240); // el tamaño del mapa de desplazamiento en píxeles private var mapPoint: Point = new Point (0,0); // la posición de el mapa de bits de desplazamiento privado var componentX = BitmapDataChannel.GREEN; // qué canal de color se usa; realmente no importa ya que está en tonos de gris; private var componentY = BitmapDataChannel.GREEN; var privado spe: int = 1; // todas las variables se aplican a un nuevo filtro privado var filter: DisplacementMapFilter = new DisplacementMapFilter (mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY); private var filterList = new Array (); // una matriz de lista de filtros. // CLASS CONSTRUCTOR public function pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // agregar las dos instancias de Clip de película al escenario storeClips (); filterList.push (filter); // agrega el filtro de desplazamiento a la matriz. bkgd_mc.filters = filterList; // aplica el conjunto de filtros al clip de película de destino. private function storeClips (): void // almacena la animación en una matriz count = displ_mc.numChildren; // el número total de clips de video dentro de displ_mc para (var i: int = 0; i < displ_mc.numChildren; i++)//finds all movieclips inside displ_mc clipcont.push(displ_mc.getChildAt(i));// frames are pushed inside the clipcont array
Ahora que tenemos la animación lista para usar, pongámosla en el filtro de desplazamiento. Vamos a acceder a la matriz de clipcont con un bucle de "tiempo liberado" utilizando el Evento.ENTER_FRAME
clase. Cada 4 cuadros, se accede a un nuevo mapa de bits en la matriz, y luego se aplica al filtro usando el método draw (). Después de dibujar el último cuadro en clipcont, el bucle comienza de nuevo y el primer cuadro en clipcont se dibuja. Es un bucle sin fin.
función privada animate (e: Event) filter.scaleX = strength1; // establece el valor de scaleY y scaleX filter.scaleY = strength1; if (timer> 3) // se dibuja un nuevo marco cada 4 frames if (count <= 0) count = clipcont.length;// setting an infinite loop count--; timer = 0; if (clipcont[count]) filter.mapBitmap.draw(clipcont[count]);// a new frame of animation is drawn bkgd_mc.filters = filterList;//updates the filter
Copia las líneas de arriba a tu archivo de acciones. Ahora hagamos esto ejecutando agregando un detector de eventos al constructor de clases.
función pública pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // agregar las dos instancias de Clip de película a la etapa filterList.push (filtro); // agregar el filtro de mapa de desplazamiento a la matriz. bkgd_mc.filters = filterList; // aplica el conjunto de filtros al clip de película de destino. storeClips (); addEventListener (Event.ENTER_FRAME, animate); // llama a la función animar al entrar en el cuadro
Actualizar el constructor de la clase con el addEventListener
método. Ahora la función animada se ha agregado al escenario y se llama en cada fotograma. Probar el efecto presionando Ctrl + Enter. Debería ver la cara animada en la esquina superior izquierda de su película.
Tenemos un bucle de animación corriendo en la esquina de la película. Hagamos que el mapa de desplazamiento siga al mouse, de esta manera podrá ver cómo se ve el efecto de camuflaje activo en diferentes partes del fondo. Pega esta línea dentro de la función animar:
función privada animate (e: Event) filter.scaleY = strength1; // establece el valor de scaleY y scaleX filter.scaleX = strength1; temporizador ++; if (timer> 3) // se dibuja un nuevo marco cada 4 frames if (count <= 0) count = clipcont.length;// setting an infinite loop count--; timer = 0; if (clipcont[count]) filter.mapBitmap.draw(clipcont[count]);// a new frame of animation is drawn filter.mapPoint = new Point(mouseX-160, mouseY-240); // displacement map follows the mouse bkgd_mc.filters = filterList;
De esta manera, actualizamos la posición del mapa de desplazamiento sobre la base de un cuadro de ingreso usando las propiedades mouseX y mouseY. Presiona Ctrl + Enter para probarlo. La cabeza ahora debe seguir al ratón..
En el último paso de este tutorial vamos a jugar un poco con la fuerza de nuestro filtro, aumentando el valor de los parámetros scaleX y scaleY durante un período de tiempo, y luego volveremos a disminuir al valor inicial. Lo que estamos tratando de lograr con esto es hacer que el efecto se vea más dinámico y ... visible. Si bien el objetivo de un camuflaje en la vida real debería ser hacer que las cosas sean menos visibles, lo que intentamos hacer aquí es hacer que se vea bien. Congelemos la animación para que puedas entender de lo que estoy hablando. En la función animar, reemplaza la línea
filter.mapBitmap.draw (clipcont [count]);
con esta línea en su lugar:
filter.mapBitmap.draw (clipcont [20]);
En lugar de dibujar la animación, le decimos a flash que dibuje el mismo cuadro una y otra vez. Presiona Ctrl + Enter para probarlo.
El efecto se ve completamente estático y aburrido. Vamos a darle algún movimiento. Pegue el siguiente código dentro de la función animar:
función privada animate (e: Event) filter.scaleY = strength1; // actualiza el valor de scaleY y scaleX filter.scaleX = strength1; temporizador ++; if (timer> 3) // se dibuja un nuevo marco cada 4 frames if (count <= 0) count = clipcont.length;// setting an infinite loop count--; timer = 0; if (clipcont[count]) filter.mapBitmap.draw(clipcont[20]);// a new frame of animation is drawn filter.mapPoint = new Point(mouseX-160, mouseY-240); // displacement map follows the mouse if (filter.scaleX > 220 || filter.scaleX < 120) // filter keeps changing it's intensity, making the effect more dynamic spe *= -1; strength1 += spe; bkgd_mc.filters = filterList;
Ahora pruébalo con Ctrl + Enter.
¿Ves que mejor se ve? Ok, ahora puedes restaurar la animación, corregir la línea que se ha modificado:
filter.mapBitmap.draw (clipcont [count]);
Este efecto también es útil en caso de que desee adjuntar un cuerpo estático a la animación facial más adelante. Se vería más activo al lado de la animación de mapa de bits..
El archivo puede ser un poco pesado si usa jpeg quality 100, que es lo que recomiendo. En una calidad inferior, el efecto pierde un poco de su encanto. Si quieres una película más pequeña, puedes comprimir las imágenes aún más en Photoshop, pero asegúrate de mantener el esquema de color correcto. El color alrededor de la cabeza del personaje siempre debe ser # 808080 o verás un recuadro a su alrededor..
Así que esto es todo. El primer tutorial que he escrito, fue divertido y espero que te hayas divertido leyendo y haciendo buen uso de él. Apreciaría mucho sus comentarios. Gracias por leer!