PaperVision3Dを使ったFlashの3D処理のお勉強

今日は気まぐれで、Flashでの3D処理についてのお話。

ちょっと調べてみると、どうやらPaperVision3DというのがFlashで3D処理を行うライブラリとして有名らしいので、PaperVision3Dの基本的な使い方を調べてみました。

ライブラリの入手

ライブラリのソースはSVNリポジトリで公開されているので、そこから最新版を入手します。
http://papervision3d.googlecode.com/svn/trunk/
自分の場合は、TortoiseSVNでPC上にエクスポートしてきました。

最新版は2.0αというバージョンなんですが、1.xと2.xで実装がだいぶ変わっているらしく、ネット上で自分が調べた範囲でのサンプルコードが1.x用のものが多かったので、今回は1.7というバージョンを使う事にしました。

ただ、2.0だとシェーディングができるようになったり等、色々と機能追加があるようなので、2.0の使い方を勉強した方が後々の為には良いのかもしれません。

サンプルを作ってみる

基本的な使い方については、最後に参考にしたサイトのリンクを並べておいたので、そちらを参照。

実際のコードの流れとしては、次のような感じになります。

  • 3Dシーンを作る。
  • カメラを設定する。
  • マテリアル(テクスチャ)を作る。
  • マテリアルを指定して、オブジェクト(面とか立方体とかいくつかの基本的な図形)を作る。
  • 必要なだけオブジェクトを作って、addChildで追加する。
  • 3Dシーンをレンダリングする。

何か面白いサンプルネタが無いかなと考えていたんですが、あまり複雑になり過ぎない範囲で面白そうなネタが思い付かず、参考にしたサイトのサンプルコードをちょっと弄る程度にしておきました。

という事で、DoCrystalで生成した当ブログの結晶画像をマテリアルにした面を回転させて並べて、結晶を立体っぽく見せるサンプルを作ってみました。

ソースコードは以下の通り。

package {
    import flash.display.*;
    import flash.events.*;
    
    import org.papervision3d.scenes.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.cameras.*;
    import org.papervision3d.materials.*;
    
    [SWF(backgroundColor=0xeeeeff)]
    
    public class DoCrystalFlash extends Sprite {
        private var container : Sprite;
        private var scene     : Scene3D;
        private var camera    : Camera3D;
        private var rootNode  : DisplayObject3D;
        
        private var planeSize : int = 300;      //Planeオブジェクト1辺の長さ
        private var segment   : int = 2;        //面の分割数
        
        private var valx      : Number = 0;
        private var valy      : Number = 0;
        
        public function DoCrystalFlash():void {
            stage.frameRate = 60;
            stage.quality   = "BEST";
            stage.scaleMode = "noScale";
            stage.align = StageAlign.TOP_LEFT;
            this.addEventListener(Event.ENTER_FRAME, loop3D);
            this.stage.addEventListener(Event.RESIZE, onStageResize);
            
            init3D();
        }
        
        private function init3D():void {
            //コンテナ生成
            this.container = new Sprite();
            addChild(this.container);
            this.container.x = this.stage.stageWidth  / 2;
            this.container.y = this.stage.stageHeight / 2;
            
            //シーン生成
            scene = new Scene3D( container );
            
            //カメラ設定
            camera = new Camera3D();
            camera.z = -planeSize;
            camera.focus = 300;
            camera.zoom = 1.5;
            
            //rootNode生成
            rootNode = scene.addChild( new DisplayObject3D( "rootNode" ) );
            
            //マテリアル設定
            var imageMaterial:BitmapFileMaterial = new BitmapFileMaterial( "stellaquacrystal.png" );
            imageMaterial.smooth = false;
            imageMaterial.doubleSided = true;
            //var color:uint = 0x9999ff;
            //var colorMaterial:ColorMaterial = new ColorMaterial(color, 1);
            
            var compoMaterial:CompositeMaterial = new CompositeMaterial();
            //compoMaterial.addMaterial(colorMaterial);
            compoMaterial.addMaterial(imageMaterial);
            compoMaterial.doubleSided = true;
            
            //Planeオブジェクト生成
            for ( var i:int=0; i<3; i++ ) {
                var planeObj:DisplayObject3D = new Plane( compoMaterial, planeSize, planeSize, segment, segment);
                planeObj.rotationY = i * 60;
                rootNode.addChild( planeObj );
            }
            scene.addChild( rootNode );
        }
        
        private function loop3D( event:Event ):void {
            //マウス座標でオブジェクトを回転
            valx -= this.container.mouseX / 50;
            valy -= this.container.mouseY / 50;
            rootNode.rotationY = valx;
            //rootNode.rotationX = valy;
            
            //レンダリング
            this.scene.renderCamera( camera );
        }
        
        private function onStageResize(event:Event):void {
            this.container.x = this.stage.stageWidth  / 2;
            this.container.y = this.stage.stageHeight / 2;
        }
    }
}

見ると分かりますが、参考にしたサイトのサンプルコードをかな〜りパクらせてもらっています。(^^;ゞ

コンパイルする時は以下のような感じ。

C:>mxmlc -compiler.source-path=c:\path_to_papervision3d\as3\tags\1_7\src DoCrystalFlash.as

実物はこちら。

(追記:やっぱりうまく表示できていなかったので、ガジェットはコメントアウトしました。デモは下記の直リンクからどうぞ。)
マウスカーソルの位置によって回転速度と向きが変わります。

結構うねうねとスムーズに動くもんですな。ただ、角度が付いてる時のテクスチャの表示が若干おかしいような気が…。この辺りは要調査…。

(追記:テクスチャが歪むのはsegmentを1にしてたからでした。2に設定してみたらキレイに表示されるようになりました。)

ちなみに、id:nitoyonさんのFlash埋め込みガジェットを使わせて頂きましたが、ちゃんと動いてるかな?

うまく見れない時用の直リンク→http://www.stellaqua.com/docrystalflash/DoCrystalFlash.swf

それにしても、思っていた以上に簡単で直感的に3D処理ができるもんですな。こういう技術は遊び甲斐があって素敵ですね。