Класс DisplacementMapFilter использует пиксельные значения из объекта BitmapData (который называется изображением карты смещения) для применения эффекта смещения к новому объекту. Изображение карты смещения обычно отличается от фактического экранного объекта или экземпляра BitmapData, к которому применяется фильтр. Эффект смещения включает смещение пикселов в фильтрованном изображении. Иными словами, пикселы до некоторой степени сдвигаются с исходной позиции. Этот фильтр можно применять для создания сдвига, деформации или пятен.
Местоположение и величина смещения, примененного к данному пикселу, определяется значением цвета, относящимся к изображению карты смещения. При работе с фильтром помимо указания изображения карты необходимо указать следующие значения, чтобы управлять расчетом смещения из изображения карты:
-
Точка на карте: местоположение фильтрованного изображения, к которому будет применяться левый верхний угол фильтра смещения. Это можно использовать только в том случае, если вы хотите применить фильтр к части изображения.
-
Компонент X: какой канал цвета, относящийся к изображению карты, влияет на позицию пикселов по оси x.
-
Компонент Y: какой канал цвета, относящийся к изображению карты, влияет на позицию пикселов по оси y.
-
Масштаб X: значение множителя, которое указывает на величину смещения по оси x.
-
Масштаб Y: значение множителя, которое указывает на величину смещения по оси y.
-
Режим фильтра: определяет действие по отношению к пустому месту, которое образуется при сдвиге пикселов. Параметры, определенные как константы в классе DisplacementMapFilterMode, должны показывать исходные пикселы (режим фильтра
IGNORE
) для того, чтобы пикселы начали появляться с другой стороны изображения (режим фильтра
WRAP
, выбранный по умолчанию), использовать ближайший сдвинутый пиксел (режим фильтра
CLAMP
) либо заполнить пространство цветом (режим фильтра
COLOR
).
Рассмотрим простой пример, чтобы понять принцип действия фильтра «Карта смещения». В этом коде загружается изображение. По завершении загрузки оно размещается по центру рабочей области, и к нему применяется фильтр карты смещения, благодаря чему пикселы во всем изображении сдвигаются влево по горизонтали.
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);
Для определения смещения использованы следующие свойства.
-
Растровое изображение карты: растровое изображение карты является новым экземпляром BitmapData, созданным этим кодом. Его размеры соответствуют размерам загруженного изображения (чтобы смещение применялось ко всему изображению в целом). В нем используется сплошная заливка красными пикселами.
-
Точка на карте: это значение соответствует точке с координатами 0, 0 (при этом смещение применяется к изображению в целом).
-
Компонент X: в качестве этого значения выбрана константа
BitmapDataChannel.RED
. Это означает, что значение красного цвета растрового изображения карты будет определять величину смещения пикселов (расстояние сдвига) вдоль оси x.
-
Масштаб X: это значение равно 250. Суммарная величина смещения (если за основу изображения карты взято полностью красное изображение) приводит лишь к небольшому сдвигу изображения (примерно на полпиксела). Поэтому если это значение приравнено 1, изображение сдвинется только на 0,5 пикселов по горизонтали. Приравняв его 250, вы получите сдвиг изображения приблизительно на 125 пикселов.
Эти параметры приводят к тому, что пикселы фильтрованного изображения сдвинутся на 250 пикселов влево. Направление (налево или направо) и величина сдвига основаны на значении цвета пикселов в изображении карты. Пикселы фильтрованного изображения обрабатываются поочередно (по крайней мере, пикселы в области применения фильтра, что в данном случае означает все пикселы). По отношению к каждому пикселу выполняются следующие операции.
-
Программа находит соответствующий пиксел в изображении карты. Например, когда фильтр рассчитывает величину смещения для пиксела, расположенного в верхнем левом углу фильтрованного изображения, эта программа обращается к пикселу, находящемуся в верхнем левом углу изображения карты.
-
Программа определяет значение указанного канала цвета в пикселе карты. В данном случае каналом цвета компонента x является красный канал, поэтому фильтр ищет значение красного канала изображения карты для указанного пиксела. Так как изображение карты имеет сплошную красную заливку, красный канал пиксела имеет значение 0xFF или 255. Эта цифра применяется в качестве значения смещения.
-
Программа сравнивает значение смещения со «средним» значением (127, которое находится посередине между 0 и 255). Если значение смещения меньше среднего значения, пиксел сдвигается в направлении положительных чисел (вправо при смещении по оси x; вниз при смещении по оси y). С другой стороны, если значение смещения выше среднего значения (как в данном примере), пиксел смещается в направлении отрицательных чисел (влево при смещении по оси x; вверх при смещении по оси y). Говоря точнее, фильтр вычитает значение смещения из 127, и результат (положительный или отрицательный) является относительной величиной применяемого смещения.
-
И напоследок программа определяет фактическую величину смещения, выясняя, какой процент от полного смещения выражает значение относительного смещения. В данном случае полностью красный означает 100 % смещения. Затем это процентное соотношение умножается на значение масштаба x или y, чтобы получить количество пикселов применяемого смещения. В данном примере 100 %, умноженные на 250, определяют величину смещения (примерно 125 пикселов влево).
Поскольку компонент y и масштаб y не определены, используются значения по умолчанию (не вызывающие смещения). Поэтому изображение вообще не сдвигается по вертикали.
В этом примере использован параметр режима фильтра по умолчанию (
WRAP
). Поэтому по мере сдвига пикселов влево пустое пространство справа заполняется пикселами, сдвинутыми с левого края изображения. Вы можете поэкспериментировать с этим значением, чтобы увидеть различные эффекты его применения. Например, при добавлении следующей строки к той части кода, где задаются свойства смещения (перед строкой
loader.filters = [displacementMap]
), это приведет к тому, что изображение будет выглядеть смазанным в рабочей области:
displacementMap.mode = DisplacementMapFilterMode.CLAMP;
Рассмотрим более сложный пример. В следующем примере фильтр карты смещения применяется для создания эффекта увеличительного стекла, наведенного на изображение:
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);
Код сначала генерирует два круга с градиентами, которые сочетаются, формируя изображение карты смещения. Красный круг создает смещение по оси x (
xyFilter.componentX = BitmapDataChannel.RED
), а синий круг приводит к смещению по оси y (
xyFilter.componentY = BitmapDataChannel.BLUE
). Чтобы вам было легче понять, как будет выглядеть изображение карты смещения, код добавляет в нижней части экрана исходные круги помимо их сочетания, которое служит изображением карты.
Затем код загружает изображение и по мере перемещения мыши применяет фильтр смещения к той части изображения, на которую указывает курсор. Круги с градиентом, использованные в качестве изображения карты смещения, вызывают распространение смещенной области в сторону от курсора. Обратите внимание, что серые области на изображении карты смещения не вызывают никакого смещения. Серый цвет имеет значение
0x7F7F7F
. Синий и красный каналы этого оттенка серого в точности совпадают со средним оттенком этих цветовых каналов, и смещения в серой области этого изображения карты не происходит. Точно так же смещение не выполняется в центре круга. Хотя цвет центра круга не серый, синий и красный канал этого цвета идентичны соответствующим каналам серого цвета. Поскольку синий и красный цвета являются цветами, вызывающими смещение, то смещение здесь не выполняется.