Hatena::ブログ(Diary)

flashrod このページをアンテナに追加 RSSフィード

2007-05-19 AS3 で Papervision3D チュートリアル

AS3でPV3D (素のFlex 2 SDK版) 11:06  AS3でPV3D (素のFlex 2 SDK版)を含むブックマーク

巷で話題のPapervision3Dだ。ずっとやりたかったのだけどなかなか手が出なかった。やっと余裕が出てきたので遅まきながらやってみる。Flash CS3もFlash 9 αもFlex BuilderAntも使わない。素の Flex 2 SDK と *.as ファイルだけで *.mxmlもなし。

Get Involved

ソースはsvnでゲットできる。WindowsだとTortoiseSVNで。適当なディレクトリを作って、

 svn export http://svn1.cvsdude.com/osflash/papervision3d/

でOK。as2とas3サブディレクトリができる。今日の時点でリビジョン68がとれた。ずーっと追いかけるならexportじゃなくてcheckoutして時々updateしたらよい。

ここでライブラリswcを作っておくと後でアプリを作るとき楽だと思うので作っておく。swcをつくるのはFlex 2 SDK の compc で。

compc -include-sources as3/trunk/src -output pv3d.swc

これでpv3d.swc ができる。Flex BuilderFlash CS3でのやりかたは持ってないので分からない。できたswcをどこか、/usr/lib/flash の下あたりにでも入れておけばよい。どうでもいいけど.swcファイルは単なるzipファイルのようだ。

Hello World

適当なチュートリアルを探してみたけど、この辺がいいかな。自分で調べなくても既に誰かがやってくれた成果を公開してくれてる。なんて素敵な時代。

Flash CS3もFlash 9 Alphaも無いので.flaファイルは読めないのだけど、ま、何とかなる。どうでもいいけど.flaファイルはOLE構造化ファイルのようだ。MFCアプリなのかな。

ここは英語だけど、このチュートリアルが最小のようだ。

このチュートリアルに沿って Flex 2 SDK でビルドできる Hello3D.as を作ってみる。ちなみに沿ってはいるけど和訳ではないので注意。

(1) 新しいスプライトを作って表示リストにいれておく。これがコンテナ。

            var container:Sprite = new Sprite();
            addChild(container);

(2) そのコンテナへの参照を指定して3Dシーンを作る。

            var scene3D:Scene3D = new Scene3D(container);

(3) カメラを作る。レンダリングはカメラレンズを通して見ているようにシーンは描画される。

            var camera:Camera3D = new Camera3D();

(4) 3Dシーンにルートオブジェクトを作る。3Dオブジェクトでツリー構造を作るようだ。

            var rootNode:DisplayObject3D = scene3D.addChild(new DisplayObject3D("rootNode"));

平面の作成

(1) ビットマップマテリアルを作るのなら、最初にBitmapDataを作っておく必要がある。

            var texture:BitmapData = new BitmapData(幅, 高さ);

BitmapDataの内容は、普通のBitmapDataプログラミングなので好きなようにしたらよい。

(2) マテリアルを作る。ビットマップマテリアルを作るにはこう:

            var material:BitmapMaterial = new BitmapMaterial(texture);
            material.oneSide = false;

oneSide = false は、両面を見えるようにする。

カラーマテリアルを作るならこう:

            var material:ColorMaterial = new ColorMaterial(0xFF0000);
            material.doubleSided = true;

doubleSided = true も両面を見えるようにする。どっちを使っても良いみたいだ。

(3) 平面を作る

            var plane:Plane = new Plane(material, 幅, 高さ, セグメントx, セグメントy);

セグメントは平面を小さな三角形に分割する数を指定する。ここは2くらいで。多分模様が細かいときは大きくするんじゃないのかなあ。

(4) つくった平面を3Dオブジェクトツリーに追加する

            var plane3D:DisplayObject3D = rootNode.addChild(plane, "plane3D");

引数plane と返り値の plane3D は同じみたいだ。

(5) 必要なら物体を回転させたり移動させたり拡大させたり好きなように。

            plane3D.rotationY = -90;

視野の変更

カメラを移動させたり焦点を変えたりする。

            camera.focus = 1000;

カメラレンズを通した見た目でコンテナにレンダリングする。

            scene3D.renderCamera(camera);

まとめると Hello3D.as はこうなる。

package {
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize
    import flash.text.TextFormat;
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.Plane;
    import org.papervision3d.scenes.Scene3D;
    [SWF(width="640", height="480", backgroundColor="#FFFFFF")]
    public class Hello3D extends Sprite {
        private const W:int = 200;
        private const H:int = 200;
        public function Hello3D() {
            var container:Sprite = new Sprite();
            container.x = 640 / 2;
            container.y = 480 / 2;
            addChild(container);
            var scene3D:Scene3D = new Scene3D(container);
            var camera:Camera3D = new Camera3D();
            var rootNode:DisplayObject3D = scene3D.addChild(new DisplayObject3D("rootNode"));
            var texture:BitmapData = new BitmapData(W, H);
            texture.fillRect(new Rectangle(0, 0, W, H), 0x80000000);
            var tf:TextField = new TextField();
            tf.autoSize = TextFieldAutoSize.LEFT;
            var fmt:TextFormat = new TextFormat();
            fmt.size = 24;
            tf.defaultTextFormat = fmt;
            tf.textColor = 0xFFFFFF;
            tf.text = "Hello World";
            texture.draw(tf);
            var material:BitmapMaterial = new BitmapMaterial(texture);
            material.oneSide = false;
            var plane:Plane = new Plane(material, W, H, 2, 2);
            var plane3D:DisplayObject3D = rootNode.addChild(plane, "plane3D");
            camera.focus = 1000;
            scene3D.renderCamera(camera);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, function(e:MouseEvent):void {
                plane3D.rotationY = container.mouseX;
                plane3D.rotationX = -container.mouseY;
                scene3D.renderCamera(camera);
            });
         }
    }
}

上のf-siteのサンプルを真似してマウス移動で物体を回転させるようにしてみた。

ビルドmxmlc で 上で作っておいた pv3d.swc を指定して

 mxmlc -include-libraries=/usr/lib/flash/pv3d.swc Hello3D.as

これで Hello3D.swf ができる。作業を始めてからここまで全く期待通りで何も引っかかるところが無い。すばらしい。

平面だとあまり面白くないので立方体にしてみる。Planeの代わりにCubeオブジェクトを作れば良いだけ。

            var cube:Cube = new Cube(material, 幅, 高さ, 奥行き, 2, 2, 2);

f:id:flashrod:20070519110103p:image

ちょっと遅いマシンでも結構快適に動く。と思ったら時々止まるなあ。GCだろうか。ま、あまり実害は無い。

どう話をひろげようか

こんなに出来が良いと自前でクォータニオンとか作ってる場合じゃない。逆に自前で行くならPV3Dとは異なるアプローチか、よほどすごい何かが必要だ。3Dライブラリを提供する人は大変だね。

PV3Dを使うのは非常に簡単。こんなに簡単だと、ただ単に3Dにしました、だけだと芸が無い。いや、ただ単に3Dにしただけなのにこんなにすごい!って事があるかもしれない。ないかもしれない。3Dアプリを作る人も、簡単になったぶんどこか別のところを大変にしないといけないかもしれない。