ActionScript用三次元描画ライブラリ Papervision3D を使って、その primitive objects (Plane, Cube, Cylinder, Sphere, Cone, PaperPlane) を描画するサンプルを作った。

# Flash コンテンツは重いからブログのトップページにいくつも載せないほうが良さげ……反省 orz

どんな プリミティブ オブジェクト があるのかは note.x | Papervision3Dメモ #1WCAN mini ActionScript Vol.2 資料アップ (Unknown Quality) を参考にした。

Cone が円錐にならずに円柱になっているのは Papervision3D を弄ってみた(4) ~ Revision 62 ~【閃光的網站・弛緩複合体 -Review Division-】 にあるようなバグが原因なんだろうか?

Papervision3D のインストール/セットアップ

Flash/ActionScript の3D描画ライブラリ Papervision3D をダウンロード して、ソースコードを適当な場所へ置く。

単純にパッケージ名指定なしの下位ディレクトリに置いても問題ない。

今回のメインクラスは HelloWorld3D.as で、


C:\flexwork\HelloWorld3D.as
C:\flexwork\org\papervision3d

という置き方でも問題なく外部ライブラリを含めてコンパイルできる。

ただ、Papervision3D のような外部ライブラリを使う場合は、できればライブラリの置き場所を考えたい。

今回は、


C:\flexwork\HelloWorld3D.as
C:\flexwork\libs\org\papervision3d

という libs ディレクトリ内にライブラリのソースコードを入れる構造にした。
libs ディレクトリはコンパイル用設定ファイルに記述すれば問題ない。

コンパイル用設定ファイル(HelloWorld3D-config.xml)を作成する

いままでコマンドオプションにすべて記述してきていたが、せっかくなので設定ファイルを作ってみた。


<flex-config>
  <output>HelloWorld3D.swf</output>
  <default-size>
    <width>400</width>
    <height>400</height>
  </default-size>
  <default-frame-rate>30</default-frame-rate>
  <default-background-color>0x000000</default-background-color>
  <use-network>true</use-network>
  <benchmark>true</benchmark>
  <compiler>
    <incremental>true</incremental>
    <source-path>
      <path-element>libs/</path-element>
    </source-path>
  </compiler>
</flex-config>

compiler.incremental は修正したファイルだけを再コンパイルしてくれるらしい、ありがたいオプション。
compiler.source-path.path-element にて外部ライブラリのソースコードの置き場所を指定している。

設定ファイルの内容については ◆nemu90kWw.の雑記 - mxmlcの使い方とコンパイルオプションを勝手に解説About the application compiler options -- Flex 2 を参考にした。

コンパイル

C:\flexwork>mxmlc HelloWorld3D.as

とすれば、"クラス名-config.xml" な名前の設定ファイル HelloWorld3D-config.xml を自動で読み込んで解釈してくれるらしい。

以下は、コンパイル風景。


C:\flexwork>mxmlc HelloWorld3D.as
設定ファイル "C:\flex_sdk_2\frameworks\flex-config.xml" をロードしています
設定ファイル "C:\flexwork\HelloWorld3D-config.xml" をロードしています
最初の設定 : 437ms
8 個の SWC がロードされました : 860ms
34 個のコンパイル単位をロードしています... 62ms
再コンパイル: C:\flexwork\HelloWorld3D.as
理由: ソースファイルまたはインクルードされているファイルのいずれかが更新されました。
変更されたファイル :1 影響を受けるファイル :0
警告: クラスパスエントリ '' は、クラスパスエントリ 'C:\flexwork' のサブディレクトリです。
 
ファイル :98 時間 : 1860ms
リンクしています... 46ms
最適化しています... 172ms
SWF エンコーディング中... 32ms
C:\flexwork\HelloWorld3D.swf (23166 bytes)
38 個のコンパイル単位を永続化しています... 31ms
合計時間 :3500ms
ピークメモリ使用量 :35 MB (ヒープ :15, ヒープ以外 :20)

ソースコード(HelloWorld3D.as)


package {
 
  import flash.display.*;
  import flash.events.*;
 
  import org.papervision3d.scenes.*;
  import org.papervision3d.objects.*;
  import org.papervision3d.cameras.*;
  import org.papervision3d.materials.*;
 
  public class HelloWorld3D extends Sprite {
 
    private var container : Sprite;
    private var scene     : Scene3D;
    private var camera    : Camera3D;
    private var rootNode  : DisplayObject3D;
 
    private var obj:Array = new Array();
 
    // 3Dオブジェクト踊らせ用パラメータ
    private var valx    : Number = 0;
    private var valy    : Number = 0;
 
    public function HelloWorld3D():void {
 
      // 画面いっぱいに表示(縦横比無視)したいときはコレを使う
      // stage.scaleMode = StageScaleMode.EXACT_FIT;
 
      // リサイズに対応(swfをブラウザで直接ひらいているときとか)
      stage.addEventListener(Event.RESIZE, onStageResize);
 
      // 定期的にイベント発生
      addEventListener(Event.ENTER_FRAME, myLoopEvent);
 
      // 表示用の Sprite オブジェクトを生成
      container = new Sprite();
      container.x = 400 / 2; // at center : swf width  = 400
      container.y = 400 / 2; // at center : swf height = 400
      addChild(container);
 
      // シーンオブジェクトを作る
      scene = new Scene3D(container);
 
      // カメラオブジェクトを作る
      camera = new Camera3D();
      camera.z = -200;
      camera.focus = 500;
      camera.zoom = 1;
 
      // ルートノードを作る
      rootNode = new DisplayObject3D();
      scene.addChild(rootNode);
 
      // いろんな3Dオブジェクトを作ってみて、配列に入れておく
      obj.push(createWireframePlane());
      obj.push(createColorPlane());
      obj.push(createCube());
      obj.push(createCylinder());
      obj.push(createSphere());
      obj.push(createCone());
      obj.push(createPaperPlane());
 
      // 3Dオブジェクトをルートノードに追加
      for(var i:int; i<obj.length; i++){
        rootNode.addChild(obj[i]);
      }
    }
 
    private function createWireframePlane():DisplayObject3D {
 
      var material:WireframeMaterial = new WireframeMaterial();
      material.oneSide = false;
      material.lineColor = 0x00FF00;
      material.lineAlpha = 1;
 
      var planeSize:int = 100;
      var segment:int = 2;
 
      var plane:Plane = new Plane(
        material, planeSize, planeSize, segment, segment);
      plane.x =  0;
      plane.y =  0;
      plane.z =  0;
      return plane;
    }
 
    private function createColorPlane():DisplayObject3D {
 
      var material:ColorMaterial =
        new ColorMaterial(0xFF0000, 1);
      material.oneSide = false;
      material.lineColor = 0x0000FF;
      material.lineAlpha = 1;
 
      var planeSize:int = 100;
      var segment:int = 1;
 
      var plane:Plane = new Plane(
        material, planeSize, planeSize, segment, segment);
      plane.x =  50;
      plane.y =  50;
      plane.z =  50;
      return plane;
    }
 
    private function createCube():DisplayObject3D {
 
      var material:WireframeMaterial = new WireframeMaterial();
      material.oneSide = false;
      material.lineColor = 0xFFFF00;
      material.lineAlpha = 1;
 
      var width:Number  = 50;
      var depth:Number  = 70;
      var height:Number = 90;
      var __segmentsS:Number = 2;
      var __segmentsT:Number = 4;
      var __segmentsH:Number = 8;
      var cube:Cube = new Cube(
        material, width, depth, height,
        __segmentsS, __segmentsT, __segmentsH);
      cube.x =   50;
      cube.y = -100;
      cube.z = -100;
      return cube;
    }
 
    private function createCylinder():DisplayObject3D {
 
      var material:WireframeMaterial = new WireframeMaterial();
      material.oneSide = false;
      material.lineColor = 0x00FFFF;
      material.lineAlpha = 1;
 
      var cylinder:Cylinder = new Cylinder(material);
      cylinder.x =  100;
      cylinder.y =  100;
      cylinder.z =  100;
      return cylinder;
    }
 
    private function createSphere():DisplayObject3D {
 
      var material:WireframeMaterial = new WireframeMaterial();
      material.oneSide = false;
      material.lineColor = 0xFF0000;
      material.lineAlpha = 1;
 
      var sphere:Sphere = new Sphere(material);
      sphere.x =  -100;
      sphere.y =  -100;
      sphere.z =  -100;
      return sphere;
    }
 
    private function createCone():DisplayObject3D {
 
      var material:WireframeMaterial = new WireframeMaterial();
      material.oneSide = false;
      material.lineColor = 0xFF00FF;
      material.lineAlpha = 1;
 
      var radius:Number = 30;
      var height:Number = 200;
 
      var cone:Cone = new Cone(material, radius, height);
      cone.x =  -50;
      cone.y =  100;
      cone.z =  -50;
      return cone;
    }
 
    private function createPaperPlane():DisplayObject3D {
 
      var material:WireframeMaterial = new WireframeMaterial();
      material.oneSide = false;
      material.lineColor = 0x00FF00;
      material.lineAlpha = 1;
 
      var pp:PaperPlane = new PaperPlane(material);
      pp.x =    150;
      pp.y =   -100;
      pp.z =    150;
      return pp;
    }
 
    private function myLoopEvent( event:Event ):void {
 
      valx += container.mouseX / 10;
      valy += container.mouseY / 10;
 
      for(var i:int; i<obj.length; i++){
        obj[i].rotationY = valx;
        obj[i].rotationX = valy;
      }
 
      scene.renderCamera(camera);
    }
 
    private function onStageResize(event:Event):void {
      container.x = stage.stageWidth  / 2;
      container.y = stage.stageHeight / 2;
    }
    
  }
}

Refs. Papervision3D : Flash/ActionScriptによる3D描画ライブラリ (NI-Lab.'s MemoWiki - Papervision3D), Adobe Flex (NI-Lab.'s MemoWiki - Flex)

追記: 2007-11-25

テクスチャ版 -> Papervision3Dのいろいろなオブジェクトにテクスチャを貼ってみる

tags: zlashdot Flash 3D Flash Flex Papervision3D

Posted by NI-Lab. (@nilab)