La clase DisplacementMapFilter usa los valores de los píxeles de un objeto BitmapData (conocido como imagen del mapa de desplazamiento) para llevar a cabo un efecto de desplazamiento sobre un nuevo objeto. La imagen del mapa de desplazamiento suele ser distinta al objeto de visualización o a la instancia de BitmapData a los que se va a aplicar el filtro. En un efecto de desplazamiento, los píxeles de la imagen filtrada se desplazan, es decir, cambian su posición en mayor o menor medida con respecto a la imagen original. Este filtro se puede utilizar para crear un efecto de desplazamiento, combado o moteado.
La ubicación y la cantidad de desplazamiento aplicadas a un píxel determinado vienen dadas por el valor del color de la imagen del mapa de desplazamiento. Cuando se trabaja con el filtro, además de especificar la imagen del mapa, es necesario indicar los siguientes valores para controlar la forma en la que se calcula el desplazamiento a partir de la imagen del mapa:
-
Punto del mapa: la posición de la imagen filtrada en la que se aplicará la esquina superior izquierda del filtro de desplazamiento. Se puede usar este valor para aplicar el filtro solo a una parte de la imagen.
-
Componente X: el canal de color de la imagen del mapa que afectará a la posición x de los píxeles.
-
Componente Y: el canal de color de la imagen del mapa que afectará a la posición y de los píxeles.
-
Escala X: un valor multiplicador que especifica la intensidad del desplazamiento en el eje x.
-
Escala Y: un valor multiplicador que especifica la intensidad del desplazamiento en el eje y.
-
Modo de filtro: determina la operación que se debe realizar en los espacios vacíos dejados por los píxeles desplazados. Las opciones, definidas como constantes en la clase DisplacementMapFilterMode, son mostrar los píxeles originales (modo de filtro
IGNORE
), cruzar los píxeles del otro lado de la imagen (modo de filtro
WRAP
, que es el predeterminado), usar el píxel desplazado más cercano (modo de filtro
CLAMP
) o rellenar los espacios con un color (modo de filtro
COLOR
).
Para entender el funcionamiento del filtro de mapa de desplazamiento, se puede considerar el siguiente ejemplo. En el código que aparece a continuación se carga una imagen y, cuando termina la carga, se centra en el escenario y se le aplica un filtro de mapa de desplazamiento que hace que los píxeles de toda la imagen se desplacen horizontalmente hacia la izquierda.
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.MouseEvent;
import flash.filters.DisplacementMapFilter;
import flash.geom.Point;
import flash.net.URLRequest;
// Load an image onto the Stage.
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image3.jpg");
loader.load(url);
this.addChild(loader);
var mapImage:BitmapData;
var displacementMap:DisplacementMapFilter;
// This function is called when the image finishes loading.
function setupStage(event:Event):void
{
// Center the loaded image on the Stage.
loader.x = (stage.stageWidth - loader.width) / 2;
loader.y = (stage.stageHeight - loader.height) / 2;
// Create the displacement map image.
mapImage = new BitmapData(loader.width, loader.height, false, 0xFF0000);
// Create the displacement filter.
displacementMap = new DisplacementMapFilter();
displacementMap.mapBitmap = mapImage;
displacementMap.mapPoint = new Point(0, 0);
displacementMap.componentX = BitmapDataChannel.RED;
displacementMap.scaleX = 250;
loader.filters = [displacementMap];
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, setupStage);
Las propiedades utilizadas para definir el desplazamiento son las siguientes:
-
Mapa de bits del mapa: el mapa de bits del desplazamiento es una nueva instancia de BitmapData creada por el código. Sus dimensiones coinciden con las de la imagen cargada (de modo que el desplazamiento se aplica a toda la imagen). Tiene un relleno sólido de píxeles rojos.
-
Punto del mapa: este valor está ajustado al punto 0, 0, lo que hace que el desplazamiento se aplique a toda la imagen.
-
Componente X: este valor está ajustado a la constante
BitmapDataChannel.RED
, lo que significa que el valor rojo del mapa de bits del mapa determinará la cantidad de desplazamiento de los píxeles (cuánto se moverán) en el eje x.
-
Escala X: este valor está ajustado a 250. La cantidad total de desplazamiento (teniendo en cuenta que la imagen del mapa es completamente roja) solo movería la imagen una distancia muy pequeña (aproximadamente medio píxel), de modo que si este valor se ajustase a 1, la imagen solo se desplazaría 0,5 píxeles horizontalmente. Al ajustarlo a 250, la imagen se mueve aproximadamente 125 píxeles.
Esta configuración hace que los píxeles de la imagen filtrada se desplacen 250 píxeles hacia la izquierda. La dirección (izquierda o derecha) y la cantidad de desplazamiento se basan en el valor de color de los píxeles de la imagen del mapa. Conceptualmente, el filtro recorre de uno en uno los píxeles de la imagen filtrada (al menos los píxeles de la región en la que se aplica el filtro, que, en este caso, son todos) y lleva a cabo el siguiente proceso con cada píxel:
-
Buscan el píxel correspondiente en la imagen del mapa. Por ejemplo, cuando el filtro calcula la cantidad de desplazamiento para el píxel de la esquina superior izquierda de la imagen filtrada, consulta el píxel de la esquina superior izquierda de la imagen del mapa.
-
Determinan el valor del canal de color especificado en el píxel del mapa. En este caso, el canal de color del componente x es el rojo, de modo que el filtro comprueba qué valor tiene el canal rojo de la imagen del mapa en el píxel en cuestión. Dado que la imagen del mapa es de color rojo sólido, el canal rojo del píxel es 0xFF, o 255. Este será el valor que se use como desplazamiento.
-
Comparan el valor de desplazamiento con el valor "medio" (127, que es el valor intermedio entre 0 y 255). Si el valor de desplazamiento es menor que el valor medio, el píxel se desplaza en dirección positiva (hacia la derecha para el desplazamiento en el eje x y hacia abajo para el desplazamiento en el eje y). Por otro lado, si el valor de desplazamiento es superior al valor medio (como en el ejemplo), el píxel se desplaza en dirección negativa (hacia la izquierda para el desplazamiento en el eje x y hacia arriba para el desplazamiento en el eje y). Para ser más precisos, el filtro resta a 127 el valor de desplazamiento y el resultado (positivo o negativo) es la cantidad relativa de desplazamiento que se aplica.
-
Finalmente, determinan la cantidad de desplazamiento real calculando qué porcentaje del desplazamiento completo representa el valor del desplazamiento relativo. En este caso, el rojo sólido significa un desplazamiento del 100%. Ese porcentaje se multiplica por el valor de escala x o escala y a fin de establecer el número de píxeles de desplazamiento que se aplicará. En este ejemplo, la cantidad de desplazamiento equivale a 100% veces un multiplicador de 250 (aproximadamente 125 píxeles a la izquierda).
Dado que no se han especificado valores para el componente y la escala y, se utilizan los valores predeterminados (que no causan ningún desplazamiento), por eso la imagen no se mueve en dirección vertical.
En el ejemplo se utiliza el modo de filtro predeterminado,
WRAP
, de modo que cuando los píxeles se desplazan hacia la izquierda, el espacio vacío de la derecha se llena con los píxeles que se han desplazado fuera del borde izquierdo de la imagen. Se puede experimentar con este valor para ver los distintos efectos. Por ejemplo, si se añade la siguiente línea a la parte del código en la que se definen las propiedades del desplazamiento (antes de la línea
loader.filters = [displacementMap]
), la imagen tendrá la apariencia de haber sido arrastrada por el escenario:
displacementMap.mode = DisplacementMapFilterMode.CLAMP;
A continuación se muestra un ejemplo más complejo, con un listado que utiliza un mapa de desplazamiento para crear un efecto de lupa sobre una imagen:
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.GradientType;
import flash.display.Loader;
import flash.display.Shape;
import flash.events.MouseEvent;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.net.URLRequest;
// Create the gradient circles that will together form the
// displacement map image
var radius:uint = 50;
var type:String = GradientType.LINEAR;
var redColors:Array = [0xFF0000, 0x000000];
var blueColors:Array = [0x0000FF, 0x000000];
var alphas:Array = [1, 1];
var ratios:Array = [0, 255];
var xMatrix:Matrix = new Matrix();
xMatrix.createGradientBox(radius * 2, radius * 2);
var yMatrix:Matrix = new Matrix();
yMatrix.createGradientBox(radius * 2, radius * 2, Math.PI / 2);
var xCircle:Shape = new Shape();
xCircle.graphics.lineStyle(0, 0, 0);
xCircle.graphics.beginGradientFill(type, redColors, alphas, ratios, xMatrix);
xCircle.graphics.drawCircle(radius, radius, radius);
var yCircle:Shape = new Shape();
yCircle.graphics.lineStyle(0, 0, 0);
yCircle.graphics.beginGradientFill(type, blueColors, alphas, ratios, yMatrix);
yCircle.graphics.drawCircle(radius, radius, radius);
// Position the circles at the bottom of the screen, for reference.
this.addChild(xCircle);
xCircle.y = stage.stageHeight - xCircle.height;
this.addChild(yCircle);
yCircle.y = stage.stageHeight - yCircle.height;
yCircle.x = 200;
// Load an image onto the Stage.
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/images/image1.jpg");
loader.load(url);
this.addChild(loader);
// Create the map image by combining the two gradient circles.
var map:BitmapData = new BitmapData(xCircle.width, xCircle.height, false, 0x7F7F7F);
map.draw(xCircle);
var yMap:BitmapData = new BitmapData(yCircle.width, yCircle.height, false, 0x7F7F7F);
yMap.draw(yCircle);
map.copyChannel(yMap, yMap.rect, new Point(0, 0), BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
yMap.dispose();
// Display the map image on the Stage, for reference.
var mapBitmap:Bitmap = new Bitmap(map);
this.addChild(mapBitmap);
mapBitmap.x = 400;
mapBitmap.y = stage.stageHeight - mapBitmap.height;
// This function creates the displacement map filter at the mouse location.
function magnify():void
{
// Position the filter.
var filterX:Number = (loader.mouseX) - (map.width / 2);
var filterY:Number = (loader.mouseY) - (map.height / 2);
var pt:Point = new Point(filterX, filterY);
var xyFilter:DisplacementMapFilter = new DisplacementMapFilter();
xyFilter.mapBitmap = map;
xyFilter.mapPoint = pt;
// The red in the map image will control x displacement.
xyFilter.componentX = BitmapDataChannel.RED;
// The blue in the map image will control y displacement.
xyFilter.componentY = BitmapDataChannel.BLUE;
xyFilter.scaleX = 35;
xyFilter.scaleY = 35;
xyFilter.mode = DisplacementMapFilterMode.IGNORE;
loader.filters = [xyFilter];
}
// This function is called when the mouse moves. If the mouse is
// over the loaded image, it applies the filter.
function moveMagnifier(event:MouseEvent):void
{
if (loader.hitTestPoint(loader.mouseX, loader.mouseY))
{
magnify();
}
}
loader.addEventListener(MouseEvent.MOUSE_MOVE, moveMagnifier);
El código genera primero dos círculos degradados, que se combinan para formar la imagen del mapa de desplazamiento. El círculo rojo crea el desplazamiento en el eje x (
xyFilter.componentX = BitmapDataChannel.RED
), y el azul crea el desplazamiento en el eje y (
xyFilter.componentY = BitmapDataChannel.BLUE
). Para entender mejor la apariencia de la imagen del mapa de desplazamiento, el código añade los círculos originales y el círculo combinado que sirve de imagen del mapa en la parte inferior de la pantalla.
A continuación, el código carga una imagen y, a medida que se mueve el ratón, aplica el filtro de desplazamiento a la parte de la imagen que se encuentra bajo este. Los círculos degradados que se utilizan como imagen del mapa de desplazamiento hacen que la región desplazada se aleje del puntero. Hay que tener en cuenta que las regiones grises del mapa de desplazamiento no causan ningún movimiento. El color gris es
0x7F7F7F
. Los canales rojo y azul de esa tonalidad de gris coinciden exactamente con la tonalidad media de esos canales de color, de manera que no hay desplazamiento en las zonas grises de la imagen del mapa. Del mismo modo, en el centro del círculo tampoco hay desplazamiento. Si bien el color de esa región no es gris, los canales rojo y azul de ese color son idénticos a los canales rojo y azul del gris medio y, puesto que el rojo y el azul son los colores que causan el desplazamiento, no se produce ninguno.