Papervision3D入门第5步

分享Flash3DPapervision3D by 达达 at 2007-09-19

呵呵,最近工作比较忙,所以都没怎么动PV3D了。正好今晚出门回来,看Blog上Colorfulee在《入门第3步》给我留言,问我怎么分别相应鼠标事件,于是我就顺便研究了下 :) ,花了半个多小时,终于被我找到办法。今天入门第5步就讲“3D交互”吧 :D

PV3D中提供了一组专门负责3D交互的类,这些类都是以Interactive为开头,其中有InteractiveSprite,InteractiveScene3D,InteractiveSceneManager,InteractiveWireframeMaterial 等等。要实现3D交互功能我们就需要用到这些类。

我们这一讲的代码是基于《入门第3步》当中的Cube代码修改的,所以如果你可能需要参考《入门第3步》的代码。

首选,我们需要把3D场景的容器对象,改成InteractiveSprite类型:

//...

import org.papervision3d.utils.InteractiveSprite;

//...

[SWF(width='200',height='200',backgroundColor='0xFFFFFF',frameRate='30')]
public class Main extends Sprite
{
    //...

    private function Init3D():void {
        //...

        // 创建3D舞台的容器
        _container = new InteractiveSprite(); //原先的代码:new Sprite();

        //...
    }

    //...
}

接着我们要把3D舞台改成支持交互操作的InteractiveScene3D类型:

//...

import org.papervision3d.scenes.InteractiveScene3D;

//...

[SWF(width='200',height='200',backgroundColor='0xFFFFFF',frameRate='30')]
public class Main extends Sprite
{
    //...

    private var _scene:InteractiveScene3D; //原先的代码::MovieScene3D;

    private function Init3D():void {
        //...

        // 创建3D舞台
        _scene = new InteractiveScene3D(_container);   //原先的代码:new MovieScene3D(_container);

        //...
    }

    //...
}

比起普通的PV3D动画程序,PV3D的3D交互程序多了一个InteractiveSceneManager对象,它负责所有的3D事件。所以代码中需要增加一个私有变量:

//...

import org.papervision3d.utils.InteractiveSceneManager;

//...

[SWF(width='200',height='200',backgroundColor='0xFFFFFF',frameRate='30')]
public class Main extends Sprite
{
    //...

    private var _interactiveSceneManager:InteractiveSceneManager;

    private function Init3D():void {
        //...

        _interactiveSceneManager = _scene.interactiveSceneManager;
        _interactiveSceneManager.faceLevelMode = true;

        //注册3D鼠标事件
        _interactiveSceneManager.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, OnObj3DMouseOver);
        _interactiveSceneManager.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, OnObj3DMouseOut);

        //...
    }

    private function OnObj3DMouseOver(event:InteractiveScene3DEvent):void{
        event.face3d.material = this._material2;  //换材质,突出显示被选中的face
    }

    private function OnObj3DMouseOut(event:InteractiveScene3DEvent):void{
        event.face3d.material = this._material1;  //换回原来材质
    }

    //...
}

你可以看到上面的代码将InteractiveSceneManager对象的faceLevelMode设置成true。这里需要说明下,PV3D给InteractiveSceneManager设计了两种状态,一种是对象(object)级别的交互,一种是面(face)级别的交互,对象级别的交互就是只精确到某个对象,比如一个Cube或者一个Plane,而面级别的交互可以精确到PV3D显示的最小单位face3D,面级别的交互更精确,但是执行效率比对象级别低很多,所以大家设计交互时需要考虑到这点。

另外代码中用到的贴图需要换成支持交互事件的InteractiveWireframeMaterial类型,为了突出显示,我还另外用了一个InteractiveColorMaterial类型的红色贴图。关于材质贴图的代码修改:


import org.papervision3d.materials.InteractiveWireframeMaterial;
import org.papervision3d.materials.InteractiveColorMaterial;

[SWF(width='200',height='200',backgroundColor='0xFFFFFF',frameRate='30')]
public class Main extends Sprite
{
    //...

    private var _material1:InteractiveWireframeMaterial;
    private var _material2:InteractiveColorMaterial;

    private function Init3D():void {
        //...

        _material1 = new InteractiveWireframeMaterial(0x000000);
        _material2 = new InteractiveColorMaterial(0xFF0000);

        materialList.addMaterial(_material1, "top");
        materialList.addMaterial(_material1, "bottom");
        materialList.addMaterial(_material1, "front");
        materialList.addMaterial(_material1, "back");
        materialList.addMaterial(_material1, "left");
        materialList.addMaterial(_material1, "right");

        //...
    }

    //...
}

整个程序的运行效果如下(请把鼠标放上去试试):

这个例子中只实现了face的选择,并没有做到Colorfulee问我的选择Cube某个面的效果,不过通过在鼠标事件中比对材质的id,我们是可以知道Cube的哪个面被选择的,不过需要为每个面都示例化一个材质贴图,不能像示例代码中那样几个面都共享同一个贴图实例。有兴趣的朋友可以自己试试看 :) 。我不希望看我Blog的朋友都变成懒得动手的大懒虫噢。

今天的学习就到这里,我想光通过看我的《PV3D入门》是没办法完全掌握PV3D的,因为我每一讲只能选重点的,或者朋友问得比较多的讲,有很多特性我是没办法介绍到的,所以建议大家出来看我的《PV3D入门》外,还可以通过PV3D的帮助文档,Wiki,或阅读PV3D源代码来更深入的了解PV3D。

今天的完整示例代码:

package {
    import flash.display.Sprite;
    import flash.events.Event;

    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.scenes.MovieScene3D;
    import org.papervision3d.materials.MaterialsList;
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.core.proto.MaterialObject3D;

    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.Cube;

    //--New--
    import org.papervision3d.utils.InteractiveSprite;
    import org.papervision3d.scenes.InteractiveScene3D;
    import org.papervision3d.utils.InteractiveSceneManager;
    import org.papervision3d.events.InteractiveScene3DEvent;
    import org.papervision3d.materials.InteractiveWireframeMaterial;
    import org.papervision3d.materials.InteractiveColorMaterial;

    [SWF(width='200',height='200',backgroundColor='0xFFFFFF',frameRate='30')]
    public class Main extends Sprite
    {
        private var _container :Sprite;
        private var _scene:InteractiveScene3D; // :MovieScene3D;
        private var _camera :Camera3D;

        private var _displayObj:DisplayObject3D;

        private var _material1:InteractiveWireframeMaterial;
        private var _material2:InteractiveColorMaterial;

        private var _interactiveSceneManager:InteractiveSceneManager;

        public function Main()
        {
            Init3D();
        }

        private function Init3D():void {
            // 创建3D舞台的容器
            _container = new InteractiveSprite();  //new Sprite;
            _container.x = 100;
            _container.y = 100;
            addChild( _container );

            // 创建3D舞台
            _scene = new InteractiveScene3D(_container); // new MovieScene3D( _container );

            //--New--
            _interactiveSceneManager = _scene.interactiveSceneManager;
            _interactiveSceneManager.faceLevelMode = true;

            _interactiveSceneManager.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, OnObj3DMouseOver);
            _interactiveSceneManager.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, OnObj3DMouseOut);

            // 创建摄像头
            _camera = new Camera3D();
            _camera.z = -500;
            _camera.zoom = 5;

            var materialList:MaterialsList = new MaterialsList();

            _material1 = new InteractiveWireframeMaterial(0x000000);
            _material2 = new InteractiveColorMaterial(0xFF0000);

            materialList.addMaterial(_material1, "top");
            materialList.addMaterial(_material1, "bottom");
            materialList.addMaterial(_material1, "front");
            materialList.addMaterial(_material1, "back");
            materialList.addMaterial(_material1, "left");
            materialList.addMaterial(_material1, "right");

            _displayObj = new Cube(materialList, 128, 128, 128, 2, 2, 2);

            _scene.addChild(_displayObj);

            this.addEventListener(Event.ENTER_FRAME, OnEnterFrame);
        }

        private function OnEnterFrame(event:Event):void {
            _displayObj.rotationX += 5;
            _displayObj.rotationY += 5;

            _scene.renderCamera(_camera);
        }

        private function OnObj3DMouseOver(event:InteractiveScene3DEvent):void{
            event.face3d.material = this._material2;
        }

        private function OnObj3DMouseOut(event:InteractiveScene3DEvent):void{
            event.face3d.material = this._material1;
        }
    }
}