Klasa DisplacementMapFilter wykorzystuje wartości pikseli z obiektu BitmapData (znanego jako obraz mapy przemieszczeń) w celu uzyskania efektu przemieszczenia na nowym obiekcie. Obraz stanowiący mapę przemieszczeń jest zazwyczaj obiektem innym niż dany obiekt wyświetlany czy instancja BitmapData, na którą nakładany jest filtr. Efekt przemieszczenia obejmuje przemieszczanie pikseli w obrazie filtrowanym — innymi słowy, w pewnym sensie przesuwanie ich z położenia oryginalnego do innego położenia. Filtru tego można użyć do wywołania efektu przesunięcia, wypaczenia lub nakrapiania.
Lokalizacja i wielkość przemieszczenia nakładana na dany piksel jest określona wartością koloru na obrazie mapy przemieszczeń. Podczas pracy z filtrami, poza określeniem obrazu stanowiącego mapę użytkownik wskazuje również następujące wartości sterujące obliczaniem przemieszczenia z obrazu mapy:
-
Map point: miejsce na obrazie filtrowanym, w którym zostanie nałożony górny lewy róg filtra przemieszczeń. Opcji tej można użyć, jeśli chce się tylko zastosować filtr do części obrazu.
-
X component: określa, który kanał koloru obrazu stanowiącego mapę wpływa na położenie x pikseli.
-
Y component: określa, który kanał koloru obrazu stanowiącego mapę wpływa na położenie y pikseli.
-
X scale: wartość mnożnika określająca siłę przesunięcia wzdłuż osi x.
-
Y scale: wartość mnożnika określająca siłę przesunięcia wzdłuż osi y.
-
Filter mode: określa, jak program Flash Player lub AIR powinny wypełniać puste przestrzenie utworzone w wyniku przesunięcia pikseli w inne miejsce. Opcje zdefiniowane jako stałe w klasie DisplacementMapFilterMode powinny powodować wyświetlanie oryginalnych pikseli (tryb filtra
IGNORE
), powodować „zawijanie” pikseli znajdujących się w sąsiedztwie z drugiej strony obrazu (tryb filtra
WRAP
, będący trybem domyślnym), używać najbliższego przesuniętego piksela (tryb filtra
CLAMP
), lub wypełniać przestrzenie kolorem (tryb filtra
COLOR
).
W celu zrozumienia działania filtru mapy przemieszczeń należy zapoznać się z prostym przykładem. Poniższy kod opisuje załadowanie obrazu oraz niezwłocznie po jego załadowaniu wycentrowanie go na stole montażowym i nałożenie filtru mapy przemieszczeń, powodującego przemieszczenie pikseli na całym obrazie w poziomie w lewą stronę.
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);
Właściwości użyte do zdefiniowania tego przemieszczenia są następujące:
-
Map bitmap: bimapa przemieszczeń jest nową instancją BitmapData utworzoną w wyniku działania kodu. Jej wymiary odpowiadają wymiarom ładowanego obrazu (zatem przemieszczenie również będzie obejmować cały obraz). Jest wypełniania pikselami w kolorze czerwonym.
-
Map point: Ta wartość jest ustawiana na punkt 0, 0 — ponownie, powodując objęcie przemieszczeniem całego obrazu.
-
X component: Ta wartość jest ustawiana na wartość stałej
BitmapDataChannel.RED
, co oznacza, że wartość czerwona bitmapy wyznaczy, jak wiele pikseli uległo przemieszczeniu (jak dalece zostały one przemieszczone) wzdłuż osi x.
-
X scale: Ta wartość jest ustawiana na 250. Pełna wielkość przemieszczenia (z obrazu mapy, który jest całkowicie czerwony) powoduje przemieszczenie na niewielką odległość (około połowy tej wartości) tak że ustawienie jej na 1 spowodowałoby przesunięcie w poziomie o tylko pół piksela. Ustawiając wartość 250, uzyskujemy odległość przemieszczenia wynoszącą około 125 pikseli.
Ustawienia te powodują przesunięcie pikseli na filtrowanym obrazie o 250 pikseli na lewo. Kierunek (w stronę lewą lub prawą) oraz wielkość przesunięcia opierają się na wartości koloru pikseli na mapie obrazu. Jeśli chodzi o koncepcję, filtr odczytuje pojedynczo piksele na obrazie filtrowanym (lub co najmniej w obszarze podlegającym filtrowaniu danego obrazu, co w analizowanym wypadku oznacza wszystkie piksele) i wykonuje na każdym pikselu następujące operacje:
-
Odnajduje piksel mu odpowiadający na obrazie stanowiącym mapę. Na przykład obliczenie przez filtr wielkości przemieszczenia dla piksela znajdującego się w lewym górnym rogu filtrowanego obrazu odbywa się na podstawie piksela znajdującego się w lewym górnym rogu obrazu stanowiącego mapę.
-
Określa on wartość danego kanału koloru w pikselu na mapie. W tym przypadku składnik x kanału koloru to kanał czerwieni, tak więc programy Flash Player i AIR sprawdzają, jaka jest wartość kanału czerwieni na obrazie stanowiącym mapę dla przetwarzanego aktualnie piksela. Ponieważ obraz stanowiący mapę ma listy kolor czerwony, kanał czerwieni piksela wynosi 0xFF, inaczej 255. Ta wartość jest używana jako wartość przemieszczenia.
-
Porównuje ona wartość przemieszczenia do wartości „środkowej” (127, stanowiącej środek między zerem a 255). Jeśli wartość przemieszczenia jest niższa niż wartość środkowa, piksel przesuwa się w kierunku dodatnim (w prawo w przypadku przemieszczenia po x; w dół w przypadku przemieszczenia po y). Z drugiej strony jeśli wartość przemieszczenia jest wyższa niż wartość środkowa (jak w omawianym przykładzie) piksel przesuwa się w kierunku ujemnym (w lewo w przypadku przemieszczenia po x; w górę w przypadku przemieszczenia po y). Bardziej precyzyjnie, filtr odejmuje wartość przemieszczenia od 127, a wynik (dodatni lub ujemny) jest to wartość względna stosowanego przemieszczenia.
-
Ostatecznie rzeczywista wartość przemieszczenia jest obliczana na podstawie procentowego udziału, jaki reprezentuje przemieszczenie względne w przemieszczeniu pełnym. W tym przypadku kolor całkowicie czerwony oznacza 100-procentowe przemieszczenie. Ten udział procentowy jest następnie mnożony przez wartości skali x lub y w celu wyznaczenia liczby pikseli przemieszczenia, jakie zostanie zastosowane. W tym przykładzie 100% razy mnożnik 250 wyznacza wielkość przemieszczenia — około 125 pikseli w lewo.
Ponieważ ani dla składnika y, ani dla skali y nie określono żadnych wartości, użyte zostały wartości domyślne (niepowodujące przemieszczenia) — dlatego obraz nie uległ przemieszczeniu w pionie.
W przykładzie użyte zostało domyślne ustawienie trybu filtru,
WRAP
, tak że w miarę przesuwania się pikseli w lewo powstająca po prawej stronie pusta przestrzeń jest wypełniana pikselami, które „wypadły” z obrazu po jego lewej stronie. Z wartościami tymi można eksperymentować, sprawdzając, jakie przyniosą one efekty. Na przykład, dodając poniższy wiersz do fragmentu kodu dotyczącego ustawiania właściwości (przed wierszem
loader.filters = [displacementMap]
), można spowodować, że obraz będzie wyglądał, jak gdyby został rozsmarowany w poprzek stołu montażowego:
displacementMap.mode = DisplacementMapFilterMode.CLAMP;
Bardziej złożonym przykładem jest poniższy listing, korzystający z filtra mapy przemieszczeń do utworzenia efektu szkła powiększającego na obrazie:
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);
Pierwszy kod generuje dwa okręgi gradientowe, które połączone ze sobą, tworzą obraz mapy przemieszczeń. Czerwony okrąg odpowiada za przemieszczenie wzdłuż osi x (
xyFilter.componentX = BitmapDataChannel.RED
), natomiast niebieski — za przemieszczenie wzdłuż osi y (
xyFilter.componentY = BitmapDataChannel.BLUE
). Aby ułatwić czytelnikowi zrozumienie, jak wygląda mapa przemieszczeń, kod dodaje oryginalne okręgi, a także okręgi połączone, które pełnią rolę obrazu stanowiącego mapę, w dolnej części ekranu.
Następuje załadowanie obrazu oraz, w wyniku ruchu muszą, nałożenie filtru przemieszczenia na fragment obrazu, nad którym znajduje się mysz. Okręgi gradientowe służące jako obraz mapy przemieszczeń powodują odrzucenie przemieszczonego obszaru daleko od wskaźnika myszy. Należy zauważyć, że szare obszary na obrazie mapy przemieszczeń nie powodują żadnego przemieszczenia. Kolor szary to
0x7F7F7F
. Kanały niebieski i czerwony tego odcienia szarości dokładnie odpowiadają średniej odcieni tych kanałów kolorów, tak że w obszarze szarości obrazu mapy brak jest jakiegokolwiek przemieszczenia. Podobnie brak jest przemieszczeń w środkowej części okręgu. Mimo że kolor tam nie jest szary, kanały niebieski i czerwony tego koloru są identyczne z kanałem niebieskim i czerwonym średnioszarego, a ponieważ niebieski i czerwony są kolorami powodującymi przesunięcie, przesunięte to jest w tym miejscu zerowe.