変位マップフィルター

(サンプル一覧を表示する)

FlashDevelop を使って、画像に変位マップフィルターを設定してみました。
変位マップフィルターはものすごく複雑なフィルターで、使いこなすのはかなり大変だと思います。

このフィルターは、マスク画像を使った画像処理フィルターです。
例えばゲームの画像処理で、マスク画像を使ってキャラクタの背景をくりぬくということをよくやりますよね。
処理内容は違いますが、変位マップフィルターもそのようなマスク画像を使った画像処理を行います。

背景をくりぬく場合は、透明になる部分かそうでないかという 2 つの状態を判定するためにマスクを使いますが、
変位マップフィルターでは、ゆがみをかける強度を設定するためにマスク画像を使います。

マスク画像の、色の濃さがゆがみをかける強度に対応します。
RGB の内、どれか 1 チャンネルのみ使用し、 0 がゆがみの無い状態、255 が最大にゆがんだ状態です。
また、X 座標・Y 座標と別々に強度を設定することができ、 X 座標 は R のチャンネルを、
Y 座標は G のチャンネルを使用するというような使い方ができます。

下のサンプルでは、Y 座標に対して R のチャンネルの成分を使って、ゆがみを適用しています。
Flash の実行画面
変位マップフィルター

Flashプレーヤーが入っていないか、JavaScriptが無効になっているようです。

Get Adobe Flash player

変位マップフィルター
テキストフィールドがゆがんで表示されています。
ゆがんだままでも、テキストフィールドとして 機能するようです。
しかし、マウスポインタが反応する位置が位置変換前の矩形領域に なっているので、
見たままの位置でマウス操作ができないので使いにくいです。

ソースコード

package 
{
	import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.GradientType;
    import flash.display.SpreadMethod;
    import flash.display.Sprite;
	import flash.events.Event;
    import flash.filters.BitmapFilter;
    import flash.filters.DisplacementMapFilter;
    import flash.filters.DisplacementMapFilterMode;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.text.TextField;

	
	/**
	 * 変位マップフィルターのサンプル
	 * @author Hikipuro
	 */
	public class Main extends Sprite 
	{
        private var size:uint        = 160;
        private var offset:uint      = 60;
        private var labelText:String = "変位マップフィルターのテスト";
		
		/**
		 * コンストラクタ
		 */
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		/**
		 * 初期化メソッド
		 * @param	e
		 */
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			draw();
            createFilter();
            createLabel();
		}

		/**
		 * ステージに、赤色のグラデーションの円を描く
		 */
        private function draw():void
		{
            var matrix:Matrix = new Matrix();
            matrix.createGradientBox(size, size);
            graphics.beginGradientFill(GradientType.RADIAL,
                                       [0xFF0000, 0x000000],
                                       [100, 100],
                                       [55, 200],
                                       matrix,
                                       SpreadMethod.PAD);
            graphics.drawRect(0, 0, size, size);
        }
		
		/**
		 * フィルターを作ってステージに適用
		 */
		private function createFilter():void
		{
            var filter:BitmapFilter = getDisplacementMapFilter();
            filters = new Array(filter);
        }

		/**
		 * 変位フィルターを作成して返す
		 * @return
		 */
        private function getDisplacementMapFilter():BitmapFilter
		{
            var mapBitmap:BitmapData = createBitmapData();
            var mapPoint:Point       = new Point(0, 0);
            var channels:uint        = BitmapDataChannel.RED;
            var componentX:uint      = channels;
            var componentY:uint      = channels;
            var scaleX:Number        = 0;
            var scaleY:Number        = 30;
            var mode:String          = DisplacementMapFilterMode.CLAMP;
            var color:uint           = 0;
            var alpha:Number         = 0;
            return new DisplacementMapFilter(mapBitmap,
                                             mapPoint,
                                             componentX,
                                             componentY,
                                             scaleX,
                                             scaleY,
                                             mode,
                                             color,
                                             alpha);
        }

		/**
		 * ステージに表示されている内容をコピーしてビットマップデータを返す
		 * @return
		 */
        private function createBitmapData():BitmapData
		{
            var bitmapData:BitmapData = new BitmapData(size, size, true, 0x000000);
            bitmapData.draw(this, new Matrix());
            var bitmap:Bitmap = new Bitmap(bitmapData);
            bitmap.x = size;
            addChild(bitmap);
            return bitmapData;
        }

		/**
		 * テキストフィールドを作成する
		 */
        private function createLabel():void
		{
            var tf:TextField = new TextField();
            tf.text = labelText;
            tf.y = offset;
			tf.textColor = 0xFFFFFF;
            tf.width = size - 2;
			tf.height = 18;
			tf.border = true;
			tf.borderColor = 0xFFFFFF;
            addChild(tf);
        }

	}
	
}		

プログラムはコンストラクタから開始されますが、コンストラクタ内に直接処理を入れると、表示したはずの画像が表示されない等の問題が出ることがあるようなので、いったんコンストラクタ内で init() イベントを設定することで開始時間をずらして、init() 内からコードを開始するような書き方になっています。これは、FlashDevelop で ActionScript3 のプロジェクトを作成すると最初からこういう構造になっています。

外部リンク