12.7.在Flex Effect裏使用DisplacementMapFilter過濾器

12.7.1 問題
你需要創建一個在圖片之間置換的漸變效果。
12.7.2 解決辦法
繼承TweenEffect 和TweenEffectInstance 類,創建一個具有最終置換值的TweenEffect 實例,然後將這些最終置換值傳給它所創建的TweenEffectInstance 類實例。在自定義的TweenEffectInstance 類裏,創建一個DisplacementMapFilter 對象並且使用Flex 框架的漸變引擎通過在每個onTweenUpdate 事件上生成新的過濾器來達到預期的置換值。
12.7.3 討論
DisplacementMapFilter 通過使用另一張圖片的象素點決定變形的位置和量來置換或者變形當前圖片的像素點。

置換的位置和量到設定的像素是通過置換目標圖片的像素點色值決定的。

DisplacementMapFilter 的構造方法如下:

-ActionScript
public function DisplacementMapFilter(mapBitmap:BitmapData = null,
mapPoint:Point = null, componentX:uint = 0, componentY:uint = 0,
scaleX:Number = 0.0, scaleY:Number = 0.0, mode:String = "wrap",
color:uint = 0, alpha:Number = 0.0)

如此長的一行代碼拆開理解較爲簡單:
-ActionScript
BitmapData (default = null)

這是過濾器應用到的置換目標圖片或組件所用到的BitmapData 對象。
mapPoint
這個是被過濾圖片的位置,對應於過濾器要應用到的置換圖片的左上角位置。如果僅僅過濾圖片的一部分的話,可以使用這個參數。

componentX
該參數指定作用x 位置上的圖片象素顏色通道。BitmapDataChannel 定義了所有有效的常量選項值:BitmapDataChannel.BLUE 或4, BitmapDataChannel.RED 或1,BitmapDataChannel.GREEN 或2, or BitmapDataChannel.ALPHA 或8。

componentY
指定作用y 位置上的圖片象素顏色通道。取值範圍和componentX 的相同。

scaleX
這個參數值指定X 軸方向上的置換強度。

scaleY
這個參數值指定Y 軸方向上的置換強度。

mode
這是一個字符串,它決定怎樣處理置換像素後形成的空白空間。可選值申明爲DisplacementMapFilterMode 類的常量,用以顯示原始的像素(mode = IGNORE)、從圖片另一邊封裝邊緣像素點(mode = WRAP,默認值)、使用最近的置換像素(mode = CLAMP)或者使用某個顏色填充這些空間(mode = COLOR)。

CustomDisplacementEffect 例示CustomDisplacementInstance。如下:
-ActionScript
package oreilly.cookbook{
import mx.effects.IEffectInstance;
import mx.effects.TweenEffect;
import mx.events.EffectEvent;
public class CustomDisplacementEffect extends TweenEffect
{
public var image:Class;
public var yToDisplace:Number;
public var xToDisplace:Number;
public function CustomDisplacementEffect(target:Object=null)
{
super(target);
this.instanceClass = CustomDisplacementInstance;
}
override protected function
initInstance(instance:IEffectInstance):void {
trace(" instance initialized ");
super.initInstance(instance);
// now that we've instantiated our instance, we can set
its properties
CustomDisplacementInstance(instance).image = image;
CustomDisplacementInstance(instance).xToDisplace =
this.xToDisplace;
CustomDisplacementInstance(instance).yToDisplace =
this.yToDisplace;
}
override public function getAffectedProperties():Array {
trace(" return all the target properties ");
return [];
}
}
}

實際上CustomDisplacementInstance 負責進行創建應用到目標的DisplacementEffect 對象。而位圖對象,過濾器在DisplacementEffect 使用的,以及CustomDisplacementTween 的x 與y置換量都應用到該實例並傳給DisplacementEffect。

CustomTweenEffect 創建CustomDisplacementInstance 的實例,如下:
-ActionScript
package oreilly.cookbook{
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.DisplayObject;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Point;
import mx.effects.Tween;
import mx.effects.effectClasses.TweenEffectInstance;
public class CustomDisplacementInstance extends
TweenEffectInstance
{
public var image:Class;
public var xToDisplace:Number;
public var yToDisplace:Number;
public var filterMode:String =
DisplacementMapFilterMode.WRAP;
private var filter:DisplacementMapFilter;
private var img:DisplayObject;
private var bmd:BitmapData;
public function CustomDisplacementInstance(target:Object)
{
super(target);
}
override public function play():void {
super.play();
//make our embedded image accessible to use
img = new image();
bmd = new BitmapData(img.width, img.height, true);
//draw the actual byte data into the image
bmd.draw(img);

這個新過濾器被創建,將被設置初始狀態的所有值:
-ActionScript
filter = new DisplacementMapFilter(bmd, new
Point(DisplayObject(target).wi
dth/2 - (img.width/2), DisplayObject(target).height/2 -
(img.height/2))),
BitmapDataChannel.RED, BitmapDataChannel.RED, 0, 0,
filterMode, 0.0, 1.0);
//copy any filters already exisiting on the target so
that we don't
destroy them when we add our new filter
var targetFilters:Array = (target as
DisplayObject).filters;
targetFilters.push(filter);
//set the actual filter onto the target
(target as DisplayObject).filters = targetFilters;
//create a tween that will begin to generate the next
values of each frame of our effect
this.tween = new Tween(this, [0, 0], [xToDisplace,
yToDisplace],
duration);
}

該類的很多繁重工作都在setDisplacementFilter 中完成。因爲過濾器是累積的(它們是疊加應用的),前面的DisplacementMapFilter 必須移除。這需要通過循環遍歷目標對象的過濾器數組來完成,移除所有DisplacementMapFilter 的實例。然後使用Tween 傳過來的值創建一個新的過濾器並且將此過濾器應用到目標對象上。注意要讓過濾器適當的顯示,過濾器數組必須要重置。使用Array.push 方法添加過濾器到數組中不會引起目標DisplayObject 使用過濾器重繪。
-ActionScript
private function setDisplacementFilter(displacement:Object):void{
var filters:Array = target.filters;
// Remove any existing Displacement filter to ensure that
ours is the only one
var n:int = filters.length;
for (var i:int = 0; i < n; i++) {
if (filters[i] is DisplacementMapFilter)
filters.splice(i, 1);
}
//create the new filter with the values passed in from
the tween
filter = new DisplacementMapFilter(bmd, new Point(0, 0),
BitmapDataChannel.RED, BitmapDataChannel.RED,
displacement[0] as Number, displacement[1] as
Number, filterMode, 0.0, 0);
//add the filter to the filters on the target
filters.push(filter);
target.filters = filters;
}
//each time we're ready to update, re-create the
displacement map filter
override public function onTweenUpdate(value:Object):void
{
setDisplacementFilter(value);
}
//set the filter one last time and then dispatch the tween
end event
override public function onTweenEnd(value:Object):void
{
setDisplacementFilter(value);
super.onTweenEnd(value);
}
}
}

當漸變結束時,DisplacementMapFilter 的最終值用來設置目標DisplayObject 的最終外觀,同時調用TweenEffectInstance 類的onTweenEnd 方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章