flash 要做出魚眼效果,在 flash8 以前的時代是非常痛苦的事,
不過現在有了 DisplacementMapFilter 這件事比變得簡單多了,
另外還有 Pixel Bender 也可以做到魚眼效果,但這兩個的原理不太一樣,
我自己的測試,Pixel Bender 的效能更好,但要 flash player 10 後
才有支援。
首先,Pixel Bender 與 flash DisplacementMapFilter 處理方式不太一樣
DisplacementMapFilter 是把來源圖片上面各個像素按照一個 map 來移動到新的位置
然後拼出一張新的圖。
而 Pixel Bender 是定義 "每一個來源圖片像素" 的執行函數,
所以如果我定義 "輸出結果的像素是來源圖片像素的 -2 相對位置",
那麼結果就是目標圖片相當於,把來源圖片往右邊移動兩個像素,
兩者原理不太一樣。
回到本篇重點 DisplacementMapFilter
DisplacementmapFilter 藉由讀取參考用的 BitmapData 資料,
把來源圖片的像素搬移(置換)位置,每個像素搬移的方式不同就會造成 "圖片的扭曲效果",
這邊說明一下濾鏡除了可以套用在 BitmapData 物件上(如上面所述),也可以直接套
用於顯示物件,像是 Bitmap 實體。
參考用的 BitmapData 只要參考它的 Red channel 就夠了,
因為一般參考用 BitmapData 習慣設成灰階的),
就像一般 filter 一樣
DisplacementMapFilter 也有建構式:
DisplacementMapFilter(mapBitmap:BitmapData, mapPoint:Point, componentX:Number,
componentY:Number, scaleX:Number, scaleY:Number,
[mode:String], [color:Number], [alpha:Number])
mapBitmap 參考用的 BitmapData
mapPoint 從 mapBitmap 的哪個像素開始參考
(假如你從 (5, 5) 開始參考一個100X100的 mapBitmap,那 mapBitmap 的尺寸就是 95X95)
componentX/componentY 決定像素位移的時候要參考 mapBitmap 像素的 color channel
scaleX/scaleY 決定 "位移百分比(0.0~1.0)" 之後要乘上的倍率
mode/color/alpha 比較複雜且不重要,可以不要寫。
範列如下
var displaceFilter:DisplacementMapFilter;
displaceFilter = new DisplacementMapFilter(fisheyeLens,
new Point(radius, 0),
BitmapDataChannel.RED,
BitmapDataChannel.GREEN,
radius, 0);
srcBitmap.filters = [displaceFilter];
這邊 fisheyeLens(魚眼) bitmapdata 為參考影像,其中像素的顏色都會用來當做是
對置換函數的輸入;
也就是說,參考影像內的某些 x, y 座標會決定要在來源影像內的該 x,y 座標上
套用多少置換量 (在適當位置的實體移動)。
置換函數的公式:
dstPixel[x, y] = srcPixel[x + ((componentX(x, y) - 128) * scaleX) / 256, y + ((componentY(x, y) - 128) * scaleY) / 256]
DisplacementMapFilter 可以搭配 Perlin noise(BitmapData)
BitmapData 支援兩種雜訊效果,noise/perlinNoise
perlinNoise 適用於有組織的紋理,像是煙霧、雲、水、火焰甚至是爆炸效果。
原理講完了,進入到 code 的部份。
// 顯示的原始圖像
image = new ImageClass();
addChild(image);
// 建立參照影像,這裡是參照紅綠兩種顏色
// 參照影像-魚眼,RADIUS = 100
fisheyelens = createFisheyeMap(RADIUS);
// 建立 dmf,參照紅綠兩種顏色
dmf = new DisplacementMapFilter(fisheyelens,
new Point(RADIUS, 0),
BitmapDataChannel.RED,
BitmapDataChannel.GREEN,
RADIUS * 2, RADIUS * 2);
// add filters
image.filters = [dmf];
addEventListener(Event.ENTER_FRAME, drawEffect);
function drawEffect(e:Event = null):void
{
// following mouse position
dmf.mapPoint = new Point(stage.mouseX - RADIUS, stage.mouseY - RADIUS);
// apply filter
image.filters = [dmf];
}
function createFisheyeMap(radius:int):BitmapData
{
var d:Number = RADIUS << 1;
//參照紅綠:0x808000
var circle:BitmapData = new BitmapData(d, d, false, 0x808000);
var distance:Number;
var cx:int, cy:int, newX:int, newY:int;
var base:Number, t:Number, dx:Number, dy:Number;
var red:uint;
var blue:uint;
var green:uint;
for (cy = 0; cy < d; cy++)
{
for (cx = 0; cx < d; cx++)
{
newX = cx - radius;
newY = cy - radius;
distance = Math.sqrt(newX * newX + newY * newY);
if (distance < radius)
{
base = Math.sin(Math.PI / 2 * distance / radius);
// 值愈大扭曲的愈厲害,預設 INTENSITY = 1
t = Math.pow(base, INTENSITY);
dx = newX * (t - 1) / d;
dy = newY * (t - 1) / d;
red = 0x80 + dx * 0xFF;
//參照紅綠, 拿掉藍
//blue = 0x80 + dx * 0xFF;
green = 0x80 + dy * 0xFF;
circle.setPixel(cx, cy, red << 16 | green << 8 | blue);
}
}
}
return circle;
}
[ref]
http://help.adobe.com/zh_TW/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d61.html
沒有留言:
張貼留言