水面のようなエフェクト

| 1 Comment | No TrackBacks

水面のような揺らぎを与えるエフェクトを作成してみた。

※枠内クリックで実行

ソースはこんな感じ

package {

	import flash.display.*;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.filters.DisplacementMapFilter;
	import flash.filters.DisplacementMapFilterMode;
	import flash.geom.Point;
	import flash.utils.Timer;

	public class WaterSurface extends Sprite {
		//ソースイメージ、ノイズイメージ、ビットマップ
		public var sourceImage:BitmapData;
		private var noiseImage:BitmapData;
		private var softLightBitmap:Bitmap;
		private var bitmap:Bitmap;
		//ノイズのパラメータ
		public var basex:uint;
		public var basey:uint;
		public var octaves:uint;
		public var seed:uint;
		public var offsetArray:Array;
		public var speedArray:Array;
		//置き換えマップの移動強度
		public var filterScale:uint;
		private var filterScaleTemp:uint;
		//減衰が始まるまでの時間(ms)
		public var delayTime:Number;
		//減衰の時間(ms)
		public var decayTime:Number;
		//減衰値
		private var decayValue:Number;
		private var softLightDecayValue:Number;
		//減衰フラグ
		private var decayFlag:Boolean;

		//コンストラクタ(エフェクトをかけるBitmapData、フィルタの強さ、減衰までの時間、減衰の時間、水面の光を入れるか)
		public function WaterSurface(g:BitmapData, _fs:uint = 20, _delay:Number = 1000, _decay:Number = 1000, _softlightFlag:Boolean = true ) 
		{
			sourceImage = g;
			init(_fs,_delay,_decay);
			bitmap = new Bitmap(sourceImage);
			addChild(bitmap);
			softLightBitmap = new Bitmap();
			if (_softlightFlag) {
				softLightBitmap.blendMode = BlendMode.HARDLIGHT;
				softLightBitmap.alpha = 0.5;
				addChild(softLightBitmap);
			}
		}
		//初期化
		private function init(_fs,_delay,_decay):void
		{
			basex = 100;
			basey = 40;
			octaves = 2;
			seed = 0;
			filterScale = _fs;
			filterScaleTemp = filterScale;
			delayTime = _delay;
			decayTime = _decay;
			decayFlag = false;
			initOffsetArray(octaves);
		}
		//オフセットを初期化
		private function initOffsetArray(octaves:int)
		{
			offsetArray = new Array();
			speedArray = new Array();
			if ( octaves > 0 )
			{
				for ( var i:int = 0; i < octaves; i++ )
				{
					offsetArray.push(new Point(0, 0))
					speedArray.push(new Point(
										Math.floor(Math.random() * 4 + 4),
										Math.floor(Math.random() * 4 + 4) ));
				}
			}
		}
		//実行
		public function start() {
			decayValue = filterScale / (stage.frameRate * decayTime/1000)
			softLightDecayValue = softLightBitmap.alpha / (stage.frameRate * decayTime/1000);
			var timer:Timer = new Timer(decayTime, 1);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE,startDecayHandler)
			timer.start();
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		//減衰をはじめる関数
		private function startDecayHandler(e:TimerEvent):void 
		{
			decayFlag = true;
		}
		//EnterFrame
		private function enterFrameHandler(e:Event):void 
		{
			for (var i:int = 0; i < octaves; i++) {
				offsetArray[i].x += speedArray[i].x;
				offsetArray[i].y += speedArray[i].y;
			}
			updatePerlinNoise();
			updateBitmap();
			if (decayFlag) {
				filterScaleTemp -= decayValue;
				softLightBitmap.alpha -= softLightDecayValue;
			}
			if (filterScaleTemp == 0) {
				removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
				filterScaleTemp = filterScale;
				decayFlag = false;
			}
		}
		//ノイズを生成する
		private function updatePerlinNoise():void
		{
			noiseImage = new BitmapData(sourceImage.width, sourceImage.height, false, 0x00000000);
			noiseImage.perlinNoise(basex, basey, octaves, seed, false, true, 2, true, offsetArray);
			softLightBitmap.bitmapData = noiseImage;
		}
		//ソースイメージにフィルタをかける
		private function updateBitmap():void
		{
			var filter:DisplacementMapFilter = getBitmapFilter();
			bitmap.filters = [filter]
		}
		//置き換えフィルタを得る
		private function getBitmapFilter():DisplacementMapFilter {
			var mapPoint:Point       = new Point(0, 0);
			var channels:uint        = 2
			var componentX:uint      = channels;
			var componentY:uint      = channels;
			var scaleX:Number        = filterScaleTemp;
			var scaleY:Number        = filterScaleTemp;
			var mode:String          = DisplacementMapFilterMode.CLAMP;
			var color:uint           = 0;
			var alpha:Number         = 0;
			return new DisplacementMapFilter(noiseImage,
											mapPoint,
											componentX,
											componentY,
											scaleX,
											scaleY,
											mode,
											color,
											alpha);
        }
}

使い方は


obj:WaterSurface = new WaterSurface(BitmapData, FilterScale, DelayTime, DecayTime,SoftlightFlag);
addChild(obj);
obj.start()

といった感じ。引数は(ビットマップデータ、エフェクトの強さ、減衰するまでの時間(ms)、減衰時間(ms)、水面のテカリの有無(bool))

プログラムの流れは

  1. PerlinNoiseを発生させる(発生ごとにオフセットで位置をずらしてアニメーション。)
  2. それを元に置き換えフィルタを作成し、ソースの画像にかける。
  3. 1.へ戻る
  4. filterScaleが0になれば終了

No TrackBacks

TrackBack URL: http://www.norisuke.jp/mt/mt-tb.cgi/6

1 Comment

I couldn’t resist commenting. :)

Leave a comment

About this Entry

This page contains a single entry by ノリスケ published on September 22, 2008 11:55 AM.

TweenMaxを使ってみる。 was the previous entry in this blog.

波紋エフェクト is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Categories

Pages

Powered by Movable Type 4.21-en