天下武功,唯快不破
最近网友问了关于点云、倾斜摄影数据的性能优化问题。本来想刀枪剑戟、斧钺勾叉给弄了,但是后来想性能其实是个系统问题,要在第22节分成数小节扎扎实实的讲一讲。
鸣谢
非常感谢王锐王大神的cookbook,我准备主要参考它里面关于性能的一章。也就是第8章。本节讲述性能优化的最基本的手段:合并几何体。
本节资源
本文集包括本节所有资源包括模型代码都在此下载,按节的序号有文件或文件夹:
注意: 务必使用浏览器打开:
【击此打开网盘资源链接】
使用方法: 注释掉第32行的宏MERGE_GEOMETRY你会得到优化前后的结果
理论知识
OSG最终绘制的都是osg::Geometry,然后Geometry会存放在Node里。比如我们要绘制10条线,那么我们有两种方法,一种方法是定义10个Geometry,每个Geometry定义两个顶点绘制1条线。另一个方法是我们定义1个Geometry,里面放20个顶点,一次性绘制10条线。这两种方法的性能差异很大。
方法一因为定义了10个Geometry,那么CPU端就会做Event、Cull、Update、Draw都会针对10个结点来做,很花性能。GPU也会接受10次来自CPU端的数据,之间通信也会增加,GPU端的绘制工作量也会增加变缓。如下是cookbook8,绘制了300×300=90000个Geometry。每个Geometry只有4个顶点时的数据绘制效率:
我们可以看到帧率只有2.46帧,笔者用的是DEBUG模式。显卡是GTX1650Ti,显存4G。从图中可以看到大量的时间花在了cull和draw上。尤其是cull,因为结点数量多了,哪怕只以视锥体做拣选cull的时间就会很长。
而方法二是只定义1个Geometry,压入了300x300x4=36万个顶点,也是90000个四边形,一个四边形是4个顶点。绘制的结果是一模一样的,但是其性能就会大幅提升:
可以看到,因为只有一个结点,没有什么好拣选的,于是cull的时间大幅缩短。Draw和GPU的时间也均有优化。
总之来说,将多个Geometry合并成一个Geometry几乎是业界普遍认为最简单、最有效、最普遍、最应该使用的优化方法。也就是我们追究求的就是CPU尽量少次多量的向GPU提交数据。
OSG中的合并工具
OSG有个类叫做osgUtil::Optimizer,大家打开后就发现里面有好多的优化都在里面,其中就有:MERGE_GEOMETRY,当我们使用如下语句时,正常的就会将结点的Geometry进行合并:
osgUtil::Optimizer optimizer;
optimizer.optimize(loadedModel.get());
看其内部使用了一个工具类的方法叫做:
MergeGeometryVisitor mgv(this);
mgv.setTargetMaximumNumberOfVertices(10000);
node->accept(mgv);
它的思想也很简单,先把Group给一级一级合,然后多个Geometry合成一样。能合并的PrimitiveSet也者合并。
osgUtil::Optimizer只能进行一些通用的合并。我们理解了思想之后就可以手动的或者自己针对自己的场景写个性化的工具,以免不想合的被合了,想合的合不了。
代码解析
这一节的代码实在是有点简单,没有什么好解析的,可以从网盘上自己下载下来看看就明白了本节所描述的观点了。
暂无评论内容