Away3D 4.0 Beta でキラキラエフェクト


今日も定時を過ぎたので、ちょっとだけ Away3D 4.0 Beta の勉強を。

以前 wonderfl に PV3D を使った こういうの をポストしたことがあって、これになんかいい感じのエフェクトを付けてみたかったんですが激重で…
動かすだけで一杯一杯だったのであっさり断念しました。

そして月日は流れ、Stage3D を手軽に使える便利な世の中になってきたので、今回は Away3D 4.0 を使って再挑戦してみました。
で、なんとなくできたのがこれ。

Away3D_Gitter_Demo

Away3D 4.0 Beta BloomFilter3D Demo

※ 画像をクリックするとデモが開きます。

今回のコードはこんな感じ。
away3d.filters.BloomFilter3D でキラキラ効果を付けています。

package
{
	import away3d.cameras.Camera3D;
	import away3d.cameras.lenses.PerspectiveLens;
	import away3d.containers.Scene3D;
	import away3d.containers.View3D;
	import away3d.debug.AwayStats;
	import away3d.filters.BloomFilter3D;
	import away3d.primitives.WireframeCube;

	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Vector3D;
	import flash.utils.getTimer;

	[SWF( backgroundColor = "0", frameRate = "60", width = "800", height = "600" )]

	public class Main extends Sprite
	{

		private var _view:View3D;
		private var _scene:Scene3D;
		private var _camera:Camera3D;

		public function Main()
		{
			setup();
		}

		private function setup():void
		{
			_view = addChild( new View3D()) as View3D;
			_view.antiAlias = 4;
			_view.backgroundColor = 0;

			var lens:PerspectiveLens = new PerspectiveLens( 70 );
			_view.camera.lens = lens;

			_scene = _view.scene;
			_camera = _view.camera;

			var bloom:BloomFilter3D = new BloomFilter3D( 8, 8, .3, .5, .01 );
			_view.filters3d = [ bloom ];

			setObj();
			addEventListener( Event.ENTER_FRAME, update );

			var awayStats:AwayStats = new AwayStats( _view );
			addChild( awayStats );
		}

		private var _numLoops:int = 20;
		private var _pitchOfCube:int = 500;

		private function setObj():void
		{
			var n:int = 0
			var i:int = 0
			while ( n < _numLoops )
			{
				var h:Number = ( 360 / _numLoops ) * n
				i = 0
				while ( i < _numLoops )
				{
					var s:Number = Math.random() * 1
					var v:Number = i * .05;
					if ( i % 2 != 0 )
						v += .05;
					var rgb:int = ColorUtil.hsvToRgb( h, s, v )
					//
					var cube:WireframeCube = new WireframeCube( 70, 70, 70, rgb, 2 );
					cube.y = v * ( _pitchOfCube * 1.6 ) - _pitchOfCube;
					cube.x = Math.cos( h * i * Math.PI / 180 ) * s * _pitchOfCube;
					cube.z = Math.sin( h * i * Math.PI / 180 ) * s * _pitchOfCube;
					_scene.addChild( cube )
					//
					i++
				}
				n++
			}
		}


		private function update( e:Event ):void
		{
			_camera.x = 500 * Math.sin( getTimer() / 4000 );
			_camera.z = 100 * Math.cos( getTimer() / 2000 );
			_camera.y = 500 * Math.sin( getTimer() / 5000 );
			_camera.lookAt( new Vector3D());
			_view.render();
		}
	}
}

HSV と RGB を相互変換する ColorUtil クラス。

package
{
	public class ColorUtil
	{
		// HSV > RGB
		public static function hsvToRgb( h:Number, s:Number, v:Number ):Number
		{
			var cv:Number = Math.round( v * 255 );
			var r:Number = cv;
			var g:Number = cv;
			var b:Number = cv;
			if ( s > 0 )
			{
				var i:Number = Math.floor( h / 60 );
				var f:Number = h / 60 - i;
				var m:Number = Math.round( v * ( 1 - s ) * 255 );
				var n:Number = Math.round( v * ( 1 - s * f ) * 255 );
				var k:Number = Math.round( v * ( 1 - s * ( 1 - f )) * 255 );
				switch ( i )
				{
					case 0:
						g = k;
						b = m;
						break;
					case 1:
						r = n;
						b = m;
						break;
					case 2:
						r = m;
						b = k;
						break;
					case 3:
						r = m;
						g = n;
						break;
					case 4:
						r = k;
						g = m;
						break;
					case 5:
						g = m;
						b = n;
						break;
				}
			}
			return r << 16 | g << 8 | b;
		}
		
		// RGB > HSV
		public static function colorToHsv( color:Number ):Object
		{
			var r:Number = color >> 16;
			var g:Number = ( color >> 8 ) & 0xFF;
			var b:Number = color & 0xFF;
			var max:Number = Math.max( r, Math.max( g, b ));
			var min:Number = Math.min( r, Math.min( g, b ));
			var range:Number = max - min;
			var h:Number = 0;
			var s:Number = 0;
			var v:Number = max / 255;
			if ( v > 0 )
			{
				s = range / max;
				if ( s > 0 )
				{
					var cr:Number = ( max - r ) / range;
					var cg:Number = ( max - g ) / range;
					var cb:Number = ( max - b ) / range;
					if ( r == max )
					{
						h = cb - cg;
					}
					else if ( g == max )
					{
						h = 2 + cr - cb;
					}
					else
					{
						h = 4 + cg - cr;
					}
					h *= 60;
					if ( h < 0 )
					{
						h += 360;
					}
				}
			}
			return { h: Math.round( h * 100 ) * 0.01, s: Math.round( s * 100 ), v: Math.round( v * 100 )};
		}
	}
}

まぁなんというかこれも…
既存のエフェクトを利用しているだけなので、超簡単ですよね。