PV3d性能优化

当你优化你的程序时,要考虑到许多因素。性能的优化并不仅仅与你使用 Papervision3D 的方式
相关。最后所说的是关于如何在 Flash 中进行性能的优化。让我们先测试一些并不只与
Papervision3D 有关的优化技巧。
舞台品质
将 stage quality 调低是得到性能的最容易的方式。降低 stage quality 并不意味你降低了
屏幕的质量。首先,先来看看你可以设置的品质设置选项:
图像是反锯齿的,使用了 4 乘 4 像素栅格,可以使 bitmap 很平滑。
图像是反锯齿的,使用了 4 乘 4 像素栅格,如果 movie 是静态的,
可以使 bitmap 很平滑。一般地,stage 的品质都设置成这个值。
图像是反锯齿的,使用了 2 乘 2 像素栅格,这不会使 bitmap
平滑并对文本阅读有点影响,对动画会有一点优化。
图像不是反锯齿的,bitmap 也不平滑。对文本的显示和动画的优化
有很大的影响。
Chapter 13
[ 383 ]
stage.quality = StageQuality.LOW;
var bmpData:BitmapData = new BitmapData(button.width,button.height);
bmpData.draw(button);
var bmpButton:Bitmap = new Bitmap(bmpData);
bmpButton.x = button.x;
bmpButton.y = button.y;
addChild(bmpButton);
removeChild(button);
将所有东西设低会影响你程序的图像显示。特别是并未优化的文本会更难读,这是需要被
考虑的也是可以优化的。开发的时候最低也要将 stage 设成中等品质,只有在必需的时候
才将 stage 的品质设成低品质。
当 scene 有一个静态视图时应使用中等品质甚至高品质,在包含动画时再将 stage 设成
低品质。当动画在播放时,文本的品质也很难看清,所以可以把品质设低。
另外一个技巧是根据用户电脑在播放 movie 时可以达到的帧速来设置 stage 的品质。如果
帧速下降到某个值时,你的程序可以侦测到这种情况并将 stage 的品质设置成中等或者低
品质。于是,使用配置更快的电脑可以看到最好的图形效果并且程序表现得更好;使用配置
稍慢的电脑也可以通过合理的帧看到不错的图形效果。
为了可以改变 stage 的 quality,你需要导入 StageQuality 类,这样你就可以使用该类
定义 quality 的静态常量。该类可以在 flash.display.StageQuality 找到。通过改变
stage 的 quality 属性,你可以在任何时候改变 quality:
当改变 stage 的 quality 时可能发生的一个问题是:它改变文本的 quality 但并不能使
文本的可读性提高而且也不是 Papervision3D 渲染器的一部分。例如,使用 2D 接口的按钮
的 label 属性。这样情况下你可以创建产生该问题元素的截屏并用该截屏来代替。以下代码
展示了如何创建一个虚构的按钮:
你可以试试将前面的例子设置 stage 的 quality。例如,将 animated mill 的 quality 设置
成中等并看看帧速是如何增加的,它肯定提高了性能。
Optimizing Performance
[] 384
scene.removeChild(do3d);
do3d.material.destroy();
do3d = null;
其它普通的Flash优化
通常情况下,你都应该尝试写优化的代码。在你不需要 event 监听器时,将它移除。不要
创建太多的 enter frame event 或者 timer 的监听器。尽量不要在一个循环里面声明变量。
这样你的程序会表现得更好,Papervision3D 程序也一样。
通常你在使用 Flex Builder 或者 Flash Builder 开发的时候,发布的都是 debug 版本。
发布的时候最好发布成 release 版本,因为它的性能会更好。
删除不需要的对象
作为简洁编程的一部分,你应该将不再需要的对象删除。这样,垃圾回收器在运行它的周期时
会将那些对象在内存中删除。
因为 Papervision3D 使用了大量的 bitmap data 对象,所以在你不再需要那些对象时应将
它们删除。当你不再需要 scene 中子对象时,应将它删除并且将它的引用和 material 删除。
一旦你需要从内在中删除某个对象时,你需要执行以下 3 行代码:
第一行的作用是将该对象从 scene 中删除。第二行将该对象的所有 material 引用都删除。
第三行将该对象的引用设为 null。还需要注意将其它对该对象的引用也要删除。只有将所有
的引用删除,内存才会被清空。
Viewport 大小
你的 viewport 的大小越大,scene 显示的也越多,渲染的也越多。应尽量将需要渲染的总像素
的数量控制得更低,这样性能会更好。虽然那些使用最大可用屏幕的程序会更好看,但你的
Papervision3D 程序使用这种方式来运行的话并不总是一种好主意。在设置 viewport 的大小时
应根据你的需要和 Papervison3D 的限制。
Chapter 13
[] 385
camera.useCulling = true;
镜头视域
镜头(camera)可以看到 scene 中所发生的一切。在同一时间它所看的越多,Flash 播放器
的工作量就越大。因此,你可以将镜头微调一下使它在同一时间看到的物体少一些。如果你
的项目需要尽可能的优化的话,你可以通过使用 camera 的 fov,zom 和 focus 属性来调低
视图。因为这个技巧对需要被渲染三角形的数量影响并不大,所以对性能的影响可能也是比较
小的。如果你将上面的属性设得比较极端的话,虽然优化了性能,但渲染的结果也会不如你意的。
剔除
在关于 camera 的第五章,我们学习了什么是剔除以及它的用法。剔除就是:确认哪些物体在
(或者部分在) camera 的视域里面并且放弃那些不在里面物体的过程。剔除是性能优化的一种,
你可以设置 camera 的属性,如下所示:
将 useCulling 设为 true,所有在视域外的物体都会被忽略,这会节省性能。
创意的想法
性能的优化需要一种有创意的方式。每个程序都是不相同的,它可能还需要这一章中并未提到
的优化方式。你可以试试你自己的想法并看看是否起作用。
在虚拟 3D 中,优化是很常见的。在一个项目的开始,你可以问下自己哪些东西可以是虚拟的,
例如-使用 billboard particle。
优化 material
如果 material 不是以最佳的方式使用的话,可能导致 Papervision3D 使用很多时间来渲染
它们。在关于 material 的第四章,你已经学习了怎样使它们尽可能的轻量的技术。在本部分
里,我们会逐个讨论这些技术并介绍更多优化策略。
Optimizing Performance
[ 386 ]
BitmapMaterial.AUTO_MIP_MAPPING = true;
透明度
MovieMaterial 的实例或者继承了 MovieMaterial 的类可以设置透明度。默认情况下,
movie material 的透明度是关闭的。你最好保持这个设置不变。带透明度的图片是 32
位的而没有透明度的图片是 24 位的。没有透明度的图片渲染得更快。
永远试着把一个 material 的 tiled 属性设成 true。根据你的情况这会轻微地提高了
性能(这是 Flash 播放器存在的一性能的 bug)。
双纹理的作用
双纹理的作用是用来 mipmapping(映射),它允许你将 material 的 smoothing 设为 true
而又不丢失性能。关于 material 的第四章大量阐述了它是如何工作的。
某些情况下为了得到 mipmapping 的好处,你不可以使用 two dimensions,你可以将
BitmapMaterial 的属性 AUTO_MIP_MAPPING 设为 true。
当你设为这样的时候,Papervision3D 会更正所有新建的 bitmap material。缺点就是它会
比把这个属性设为 false 的时候要用更多一点内存。
material 的大小
在 modeling 那一章,你已经学习了你应该将 material 的宽和高尽量做小。例如,当你有
一个车的 model 时,你想把轮子纹理化,聪明是做法是把纹理做得越小越好。因为轮子不可
能以全屏出现,所以使用 1024 乘 1024 的纹理是不合理的。应该使用双纹理来代替,如 64
乘 64 像素的图片。
Tiled
动画化的 material
animated material 是 Flash 播放器比较难处理的一种 material。每次我们在渲染一个使用了
animated material 的对象时候,播放器会创建 movie clip 的一个当前状态的屏幕快照。该屏幕
快照会被用作一个一般的 bitmap material,然后被转换成 3D 视图并被画到屏幕上。
Andy Zupko 在他的博客中介绍了一种会将每一帧储存在内存中 material 类型,并提供
Chapter 13
[ 387 ]



创建这个屏幕快照是很耗 CPU 的,所以当该 material 要动画化时应该将 animated 属性
设为 true。当你不再需要该动画时,将它设为 false。默认情况下,所有继承了 MovieMaterial
的 material 都设成 false,MovieMaterial 包含了一个 VideoStreamMaterial 的异常,
很明显这些 material 需要被动画化。
因为 material 上的动画是很耗 CPU 的,你应该尽量少用带有同步动画的 material。
要想在使用动画化的 material 时获得性能,你可以将动画的每一帧作为一个屏幕快照保存
在内存里。每次动画到达一个帧(该帧之前已经显示过)时,只需从内存读取缓存的屏幕快照,
而不是重新创建该帧的屏幕快照。
很不幸的是, Papervision3D 并没有实现该功能。但是,Papervision3D 核心组的组员
这个类的下载。你可以在这个网页了解:http://blog.zupko.info/?p=248。
当你使用该缓存机制时,你还应该考虑以下事情:
因为所有屏幕快照是作为 bitmap data 储存在内存的,这会使用相当一部分的内存的。
你用得越多帧或者 movie clip 的解析度越高的话,用的内存也越多。
这只会对静态 movie clip 起作用,也就是多次播放该动画时起作用。
因为每个帧是储存为 bitmap data 的,所以 material 是没有交互性的。
在同一时间使用多个动画化的 material时,将帧缓存起来对性能有很大的提高。
优化 object
你的 object 越复杂,越多的三角形需要被画出来。之前已经说过,你应该尽量把三角形
保持得越少。当使用外部工具建模时,最好先建立一个比较简单的多边形模型,然后根据
需要添加更多的多边形或者三角形。反向操作时也一样,从一个复杂的模型中删除三角形时
会需要做更多工作。
Optimizing Performance
[ 388 ]
优化 object 还有更多的技巧。在以下的章节中会有介绍。
将在 object 背后的其它 object 删除
听起来所容易:只需将不可见的 object 删除掉。这些 object 并不是指那些位于 camera
视域外的 object 或者在 3D object 背面的那些,因为 Papervision3D 会自动帮我们检测
这些。我们所说的 object 是指位于视域内的,但从某个视角来看它们是位于其它 object
后面的 object。
因为 Papervision3D 默认使用了 painter 的算法,它描画 object 时是从最远到最近的。
所以,当一个 object 在另一个 object 的前面,它们都会被画到屏幕的。当一个 object
完全掩盖它后面的另一个 object 时,将它们都描画出来将是一种浪费。
我们来想象一下这样一种情形,你建立一个由两个房间(一个卧室,一个冲凉房) 组成的
3D 环境。两个房间由一块墙隔开,你可以自由行走。当你点击门时,你进入另一个房间。
现在你面对着门的那个方向,墙后面是冲凉房。根据 painter 的算法,首先画的是冲凉房,
然后是阻止你看见冲凉房的那一块墙。但是我们都看不到冲凉房,何必把它画出来呢。所以
将冲凉房从 scene 中移除掉会省掉很多的性能。
你可能会想,这不是 far plane 可以做到的吗?far plane 可以使你减少渲染那些太远而
不能被看见的 object,但在这个例子中它仍然会渲染你所面向的那个冲凉房。当 camera
接近门的时候,far plane 就不会起作用了。
当你知道你不能看见那些位于某些 object 后面的 object 时,将它们删除是很节省性能的,
特别是当它们包含很多三角形的时候。
在这方面需要做很多工作。在你计划你的项目时,而且你知道 Papervision3D 可以做到什么,
将那些隐藏的 object 删除掉是一种不错的考虑。
Chapter 13
[ 389 ]
private var slod:SimpleLevelOfDetail;
private function init():void
{
var stats:StatsView = new StatsView(renderer);
addChild(stats);
var mat:WireframeMaterial = new WireframeMaterial
(Math.random()*0xFFFFFF);
var sphere1:Sphere = new Sphere(mat,200,12,12);
var sphere2:Sphere = new Sphere(mat,200,6,6);
var sphere3:Sphere = new Sphere(mat,200,3,3);
var spheres:Array = [sphere1,sphere2,sphere3];
slod = new SimpleLevelOfDetail(spheres,600,2000);
scene.addChild(slod);
}
override protected function onRenderTick(e:Event=null):void
{
slod.z += 5;
super.onRenderTick();
}
Level of detail(细节的级别)
Level of detail(也即是 LOD)是关于:基于 3D object 与 camera 的距离来减少它们的
复杂性。假设你有一个离 camera 很近的 do3。该 do3D 在屏幕上显得很大,你可以看清所有
detail(细节)。然而,在这个 object 被放置在背景的某个地方时,它不需要被看清所有
细节。这是就可以用到 LOD,它可以根据离 camera 的距离来显示一个 object 的三角形数量
的多或少。如果我们想它做得更好,应该在模型中加入更多的三角形,那样,你的 do3D 从
一个样式转换到另一个时就不会有太大的变化。这会轻微地改变了 do3D 的样子。
Papervision3D 内建了对 LOD 的支持,但它不支持 do3D 之间的窜改。这个没有窜改功能的
技术叫做 simple level of detail(细节的简单级别),或者是 SLOD。
提供内建 SLOD 支持的类叫做 SimpleLevelOfDetail,它可以从
org.papervison3d.objects.special.SimpleLevelOfDetail 包导入。
下面是它的用法:
Optimizing Performance
[ 390 ]
Parameter Data type Default
value
Description
1 object Array —
2 minDepth Number 1000
3 maxDepth Number 10000
4 distances Array null
首先,我们实例化三个球形然后把它们放到一个数组里面。该数组作为 SimpleLevelOfDetail
类的第一个参数。你根据 object 的 detail 的不同程度添加到数组,从最近而且有最多
detail 的 object 开始,结束于最远而且最简单的 object。
实例化 SimpleLevelOfDetail 类需要 4 个参数:
一个包含 3D object 的数组。数组的第一个
元素代表最近而且拥有最多 detail 的,最后
的元素是最远而且最简单的 3D object。
定义最近而且最多 detail 的 object 应该
使用的距离。
定义最远而且最少 detail 的 object 应该
使用的距离。
一个用来定义 object 数组中每个 object
深度值的一个 integer 数组。默认设为 null。
如果提供了该数组,它会替换 minDepth 和
maxDepth 参数。
一旦 SimpleLevelOfDetail 类实例化后,它会被添加到 scene 中,因为这个类继承了
DisplayObject3D。
在每次 onRenderTick 的调用时,SLOD sphere 会被移到离 camera 稍远的地方,这会显示了
object 是如何变化的。
Chapter 13
[ 391 ]
Distance: 600 Distance: 1200 Distance: 1700
LODExample
发布之后,你可以看到以下次序的图片。
因为一个 StatsView 实例被添加到 stage,你也可以在左上方见到渲染了的三角形减少的数量。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值