Pv3D-9.排序.doc_第1页
Pv3D-9.排序.doc_第2页
Pv3D-9.排序.doc_第3页
Pv3D-9.排序.doc_第4页
Pv3D-9.排序.doc_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第九章 : Z-sorting (深度排列)简介: 本章主要介绍下面三个方面: a : 什么是Z-sorting(深度排序) b : layering scene renders (分层渲染场景) c : 用四叉树进行复杂的渲染的渲染 注:viewport层 就是ViewportLayer类的实例.它包含在viewport 内Z-sorting的解释 :在前面的章节中你一定碰到过Z-sorting(深度排序)的问题,你用的3D模型(model)越复杂,如果Z-sorting控制不准确,导致的问题也将会越来越明显 。下面两幅图显示了两个茶壶,它清楚的显示了什么是Z-sorting(深度排序).上面的图显示有一部分平面不可见,喷口后面的平面由于排在茶壶身体所在面的后面(即就是排在后面,我们不可见的一面),因而不可见,这就是利用了Z-sorting 。The painters algorithm (排序算法)Z-sorting(深度排序)方法将决定每个平面在scene里的显示深度,其深度位置是按照scene里的平面(即3D对象的某一面)距camera的距离来决定的 。在排序时判断哪个平面应该在前面是非常耗cpu的(The process of determining which triangle should be in front is CPU intensive.)。默认的,papervision3d 用一种非常快速但不是很精确的算法来为scene里的每个平面排序。该算法就是The painters algorithm ,它的主旨是:远处的物体应在近处的物体之前被显示出来(即先显示远处的物体,再显示近处的物体)该算法的流程如下 :第一:所有在camera视图里的平面(3D对象的某一面)是按照距camera的距离,由远到近进行排序的。第二:所有的平面(3D对象的某一面)是按照已排好的顺序依次显示在scene上 即:最先开始显示最远处的的对象 然后由远及近依次显示各个对象。最近的对象最后显示。上面 最左边的图里的山是离camera最远的,所以它最先显示出来,然后显示中间那张图里的草型区域,最后显示右图里的树林。Sorting triangles 对平面进行排序为了更好的理解和深度排序有关的问题,我们需要更好的理解深度排序,下面是一幅标有注解的图 。注:triangle :平面 。 按照The painters algorithm排序算法,则最先显示的是最远处的平面对象。所以先显示平面B,然后显示平面A 。 下面的两幅图,左边是按由近及远顺序显示的图(图Expected),右边是按照深度排序的方法显示的图(图painters algorithm) 有一个很有效的方法去解决上面显示不明了的问题,即对B平面进行再分 。下图是对平面细分的指导 :上面的平面B被再细分成平面B和平面C 。渲染scene时,将会首先显示平面C然后是平面A, 最后是平面B 。下图是再分后的结果:如果换一个视角,将会导致重新排序,平面显示的顺序依旧是由远到近 ,只是此时各个平面距camera的距离发生了改变。如下图:这时,平面A将会最先显示,然后是B 最后是C 。但是这里将会导致一个Z-sorting问题:即平面A将会和B重叠 。Layering your renders :为了增加3D对象的显示效果,可以增加多个三角形平面(即创建更多的segment),但它不是最好的解决方案。因为当多个三角形平面的顶点(vertex)投影到scene上时,三角形平面越多,投影到scene上的点也越多,因而消耗的cpu也越多 . 更好的解决办法是用viewport(视口) 层,这些viewport(视口)层被嵌套在viewport里(因为viewport可以多方位旋转,因而有多个viewport层)。 这些viewport(视口)层的概念与photoshop和flash里层的概念一样,他们的工作原理一样 ,最上层的总是显示在最前面 。在photoshop里,每层只是放一种元素或者一种混合元素。在Pv3d里也是一样,每层只放一种元素。例如:我们可以将椅子放在某一层,然后将桌子放在另一层。每层的排列顺序可以通过pv3d 里算法实现。为了演示上述方法,我们将重用在第八章介绍过了的animatedMill模型。下面将展示一些Z-sorting(深度排序)的问题 。下面的代码将作为本章的模板。 package import flash.events.Event; import org.papervision3d.core.animation.clip.AnimationClip3D; import org.papervision3d.events.FileLoadEvent; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.materials.special.CompositeMaterial; import org.papervision3d.objects.parsers.DAE; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.BasicView; private class ViewportLayersExample extends BasicView private var mill:DAE; private var floor:Plane; private var rotX:Number = 0.1; private var rotY:Number = 0.1; private var camPitch:Number = 90; private var camYaw:Number = 270; private var easeOut:Number = 0.1; public function ViewportLayersExample() stage.frameRate = 40; init(); private function init():void mill = new DAE(true,null,true); mill.addEventListener(FileLoadEvent.LOAD_COMPLETE, modelLoaded);mill.load(assets/animatedMill.dae); var colorMat:ColorMaterial = new ColorMaterial(0x006600); var wireMat:WireframeMaterial = new WireframeMaterial(); var floorMat:CompositeMaterial = new CompositeMaterial(); floorMat.addMaterial(colorMat); floorMat.addMaterial(wireMat); floorMat.doubleSided = true; floor = new Plane(floorMat,1000,1000,1,1); floor.y = -410; scene.addChild(floor); floor.rotationX = 90; private function modelLoaded(e:FileLoadEvent):void scene.addChild(mill); var animationLeft:AnimationClip3D = new AnimationClip3D (right,0,6); var animationRight:AnimationClip3D = new AnimationClip3D (left,6,12); mill.animation.addClip(animationRight); mill.animation.addClip(animationLeft); mill.play(right); startRendering(); override protected function onRenderTick(e:Event=null):void var xDist:Number = mouseX - stage.stageWidth * 0.5; var yDist:Number = mouseY - stage.stageHeight * 0.5; camPitch += (yDist * rotX) - camPitch + 90) * easeOut; camYaw += (xDist * rotY) - camYaw + 270) * easeOut; camera.orbit(camPitch, camYaw); super.onRenderTick(); 在init()方法里,我们加载了外部模型,并把它添加到了scene里。为地板floor对象添加了由WireframeMaterial和ColorMaterial组成的混合材质(floorMat)。最后onRenderTick(e:Event=null)方法里的几段代码是创建鼠标的交互性。移动鼠标,Camera将会绕scene原点进行旋转 ,因而我们就能看到多个方位 。测试代码,将会是下面这样的画面 ,下面的地板floor有一些Z-sorting(深度排序)问题。因为从底部看,模型mill在floor的后面,我们看不到mill模型 。为了能让我们在floor后面看到mill模型,下面我们用层的概念分析一下该问题 :为了解决该问题,我们在此提出上面讲述了很多的层问题。 用层的方法可以解决mill模型不可见的问题 。 因为从底部看,模型mill在floor的后面,即floor在最上层,而mill模型在floor的下一层,因而我们看不到mill模型。 为了使mill模型在从底部看可见,我们只需改变floor和mill模型 层的顺序的即可 。下面有一些改变层顺序的方法:用useOwnContainer属性创建一个viewport层设置3D对象的useOwnContainer为true(3dDisplayObject. useOwnContainer=true;),将会创建一个新的层,该层在所有层的上面(即该层在最上面)。并且该3d对象被画在了该层上。因而该3d对象将不会被遮住。在上面的代码中为了使我们从底部看mill模型可见,只需在modelLoaded()方法里加上下面一句代码:mill.useOwnContainer = true;加上上句代码后再次测试,发现现在的效果更好,图片如下:换多个方位看,我们会发现不存在Z-sorting问题了。其图片显示如下:右图是从较低的点的视口看的(即看它的底部)。把useOwnContainer设为true后,mill模型始终在最上层,因而我们始终能看到mill模型。但这是不符合真实的,并且该属性很耗cpu。下面我们将介绍另外两种方法来代替useOwnContainer方法。下面的两种方法更符合现实。用getChildLayer方法创建viewport层并给viewport层排序通过viewport3D类的getChildLayer方法得到ViewportLayer的实例。var millLayer:ViewportLayer = viewport.getChildLayer(mill);为了使它运行,我们还需要导入ViewportLayer类:import org.papervision3d.view.layer.ViewportLayer;getChildLayer()的三个参数: 参数数据类型 默认值 用法描述do3d DisplayObject3D 获得的do3d的所在层或者为do3d创建一个新的层(创建新的层需要第二个参数)createNew Boolean true是否为do3d创建一个新的viewport层(该值一般设为true,这样才能创建一个新的层,因为新层在所有层的最上面)Recurse Boolean true 是否将do3d里的子对象也 添加到该层当你得到新的viewport层的实例,你也可以将其他的3D对象添加到同一个层中。例如我们可以将大量mill模型添加到同一层. 作为用法演示: 我们在先前的代码的基础上 ,将floor添加到millLayer 层里 。当然这是没有意义的,这和不用层得到的效果是一样的。因为添加floor以后,floor就又在最上面了。我们在这里只是介绍用法:millLayer.addDisplayObject3D(floor);实例化ViewportLayer来创建 viewport 层下面是用法 :var millLayer:ViewportLayer = new ViewportLayer(viewport,null);viewport.containerSprite.addLayer(millLayer);millLayer.addDisplayObject3D(mill,true);ViewportLayer类的构造函数的三个参数 : 参数数据类型默认值用法描述Viewport Viewport3DViewport3D实例对象do3d DisplayObject3D 被添加进层的3d对象在getChildLayer() 方法里可以设置Recurse为true,将3d对象的子对象全部添加到层中。但是在ViewportLayer构造函数中并没有Recurse这个参数,因此在上面的代码中将do3d属性设为null,然后用addDisplayObject3D() 方法将do3d对象添加到层,addDisplayObject3D()方法的第二参数为Recurse ,故可以在这里进行设置isDynamicBooleanfalse是否要去除层在接下来的渲染。这个参数时pv3d内部决定的,不能在外部修改,只能在源码处进行修改addDisplayObject3D()的一个参数为do3d 第二个为Recurse 。Sorting layers前面的例子展示了使用viewport 层来解决Z-sorting(深度排序)问题,但是增加多个层也会带来处理层的问题。Papervision3D有三个内置的模式(mode)去处理这个问题 。用到的是sortMode属性 。用法如下:viewport.containerSprite.sortMode = ViewportLayerSortMode.Z_SORT;Papervision3D支持viewport层的3种排序算法 是ViewportLayerSortMode类三个静态常量属性ViewportLayerSortMode.Z_SORTViewportLayerSortMode.ORIGIN_SORTViewportLayerSortMode.INDEX_SORT在使用上面的3个mode时, 必须导入类:import org.papervision3d.view.layer.util.ViewportLayerSortMode;用ViewportLayerSortMode.Z_SORT给viewport 层排序 :默认的,这些viewport 层是按照Z-sorting深度排序的算法进行排序的.他们排序的方式是基于层上的每个点(vertices)的Z坐标距camera的平均值来决定(即层内所有的点在Z轴上距camera的距离/点的总数)。因而距camera最远的层将会最先显示在scene在舞台上,然后是较远的显示。目前,我们只为mill模型创建了一个层,但我们要用层给mill模型和floor进行排序时。我们需要将floor也添加到viewport层中(一个新的viewport层)var millLayer:ViewportLayer = viewport.getChildLayer(mill);var floorLayer:ViewportLayer = viewport.getChildLayer(floor);上面的代码创建了两个新层。当你测试,从顶部和从底部看你的3D模型和floor会发现不存在Z-sorting(深度排序)问题。但是,把camera 放在floor的上面一点点,会发现又出现了Z-sorting(深度排序问题),这时会发现整个floor对象显示在mill模型前面而不是单一的一个平面。为此,我们可以强制为某个viewport 层设置深度(即距camera的距离),如果设置floor距camera的距离为2000,因而达到为floor排序的目的 。下面是用法:floorLayer.forceDepth = true;floorLayer.screenDepth = 2000; 用上述方法可以达到为viewport重新排序的目的 (即强制设置他们的深度)。用 ViewportLayerSortMode.ORIGIN_SORT给层排序第二种算法是基于每个三D对象的原点进行的:当用默认的z-sorting(即:ViewportLayerSortMode.Z_SORT)排序无法满足精确的要求时。例如有一个模型,在某一面上有多个点(vertices),而在其他面上的点却很少。当按上述方法对它的深度(即距camera的距离)取平均值显然是不精确的 ,这将会导致失去平衡。为了解决这种情况,我们使用ViewportLayerSortMode.ORIGIN_SORT 排序,它是按照3D对象的原点进行排序的。当一个层中包含很多3D对象时,他们的原点将会取平均值 。用ViewportLayerSortMode.INDEX_SORT给viewport 层(ViewportLayer)排序这种算法是基于层的layerIndex属性来实现的。我们可以控制设定它:var millLayer:ViewportLayer = viewport.getChildLayer(mill);var floorLayer:ViewportLayer = viewport.getChildLayer(floor);millLayer.layerIndex = 1;floorLayer.layerIndex = 2;viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;我们这样设置millLayer.layerIndex = 1; floorLayer.layerIndex = 2; ,将会导致scene里先创建millLayer(即离camera较远) 然后再创建floorLayer层(即离camera较近),由于floorLayer层较后创建,因而floorLayer层在的最上面。尽管这样做对floorLayer层意义不大,但是我们是借此来介绍怎样使用layerIndex 属性 。目前我们已经有了几种可供选择的方法来给viewport层(ViewportLayer)进行排序。但是这些方法在我们的demo(即演示例子)里的使用都不能达到正确的效果。一个可供选择的方法是将它设为只有一面可见 即:matrial.oneSide=true; 但是对于这个demo,这并不是我们想要的。当cameral在floor的上表面和下表面时,我们需要正确(即符合实际)的观察floor和mill模型如果我们用ViewportLayerSortMode.INDEX_SORT给层排序,当cameral在floor的上表面和者下表面之间进行变动时,使用layerIndex属性来交换viewport层(ViewportLayer)的深度 将会产生怎么的结果呢?在 onRenderTick()方法里来设定这些属性/注意:下面的代码是demo的代码的基础上进行的/下面的代码是放在onRenderTick()里面的if(camera.y-410) viewport.getChildLayer(mill).layerIndex = 1; viewport.getChildLayer(floor).layerIndex = 2;else viewport.getChildLayer(mill).layerIndex = 2; viewport.getChildLayer(floor).layerIndex = 1;为了使layerIndex属性正常运行我们还需要这样设置:viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;这行代码放在modelLoaded()方法里上述方法成功解决了demo里存在的问题但这个方法并不是在每个工程中都适用 。Creating and sorting sublayers不仅viewport支持viewport层(ViewportLayer),viewport 层他们自己也可以嵌套层(即层中再包含层),因而我们可以在同一个scene里使用多种排序方法。下面我们按照图示写出相关代码:/Create viewport layer 1 structurevar viewportLayer1:ViewportLayer = new ViewportLayer(viewport,null);var viewportLayer1_1:ViewportLayer = new ViewportLayer(viewport, chair);var viewportLayer1_2:ViewportLayer = new ViewportLayer(viewport, table);viewportLayer1.addLayer(viewportLayer1_1);viewportLayer1.addLayer(viewportLayer1_2);viewportLayer1.sortMode = ViewportLayerSortMode.INDEX_SORT;/Create a regular viewport layer 2var viewportLayer2:ViewportLayer = new ViewportLayer(viewport,floor);/Create viewport layer 3 structurevar viewportLayer3:ViewportLayer = new ViewportLayer(viewport,null);var viewportLayer3_1:ViewportLayer = new ViewportLayer(viewport,wall);var viewportLayer3_2:ViewportLayer = new ViewportLayer(viewport,door);viewportLayer3.addLayer(viewportLayer3_1);viewportLayer3.addLayer(viewportLayer3_2);viewportLayer3.sortMode = ViewportLayerSortMode.ORIGIN_SORT; /Add parent layers to the viewportviewport.containerSprite.addLayer(viewportLayer1);viewport.containerSprite.addLayer(viewportLayer2);viewport.containerSprite.addLayer(viewportLayer3);viewport.containerSprite.sortMode = ViewportLayerSortMode.Z_SORT;从上面的代码中可以看出嵌套的层在处理深度排序时 和在viewport里一样 。四叉树渲染引擎(Quadtree rendering)四叉树渲染引擎(Quadtree rendering)可以代替我们现在默认使用的的BasicRenderEngine 引擎。我们对四叉树渲染引擎(Quadtree rendering)的算法不会深入讲解。 我们只需要知道它可以解决大部分的深度排序(Z-sorting)问题。但是四叉树渲染引擎(Quadtree rendering)非常耗CPU。尽管这样,由于它的使用非常简单,下面我们来使用它:首先我们要新建一个工程,该工程是在ViewportLayersExample文档类(本章前面的模板,第一个代码) 的基础上建立起来。在该类的基础上,我们需要导入四叉树渲染引擎(Quadtree rendering)的包,import org.papervision3d.render.QuadrantRenderEngine;然后在init()方法里加上下面的代码:renderer = new QuadrantRenderEngine();上面的代码代替了我们默认的BasicRenderEngine引擎。BasicRenderEngine引擎是在我们继承BasicView类时自动创建的。实例化QuadrantRenderEngine只需要一个参数 该参数指定你要选择哪种排序的方法。这些方法是QuadrantRenderEngine类的静态常量。QuadrantRenderEngine.CORRECT_Z_FILTER: :为不交叉的平面进行正确的排序。QuadrantRenderEngine.QUAD_SPLIT_FILTER: 为交叉的平面进行排序,引擎将会自动的分割交叉的平面,然后进行正确的排序。QuadrantRenderEngine.ALL_FILTERS:这个是上面两种类型的组合。它是默认值(即不传参数时默认是它)当我们测试代码,会发现出现的情况不令人满意。原因是我们用的模型是由少量的平面组成,这就限制了四叉树渲染引擎(Quadtree rendering)的正常发挥。该问题得原因是因为每一个平面都被四叉树渲染引擎(Quadtree rendering)渲染了,但是并不是每个平面都需要用四叉树渲染引擎(Quadtree rendering)进行渲染,我们可以不让3D对象不被四叉树渲染引擎(Quadtree rendering)进行渲染,因而该3D对象将会被默认的BasicRenderEngine引擎进行渲染。 我们可以用设置3D对象的testQuad属性为false来实现。我们例子的问题在于floor的深度排序问题。因而我们可以用四叉树渲染引擎(Qua

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论