Pv3D9排序.docx

上传人:b****6 文档编号:6630235 上传时间:2023-01-08 格式:DOCX 页数:16 大小:203.33KB
下载 相关 举报
Pv3D9排序.docx_第1页
第1页 / 共16页
Pv3D9排序.docx_第2页
第2页 / 共16页
Pv3D9排序.docx_第3页
第3页 / 共16页
Pv3D9排序.docx_第4页
第4页 / 共16页
Pv3D9排序.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

Pv3D9排序.docx

《Pv3D9排序.docx》由会员分享,可在线阅读,更多相关《Pv3D9排序.docx(16页珍藏版)》请在冰豆网上搜索。

Pv3D9排序.docx

Pv3D9排序

 

第九章:

Z-sorting(深度排列)

简介:

本章主要介绍下面三个方面:

a:

什么是Z-sorting(深度排序)

b:

layeringscenerenders(分层渲染场景)

c:

用四叉树进行复杂的渲染的渲染

注:

viewport层就是ViewportLayer类的实例.它包含在viewport内

Z-sorting的解释:

在前面的章节中你一定碰到过Z-sorting(深度排序)的问题,你用的3D模型(model)越复杂,如果Z-sorting控制不准确,导致的问题也将会越来越明显。

下面两幅图显示了两个茶壶,它清楚的显示了什么是Z-sorting(深度排序).

上面的图显示有一部分平面不可见,喷口后面的平面由于排在茶壶身体所在面的后面(即就是排在后面,我们不可见的一面),因而不可见,这就是利用了Z-sorting。

Thepainter'salgorithm(排序算法)

Z-sorting(深度排序)方法将决定每个平面在scene里的显示深度,其深度位置是按照scene里的平面(即3D对象的某一面)距camera的距离来决定的。

在排序时判断哪个平面应该在前面是非常耗cpu的(TheprocessofdeterminingwhichtriangleshouldbeinfrontisCPUintensive.)。

默认的,papervision3d用一种非常快速但不是很精确的算法来为scene里的每个平面排序。

该算法就是Thepainter'salgorithm,它的主旨是:

远处的物体应在近处的物体之前被显示出来(即先显示远处的物体,再显示近处的物体)

该算法的流程如下:

第一:

所有在camera视图里的平面(3D对象的某一面)是按照距camera的距离,由远到近进行排序的。

第二:

所有的平面(3D对象的某一面)是按照已排好的顺序依次显示在scene上

 

即:

最先开始显示最远处的的对象然后由远及近依次显示各个对象。

最近的对象最后显示。

上面最左边的图里的山是离camera最远的,所以它最先显示出来,然后显示中间那张图里的草型区域,最后显示右图里的树林。

Sortingtriangles——对平面进行排序

为了更好的理解和深度排序有关的问题,我们需要更好的理解深度排序,下面是一幅标有注解的图。

注:

triangle:

平面。

按照Thepainter'salgorithm排序算法,则最先显示的是最远处的平面对象。

所以先显示平面B,然后显示平面A。

下面的两幅图,左边是按由近及远顺序显示的图(图Expected),右边是按照深度排序的方法显示的图(图painter'salgorithm)

 

有一个很有效的方法去解决上面显示不明了的问题,即对B平面进行再分。

 

下图是对平面细分的指导:

上面的平面B被再细分成平面B和平面C。

渲染scene时,将会首先显示平面C然后是平面A,最后是平面B。

下图是再分后的结果:

 

如果换一个视角,将会导致重新排序,平面显示的顺序依旧是由远到近,只是此时各个平面距camera的距离发生了改变。

如下图:

这时,平面A将会最先显示,然后是B最后是C。

但是这里将会导致一个Z-sorting问题:

即平面A将会和B重叠。

 

Layeringyourrenders:

为了增加3D对象的显示效果,可以增加多个三角形平面(即创建更多的segment),但它不是最好的解决方案。

因为当多个三角形平面的顶点(vertex)投影到scene上时,三角形平面越多,投影到scene上的点也越多,因而消耗的cpu也越多.更好的解决办法是用viewport(视口)层,这些viewport(视口)层被嵌套在viewport里(因为viewport可以多方位旋转,因而有多个viewport层)。

这些viewport(视口)层的概念与photoshop和flash里层的概念一样,他们的工作原理一样,最上层的总是显示在最前面。

在photoshop里,每层只是放一种元素或者一种混合元素。

在Pv3d里也是一样,每层只放一种元素。

例如:

我们可以将椅子放在某一层,然后将桌子放在另一层。

每层的排列顺序可以通过pv3d

里算法实现。

<该段主要是讲pv3d层的概念:

每个层只能放一种元素,该元素既可以是单一的,也可以是混合的>

为了演示上述方法,我们将重用在第八章介绍过了的animatedMill模型。

下面将展示一些Z-sorting(深度排序)的问题。

下面的代码将作为本章的模板。

 

package{

importflash.events.Event;

importorg.papervision3d.core.animation.clip.AnimationClip3D;

importorg.papervision3d.events.FileLoadEvent;

importorg.papervision3d.materials.ColorMaterial;

importorg.papervision3d.materials.WireframeMaterial;

importorg.papervision3d.materials.special.CompositeMaterial;

importorg.papervision3d.objects.parsers.DAE;

importorg.papervision3d.objects.primitives.Plane;

importorg.papervision3d.view.BasicView;

privateclassViewportLayersExampleextendsBasicView

{

privatevarmill:

DAE;

privatevarfloor:

Plane;

privatevarrotX:

Number=0.1;

privatevarrotY:

Number=0.1;

privatevarcamPitch:

Number=90;

privatevarcamYaw:

Number=270;

privatevareaseOut:

Number=0.1;

publicfunctionViewportLayersExample()

{

stage.frameRate=40;

init();

}

privatefunctioninit():

void

{

mill=newDAE(true,null,true);

mill.addEventListener(FileLoadEvent.LOAD_COMPLETE,modelLoaded);

mill.load("assets/animatedMill.dae");

varcolorMat:

ColorMaterial=newColorMaterial(0x006600);

varwireMat:

WireframeMaterial=newWireframeMaterial();

varfloorMat:

CompositeMaterial=newCompositeMaterial();

floorMat.addMaterial(colorMat);

floorMat.addMaterial(wireMat);

floorMat.doubleSided=true;

floor=newPlane(floorMat,1000,1000,1,1);

floor.y=-410;

scene.addChild(floor);

floor.rotationX=90;

}

privatefunctionmodelLoaded(e:

FileLoadEvent):

void

{

scene.addChild(mill);

varanimationLeft:

AnimationClip3D=newAnimationClip3D("right",0,6);

varanimationRight:

AnimationClip3D=newAnimationClip3D("left",6,12);

mill.animation.addClip(animationRight);

mill.animation.addClip(animationLeft);

mill.play("right");

startRendering();

}

overrideprotectedfunctiononRenderTick(e:

Event=null):

void

{

varxDist:

Number=mouseX-stage.stageWidth*0.5;

varyDist:

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的实例。

varmillLayer:

ViewportLayer=viewport.getChildLayer(mill);

为了使它运行,我们还需要导入ViewportLayer类:

importorg.papervision3d.view.layer.ViewportLayer;

getChildLayer()的三个参数:

参数数据类型默认值用法描述

do3dDisplayObject3D————获得的do3d的所在层

或者为do3d创建一个新的

层(创建新的层需要第二个参数)

createNewBooleantrue是否为do3d创建一个新的

viewport层(该值一般设

为true,这样才能创建

一个新的层,因为新层

在所有层的最上面)

RecurseBooleantrue是否将do3d里的子对象也

添加到该层

当你得到新的viewport层的实例,你也可以将其他的3D对象添加到同一个层中。

例如我们可以将大量mill模型添加到同一层.作为用法演示:

我们在先前的代码的基础上,将floor添加到millLayer层里。

当然这是没有意义的,这和不用层得到的效果是一样的。

因为添加floor以后,floor就又在最上面了。

我们在这里只是介绍用法:

millLayer.addDisplayObject3D(floor);

 

实例化ViewportLayer来创建viewport层

下面是用法:

varmillLayer:

ViewportLayer=newViewportLayer(viewport,null);

viewport.containerSprite.addLayer(millLayer);

millLayer.addDisplayObject3D(mill,true);

 

ViewportLayer类的构造函数的三个参数:

参数数据类型默认值用法描述

ViewportViewport3D————Viewport3D实例对象

do3dDisplayObject3D————被添加进层的3d对象

在getChildLayer()

方法里可以设置Recurse为

true,将3d对象的子对象全部添加到层中。

但是在

ViewportLayer构造函数中并没有Recurse这个参数,因此

在上面的代码中将do3d属性设为null,然后用addDisplayObject3D()方法将do3d对象添加到层,

addDisplayObject3D()方法的第二参数为Recurse,故可以在这里进行设置

isDynamicBooleanfalse是否要去除层在接

下来的渲染。

这个参数时pv3d内部决定的,不能在外部修改,只能在源码处进行修改

addDisplayObject3D()的一个参数为do3d第二个为Recurse。

 

Sortinglayers

前面的例子展示了使用viewport层来解决Z-sorting(深度排序)问题,但是增加多个层也会带来处理层的问题。

Papervision3D有三个内置的模式(mode)去处理这个问题。

用到的是

sortMode属性。

用法如下:

viewport.containerSprite.sortMode=ViewportLayerSortMode.Z_SORT;

Papervision3D支持viewport层的3种排序算法是ViewportLayerSortMode类三个静态常量属性

ViewportLayerSortMode.Z_SORT

ViewportLayerSortMode.ORIGIN_SORT

ViewportLayerSortMode.INDEX_SORT

在使用上面的3个mode时,必须导入类:

importorg.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层)

varmillLayer:

ViewportLayer=viewport.getChildLayer(mill);

varfloorLayer:

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属性来实现的。

我们可以控制设定它:

varmillLayer:

ViewportLayer=viewport.getChildLayer(mill);

varfloorLayer:

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里存在的问题但这个方法并不是在每个工程中都适用。

Creatingandsortingsublayers

不仅viewport支持viewport层(ViewportLayer),viewport层他们自己也可以嵌套层(即层中再包含层),因而我们可以在同一个scene里使用多种排序方法。

下面我们按照图示写出相关代码:

 

//Createviewportlayer1structure

varviewportLayer1:

ViewportLayer=newViewportLayer(viewport,null);

varviewportLayer1_1:

ViewportLayer=newViewportLayer(viewport,chair);

varviewportLayer1_2:

ViewportLayer=newViewportLayer(viewport,table);

viewportLayer1.addLayer(viewportLayer1_1);

viewportLayer1.addLayer(viewportLayer1_2);

viewport

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 可爱清新

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1