3D オブジェクトの ViewportLayerにアクセスする

Papervison3D では 3D オブジェクトを Sprite の派生クラスである ViewportLayer に描画しています。ViewportLayer にアクセスすることで、マウスイベントを拾ったり描画された内容にフィルターをかけたりといった Sprite が持っている機能を利用できます。(Papervision3D 逆引きシリーズ)

ViewportLayer にアクセスするには

ViewportLayer にアクセスするには BasicView のプロパティである viewport(Viewport3Dのオブジェクト) の getChildLayer() メソッドを使用します。引数に DisplayObject3D のオブジェクトを渡すとそのオブジェクトの描画先である ViewportLayer を取得できます。

BasecView と Viewport3D と ViewportLayer の関係

View も Viewport3D も ViewportLayer もすべて Sprite を派生したクラスです。3つのクラスはディスプレイツリーで以下のような親子関係にあります。

  • BasecView
    • Viewport3D
      • ViewportLayer
      • ViewportLayer
      • ...
BasicView
Camera, Scene, Viewport など 3D の描画に必須のクラスをまとめたクラス。ただし BasicView は 3D 描画に絶対必要というわけではなく、描画必須クラスをまとめるヘルパクラス的意味合いが強い。Sprite を派生しているのは 便宜上であり、BasicView を用いずに描画必須クラスを直接構築し手動でプロパティを設定したあと Viewport3D を、ドキュメントクラスに追加しても 3D は表示される。
Viewport3D
3D オブジェクトを描画するスクリーンのような位置づけ。カメラと対応してそのカメラから見た 3D オブジェクトが描画される。
ViewportLayer
Viewport3Dに描画される個々のオブジェクトに対応するSprite。ドキュメントを読んだ限りでは getChildLayer() した時に生成されることもあるらしい。getChildLayer() されるまではすべての 3D オブジェクトが Viewport3D に描画されているが、各々の 3D オブジェクトに対応した Sprite が必要な時には ViewportLayer が生成され、描画先がこっちに変わるのかもしれない。

ソース

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.materials.shadematerials.GouraudMaterial;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.view.layer.ViewportLayer;
    import org.papervision3d.lights.PointLight3D;
    
    [SWF(width="320", height="240", backgroundColor="#FFFFFF")]
    public class Sample004 extends Sprite
    {
        public function Sample004 ()
        {            
            // PaperVision のビューを作成
            var view:BasicView = new BasicView();
            view.camera.y = 100;
            view.camera.x = 300;
            addChild(view);
            view.startRendering();
            
            // 光源を作る
            var light:PointLight3D = new PointLight3D(false);
            light.x = 500;
            light.y = 800;
            light.z = 0;

            // バウンドエリアに対応する 3D オブジェクトを作る
            var cubes:Array = [];
            for(var i:int=0; i<3; i++) {
                cubes[i] = new Cube(new MaterialsList({all:new GouraudMaterial(light, 0xeeeeee, 0x666666)}), 100, 100, 100);
                cubes[i].x = -150 + i*150;
                view.scene.addChild(cubes[i]);
            }
            
            // 毎フレームの処理
            var cnt:int=0;
            addEventListener(Event.ENTER_FRAME, function(e:Event):void {
                view.camera.x = 800*Math.cos(cnt*Math.PI/180);
                view.camera.z = 800*Math.sin(cnt*Math.PI/180);
                cnt++;
            });
            
            // 各 3DObject の ViewportLayer にアクセス
            for(i=0; i<3; i++) {
                // ViewportLayer を取得
                var layer:ViewportLayer = view.viewport.getChildLayer(cubes[i]);
                // イベントリスナーを追加
                layer.addEventListener(MouseEvent.MOUSE_OVER, function(e:MouseEvent):void {
                    ViewportLayer(e.target).buttonMode = true;
                    ViewportLayer(e.target).filters = [ new GlowFilter(0xcc0000) ];
                });
                layer.addEventListener(MouseEvent.MOUSE_OUT, function(e:MouseEvent):void {
                    ViewportLayer(e.target).filters = [];
                });
            }
        }
    }
}