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();
}
}
}
