Klassen DisplacementMapFilter använder pixelvärden från ett BitmapData-objekt (kallas för förskjutningsbild) för att skapa en förskjutningseffekt på ett nytt objekt. Förskjutningsbilden är oftast annorlunda än det visningsobjekt eller den BitmapData-instans som filtret tillämpas på. En förskjutningseffekt innebär att pixlar förskjuts i den filtrerade bilden. M.a.o. flyttas de bort från den ursprungliga platsen i någon utsträckning. Filtret kan användas för att skapa en skiftad, förvrängd eller ojämn effekt.
Var och hur mycket förskjutning som används på en viss pixel avgörs av förskjutningsbildens färgvärde. När du arbetar med filtret anger du inte bara förskjutningsbild, du anger också följande värden som styr hur förskjutningen beräknas utifrån förskjutningsbilden:
-
Mappningspunkt: Den plats i den filtrerade bilden där det övre vänstra hörnet av förskjutningsfiltret ska placeras. Använd värdet om du bara vill tillämpa filtret på en del av en bild.
-
X-komponent: Vilken av förskjutningsbildens färgkanaler som ska påverka pixlarnas x-position.
-
Y-komponent: Vilken av förskjutningsbildens färgkanaler som ska påverka pixlarnas y-position.
-
X-skala: Ett multiplikatorvärde som anger hur stark förskjutningen är i x-axeln.
-
Y-skala: Ett multiplikatorvärde som anger hur stark förskjutningen är i y-axeln.
-
Filterläge: Avgör vad som ska ske i eventuella tomrum som kan uppstå när pixlar flyttas bort. Alternativen, som definieras som konstanter i klassen DisplacementMapFilterMode, är att visa de ursprungliga pixlarna (filterläget
IGNORE
), flytta över pixlarna till bildens andra sida (filterläget
WRAP
, som är standard), använda närmaste skiftade pixel (filterläget
CLAMP
) eller fylla i tomrummen med en färg (filterläget
COLOR
).
Ett enkelt exempel gör det lättare att förstå hur förskjutningsfilter fungerar. I koden läses en bild in. När den har lästs in helt centreras den på scenen och ett förskjutningsfilter tillämpas på den så att pixlarna i hela bilden flyttas vågrätt till vänster.
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);
De egenskaper som används för att definiera förskjutningen är följande:
-
Mappningsbild: Förskjutningsbitmappen är en ny BitmapData-instans som skapas av koden. Dess mått matchar den inlästa bildens mått (så att förskjutningen tillämpas på hela bilden). Den fylls i med heltäckande röda pixlar.
-
Mappningspunkt: Värdet ställs in på punkten 0,0 så att förskjutningsfiltret täcker hela bilden.
-
X-komponent: Det här värdet ställs in på konstanten
BitmapDataChannel.RED
så att mappningsbildens röda värde avgör hur mycket pixlarna förskjuts (hur långt de flyttas) på x-axeln.
-
X-skala: Det här värdet är inställt på 250. Hela förskjutningen (från att förskjutningsbilden är helt röd) förskjuter bara bilden en liten bit (ungefär en halv pixel); om värdet är 1 flyttas bilden således endast 0,5 pixlar vågrätt. Värdet 250 gör att bilden flyttas ungefär 125 pixlar.
De här inställningarna gör att den filtrerade bildens pixlar flyttas 250 pixlar till vänster. Förflyttningens riktning (vänster eller höger) och mängden förflyttning baseras på färgvärdet i pixlarna i förskjutningsbilden. Filtret går igenom pixlarna i den filtrerade bilden en i taget (åtminstone pixlarna i det område som filtret tillämpas på, vilket i det här fallet är alla pixlar) och gör följande med varje pixel:
-
Söker efter motsvarande pixel i förskjutningsbilden. När filtret till exempel beräknar förskjutningsmängden för pixeln i det övre vänstra hörnet av den filtrerade bilden, läser det pixeln i övre vänstra hörnet på förskjutningsbilden.
-
Värdet avgörs för den angivna färgkanalen i förskjutningspixeln. I det här fallet är x-komponentens färgkanal den röda kanalen, så filtret kontrollerar vilket värde den röda kanalen i förskjutningsbilden har vid pixeln i fråga. Eftersom förskjutningsbilden är heltäckande röd är pixelns röda kanal 0xFF, d.v.s. 255. Det värdet används som förskjutningsvärde.
-
Jämför förskjutningsvärdet med mellanvärdet (127, d.v.s. mellan 0 och 255). Om förskjutningsvärdet är lägre än mellanvärdet flyttas pixeln i positiv riktning (till höger för x-förskjutning, nedåt för y-förskjutning). Om förskjutningsvärdet är högre än mellanvärdet (som är fallet i det här exemplet) flyttas pixeln i stället i negativ riktning (till vänster för x-förskjutning, uppåt för y-förskjutning). För att vara mer exakt subtraherar filtret förskjutningsvärdet från 127, och resultatet (positivt eller negativt) är den relativa förskjutning som tillämpas.
-
Slutligen avgörs den faktiska förskjutningsmängden genom beräkning av hur stor procentandel av fullständig förskjutning som det relativa förskjutningsvärdet representerar. I det här fallet är helt röd 100 % förskjutning. Den procentandelen multipliceras sedan med x-skalan eller y-skalan för att avgöra hur många pixlars förskjutning som ska tillämpas. I det här exemplet avgörs förskjutningsmängden av 100 % gånger multiplikatorn 250, vilket blir ungefär 125 pixlar till vänster.
Eftersom inga värden angavs för y-komponenten och y-skalan användes standardvärdena (vilket innebär att ingen förskjutning görs). Därför flyttas bilden inte alls i lodrät riktning.
Standardinställningen för filterläge,
WRAP
, används i det här exemplet så att de tomma pixlar som uppstår till höger fylls av de pixlar som flyttades utanför bildens vänsterkant. Du kan experimentera med det här värdet för att se de olika effekterna. Om du till exempel lägger till följande rad i den del av koden där förskjutningsegenskaperna ställs in (före raden
loader.filters = [displacementMap]
) ser bilden ut som om den har smetats ut på scenen:
displacementMap.mode = DisplacementMapFilterMode.CLAMP;
Följande kod är ett mer komplicerat exempel där ett förskjutningsfilter används för att skapa effekten av ett förstoringsglas på en bild:
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);
Koden skapar först två övertoningscirklar som kombineras till förskjutningsbilden. Den röda cirkeln skapar x-axelns förskjutning (
xyFilter.componentX = BitmapDataChannel.RED
) och den blå cirkeln skapar y-axelns förskjutning (
xyFilter.componentY = BitmapDataChannel.BLUE
). För att det ska bli lättare att förstå hur förskjutningsbilden ser ut läggs både originalcirklarna och den kombinerade cirkeln som fungerar som förskjutningsbild till längst ned på skärmen.
Sedan läses en bild in och när musen flyttas tillämpas förskjutningsfiltret på den del av bilden som är under muspekaren. Övertoningscirklarna som används som förskjutningsbild gör att det förskjutna området sprids ut från pekaren. Observera att de grå områdena i förskjutningsbilden inte orsakar någon förskjutning. Den grå färgen är
0x7F7F7F
. De blå och röda kanalerna för den nyansen av grått matchar mellannyansen för dessa färgkanaler exakt. Det gör att ingen förskjutning görs i grå områden i förskjutningsbilden. På samma sätt görs ingen förskjutning i cirkelns mitt. Färgen där är inte grå, men färgens blå kanal och röda kanal är identiska med den blå kanalen och den röda kanalen i mellangrå. Eftersom blå och röd är de färger som orsakar förskjutningen görs ingen förskjutning där.