Alternativa3Dをやる その3-被写界深度

Filed under 3D, Alternativa3D, AS3



Flashの3D表現ライブラリの1つである、Alternativa3Dに手を出してみました。

使ってるバージョンは7.5です。

今回は、3Dライブラリのデモによくある被写界深度をやってみました。

サンプルはこんな感じです。

以下、今回のメモ。

  • DistanceSortContainerでZソートが使える。
  • 基本、lookAt()みたいなものはないので自前で計算。
  • BlurFilterなど、フィルタ系は普通に使える。

以下ソースです。

package
{
	import alternativa.engine3d.containers.DistanceSortContainer;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.View;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.primitives.Plane;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.filters.BlurFilter;

	[SWF(backgroundColor=0x000000)]
	public class Main extends Sprite
	{
		[Embed(source='ball.png')]
		private var img:Class;

		private static const RADIAN:Number = Math.PI/180;
		private static const FOCUS:Number = 800;
		private static const NUM_PLANE:int = 40;
		private var rootContainer:DistanceSortContainer;
		private var camera:Camera3D;
		private var view:View;
		private var theta:Number;
		private var planes:Vector.<Plane>;

		public function Main()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.quality = StageQuality.LOW;
			stage.frameRate = 30;

			// ベースとなるコンテナ。
			rootContainer = new DistanceSortContainer();
			rootContainer.sortByZ = true;

			// カメラの初期化 (PV3Dでいうフリーカメラみたいなの)。
			camera = rootContainer.addChild(new Camera3D) as Camera3D;
			camera.z = -800;
			camera.x = camera.y = 0;

			// ビューポート (View is DisplayObject)
			view = new View(stage.stageWidth, stage.stageHeight);
			view.logoAlign = StageAlign.TOP_LEFT;
			view.logoHorizontalMargin = 80;
			camera.view = addChild(view) as View;

			// デバッグ情報を表示する場合は記述
			camera.diagramAlign = StageAlign.TOP_LEFT;
			addChild(camera.diagram);

			// Planeを配置
			theta = 0;
			planes = new Vector.<Plane>(NUM_PLANE, true);
			var texture:BitmapData = (new img as Bitmap).bitmapData;
			var mat:TextureMaterial = new TextureMaterial(texture, false, true);
			for(var i:int=0 ; i<NUM_PLANE ; i++)
			{
				var plane:Plane = rootContainer.addChild(new Plane(50, 50,1,1,true)) as Plane;
				plane.setMaterialToAllFaces(mat);
				plane.x = Math.random()*900 - 450;
				plane.z = Math.random()*900 - 450;
				plane.y = Math.random()*900 - 450;
				planes[i] = plane;
			}

			addEventListener(Event.ENTER_FRAME, onFrame);
			stage.addEventListener(Event.RESIZE, onResize);
		}

		private function onResize(e:Event):void
		{
			view.width = stage.stageWidth;
			view.height = stage.stageHeight;
		}

		private function onFrame(e:Event):void
		{
			// カメラの円運動
			camera.x = Math.sin(theta * RADIAN) * 800;
			camera.z = -Math.cos(theta * RADIAN) * 800;
			var rad:Number = -Math.atan2(camera.z, camera.x);
			camera.rotationY = rad - 90*RADIAN;
			theta ++;

			// カメラとの距離に応じてBlurFilterを適用
			for(var i:int=0 ; i<NUM_PLANE ; i++)
			{
				var p:Plane = planes[i];
				p.rotationY = rad +  90*RADIAN;
				var d:Number = Math.abs((camera.x-p.x)*(camera.x-p.x)+(camera.y-p.y)*(camera.y-p.y)+(camera.z-p.z)*(camera.z-p.z) - 640000);
				d /= 50000;
				p.filters = [new BlurFilter(d,d,1)];
			}

			// レンダリング
			camera.render();
		}
	}
}

Post a Comment

Your email is never published nor shared.