PV3DをAway3Dに移植(パーティクルタイポグラフィ)

先日Papervision3Dを使ってパーティクル生成を作成しましたが、Away3Dに移植してみました。下のFlashをクリックすると再生が始まります。

Away3Dを試してみて、、、

Away3Dを使った感想

Away3DだとZ-depth filterという機能があるのですが、primitiveインスタンス(たぶんメッシュとかの素材)でないとフィルタが適用できなかったので、MCやSpriteにZ座標のフィルタをかけられないようです。

PV3DAway3Dの比較

PV3DAway3Dソースコードレベルの違いはそんなに大きくなかったです。3D空間の宣言が違ったこと、MovieClipアセット(MCを3D要素に使うときに作る素材オブジェクトのこと)のサイズ設定方法の違い、成果物swfの容量の違いでしょうか。

3D空間の宣言の違いについて

Away3Dの3D空間の宣言
camera = new Camera3D({x:0, y:0, z:-200, focus:200, zoom:2})
scene  = new Scene3D();
world  = new ObjectContainer3D();
scene.addChild(world);

// create a 3D-viewport. use BASIC renderer for now
view = new View3D({x:0, y:0, renderer:Renderer.BASIC, camera:camera, scene:scene});

// ビューポートを画面に追加
addChild(view);

Away3Dはカメラやシーンの他に、まとめ役のビューポートを設定するのがPV3Dと違うところ。

PV3Dの3D空間の宣言
var world:Sprite = new Sprite();
addChild(world);

scene = new Scene3D(world);
container = new DisplayObject3D();
camera  = new Camera3D(container,2,200,{x:0, y:0, z:-200});

PV3Dはシーンとカメラさえ設定すれば表示できる手軽さが便利。

MovieClipアセットのサイズ設定について

PV3DはMovieClipアセットを作るとき、サイズ固定させなければならず個人的には不便だと思っているのですが、Away3Dでは自動的に設定されるようで便利でした。

Away3DのMovieClipアセットの設定方法
var obj:Object3D = new MovieClipSprite(mc);
PV3DのMovieClipアセットの設定方法
var material:MovieMaterial = new MovieMaterial(mc, true,{doubleSided:false, smooth:false} );
var obj:Plane = new Plane(material, 50, 50, 0, 0);

Planeインスタンスを作るときに、適当な縦横サイズを設定する必要があり自動で設定されないのが不便。PV3Dで個人的に唯一不便だと思っている箇所です。

成果物swfの容量の違い

Away3Dの方が高機能だと思いますが、その分容量も膨らむようです。といってもただが100KB程度ですが。

ソースコード

ドキュメントクラス AwaySample.as

package
{
    // Away3D
    import away3d.cameras.Camera3D;
    import away3d.containers.*;
    import away3d.core.base.*;
    import away3d.core.render.*;
    import away3d.events.*;
    import away3d.materials.*;
    import away3d.primitives.*;
    import away3d.sprites.*;
    
    // Tweener
    import caurina.transitions.Tweener;
    
    // Flash
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.text.*;
    import flash.utils.*;

    [SWF(width="450",height="300",frameRate="60",backgroundColor="#000000")]
    
    public class AwaySample extends Sprite
    {
        // 定数
        private const PARTICLE_ROUND   :int = 250;
        private const PARTICLE_AMOUNT  :int = 2;
        private const PARTICLE_INTERVAL:int = 50;
        private const MOUSE_INTERVAL   :int = 50;
        
        // 3D定義
        private var scene  :Scene3D;
        private var view   :View3D;
        private var camera :Camera3D;
        private var world  :ObjectContainer3D;
        
        // マウス追随用の変数
        private var oldX:Number;
        private var oldY:Number;
        
        // 背景画像
        [Embed(source="asset/bg.png")]
        private var BackGround:Class;
    
        /**
         * コンストラクタ 
         */            
        public function AwaySample()
        {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align     = StageAlign.TOP_LEFT;
            stage.quality   = StageQuality.LOW;
            
            stage.addEventListener(MouseEvent.CLICK, init);
            
            addChild(new BackGround());
        }
        
        /**
         * 初期化 
         * @param event
         */        
        private function init(event:MouseEvent):void
        {
            // マウスクリックを解除
            stage.removeEventListener(MouseEvent.CLICK, init);
            
            //ピクセル等倍になる距離 = camera.focus * camera.zoom - camera.focus
            camera = new Camera3D({x:0, y:0, z:-200, focus:200, zoom:2})
            scene  = new Scene3D();
            world  = new ObjectContainer3D();
            scene.addChild(world);
            
            // create a 3D-viewport. use BASIC renderer for now
            view = new View3D({x:0, y:0, renderer:Renderer.BASIC, camera:camera, scene:scene});
            
            // ビューポートを画面に追加
            addChild(view);
            
            // レンダリング
            stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            
            // パーティクル生成タイマー
            var particleTimer:Timer = new Timer(PARTICLE_INTERVAL);
            particleTimer.start();
            particleTimer.addEventListener(TimerEvent.TIMER, createParticle );
            
            // マウス追随タイマー
            var mouseTimer:Timer = new Timer(MOUSE_INTERVAL);
            mouseTimer.start();
            mouseTimer.addEventListener(TimerEvent.TIMER, drawMouseLine );
        }

        /**
         * 3Dレンダリング 
         * @param event
         */        
        private function onEnterFrame(event:Event):void
        {
            view.render();
        }
        
        /**
         * パーティクル生成 
         * @param event
         */        
        private function createParticle(event:TimerEvent):void
        {
            // 親を生成(マウス座標に配置)
            var wrap:ObjectContainer3D = new ObjectContainer3D();
            wrap.x = stage.mouseX;
            wrap.y = -stage.mouseY;
            
            for(var i:int=0; i .8)        mc.filters = [ new BlurFilter(8, 8, 3) ]
                else if(mc.scaleX > .6) mc.filters = [ new BlurFilter(4, 4, 2) ]
                
                var obj:Object3D = new     MovieClipSprite(mc);
                Tweener.addTween(obj,
                {
                    x : Math.random()*PARTICLE_ROUND - PARTICLE_ROUND/2,
                    y : 500, 
                    z : Math.random()*PARTICLE_ROUND - PARTICLE_ROUND/2,
                    time       : 3,
                    transition : "easeInExpo",
                    onCompleteParams:[wrap, obj],
                    onComplete : function(w:ObjectContainer3D, o:Object3D):void{ w.removeChild(o); }
                });
                
                wrap.addChild(obj);
                
            }
            world.addChild(wrap);
        }
        
        /**
         * マウス追随を描画 
         * @param event
         */        
        private function drawMouseLine(event:TimerEvent):void
        {
            var sp:Sprite = new Sprite();
            sp.graphics.lineStyle(1, 0x99CC00);
            sp.graphics.moveTo(oldX, oldY);
            sp.graphics.lineTo(mouseX, mouseY);
            addChild(sp);
            
            oldX = mouseX;
            oldY = mouseY;
            
            Tweener.addTween(sp,
            {
                alpha      : 0,
                time       : 3,
                onComplete : function():void{ removeChild(sp); }
            });
        }
    }
}

はてなの仕様で</pp>という意味もないタグが上記ソースに入っていますので、上記ソースをお試しになる際は取り除いてください。