Papervision3D入门第5步
呵呵,最近工作比较忙,所以都没怎么动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; } } }