ActionScript3でゆらゆら

AS3で画像をゆらゆらさせてみた。

元画像はこれ↓

この画像をゆらゆらさせるとこんな感じ。



わかりにくいけど、一応ゆらゆら動いてます。


以下、スクリプト

Root.as

package {

	import flash.display.Sprite;
	import flash.display.StageAlign;

	public class Root extends Sprite {

		public function Root():void {

			stage.scaleMode = "noScale";
			stage.align = StageAlign.TOP_LEFT;

			graphics.beginFill(0x444444);
			graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			graphics.endFill();

			addChild(new Base());
		}
	}
}

Base.as

package {

	import flash.display.Sprite;
	import flash.display.Loader;
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.geom.Point;
	import flash.filters.DisplacementMapFilter;
	import flash.filters.DisplacementMapFilterMode;
	import flash.events.Event;
	import flash.net.URLRequest;

	public class Base extends Sprite {

		public static const IMAGE_WIDTH:Number = 400;
		public static const IMAGE_HEIGHT:Number = 300;
		public static const BITMAPDATA_WIDTH:Number = IMAGE_WIDTH;
		public static const BITMAPDATA_HEIGHT:Number = IMAGE_HEIGHT;
		public static const OFFSET:Number = 0;
		public static const BASE:Number = 1 / 8;
		public static const PERLIN_OCTAVES:Number = 6;
		public static const COLOR_CHANNEL:Number = BitmapDataChannel.BLUE | BitmapDataChannel.GREEN;
		public static const SCALE:Number = 15;

		private var bmpData:BitmapData;
		private var point:Point;

		public function Base():void {

			// PointクラスとBitmapDataクラスは毎フレーム生成する必要はない
			this.point = new Point(OFFSET, OFFSET);
			this.bmpData = new BitmapData(BITMAPDATA_WIDTH, BITMAPDATA_HEIGHT);

			// 画像データ読み込み
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
			loader.load(new URLRequest("photo.jpg"));
			loader.scaleX = 0.5;
			loader.scaleY = 0.5;
			addChild(loader);
		}

		private function completeHandler(e:Event):void {

			// 画像の読み込みが完了したらイベントハンドラーを登録
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}

		private function enterFrameHandler(e:Event):void {

			this.bmpData.perlinNoise(BITMAPDATA_WIDTH * BASE, BITMAPDATA_HEIGHT * BASE, PERLIN_OCTAVES, 
									Math.floor(Math.random() * 10), false, true, COLOR_CHANNEL, false);

			var displacementMap:DisplacementMapFilter = new DisplacementMapFilter(this.bmpData, this.point, 
					BitmapDataChannel.BLUE, BitmapDataChannel.GREEN, SCALE, SCALE, DisplacementMapFilterMode.CLAMP);

			filters = [displacementMap];
		}
	}
}

ゆらゆらさせている処理はBaseクラスのenterFrameHandlerメソッド内。

this.bmpData.perlinNoise(BITMAPDATA_WIDTH * BASE, BITMAPDATA_HEIGHT * BASE, PERLIN_OCTAVES, 
									Math.floor(Math.random() * 10), false, true, COLOR_CHANNEL, false);

var displacementMap:DisplacementMapFilter = new DisplacementMapFilter(this.bmpData, this.point, 
					BitmapDataChannel.BLUE, BitmapDataChannel.GREEN, SCALE, SCALE, DisplacementMapFilterMode.CLAMP);

filters = [displacementMap];

まずBitmapDataクラスのperlinNoiseメソッドでノイズイメージを生成。

この処理で↓こんなBitmapDataが生成される。

これを置き換え用BitmapDataとしてDisplaycementMapFilterを生成。

最後にBaseクラスのfiltersに、生成したDisplacementMapFilterをセットしてあげれば、画像がゆらゆらしてくれる。


DisplacementMapFilterクラスの生成について、少し補足します。

var displacementMap:DisplacementMapFilter = new DisplacementMapFilter(this.bmpData, this.point, 
					BitmapDataChannel.BLUE, BitmapDataChannel.GREEN, SCALE, SCALE, DisplacementMapFilterMode.CLAMP);

ここで、3番目と4番目の引数に注目してみましょう。

3番目の引数で青、4番目の引数で緑を指定しています。

3番目の引数は、X方向にどのカラーチャネルを使用するか、
4番目の引数は、Y方向にどのカラーチャネルを使用するかを指定します。

ここで、↓先ほどの変な画像。

この画像の青の部分を使用してX方向に置き換え、緑の部分を使用してY方向に置き換えとなります。

これを毎フレーム処理する事で、画像がゆらゆらするようになるわけですね。