市级海量数据流畅调度方案(初稿)

一.系统约束

1. 硬件限制 (CPU, 显卡,内存,硬盘)

最耗费CPU时间的是 视锥体和boundSphere/boundBox的求交计算。

显卡现在最大的瓶颈是 当渲染批次多时(2000个primitivesets,20万三角面片),渲染时间(Draw和GPU)都达到了30多毫秒。

测试机型硬件配置(本机):

 

CPU为4核处理器

显卡:  NVIDIA GForce GT 630  1024MB显存

 

硬盘:  500GB

 

2. 软件限制(OpensceneGraph原理限制)

2.1 操作系统OS    

 

2.2 底层OpensceneGraph 3.2.1

目前版本的Osg在windows系统下多线程渲染sharecontext的支持是有问题的,不能实现后台加载线程编译显示列表和纹理对象,只能在渲染线程中编译显示列表和纹理对象加重了渲染的压力。

Osg采用的是场景树管理机制,update,cull,draw三个流程中cull流程由于需要遍历整个场景树生成渲染叶子和状态树,所以耗费的时间与场景树中的节点数量成正比。测试发现当有2000个点状地物时帧速大概是16帧/秒,cull耗时约32ms。4000个点状地物时帧速降到5.5帧/秒,cull耗时66ms,draw耗时80ms,GPU耗时75ms(update时间基本稳定在3-6ms可以忽略不计)。

3.  网上相关资料

 

gpu 池化调度_数据

gpu 池化调度_数据_02

 

gpu 池化调度_数据_03

 

gpu 池化调度_数据库_04

 

gpu 池化调度_数据库_05

 

gpu 池化调度_数据_06

gpu 池化调度_外包_07

 

猜测:

Citymaker在制作城市建筑时是不是做了内部合并输出成一定格式的文件?但是从操作上看似乎它也能选择单个建筑物进行编辑,那么它在高空能看到的建筑物数量应该也是要受限的,否则光是一次渲染遍历一遍的时间就难以让人接受,但从“数字澳门”的软件截图上看,似乎渲染的建筑物数量是很多的? 

难道我们将一定高度(比如5米高度一下的)的建筑物的高程信息合成到地形部分?这样就不用单独渲染建筑物了,顶面和侧面的纹理就用地形纹理就行,地形网格肯定要加密一些,最好用shader辅助,但是这样做建筑物一开始的形状就会比较奇怪(skyline的发布会上倾斜摄影测量构建的上海浦东外滩),不够美观,查询时就需要直接从数据库来查询了。

4. 总结

加快场景渲染速度的方式有以下几种途径。【更新硬件和操作系统不在此考虑】

A. 合并地物以缩短cull的时间。将几个临近的建筑物作为一个地物进行装载和渲染,这样就减少了场景树上的节点数量,从而减少cull的时间?(视锥和外包box的求交计算没有减少呀。)也不能将太多的建筑物合并,否则加载是会出现帧冲击,选择编辑单个对象也会遇到问题,系统的灵活性会降低。这种途径可行性太差。

B. 减少渲染批次缩短渲染时间。 原理:显卡一次渲染10万个三角形和100次各渲染1000个三角形虽然渲染的三角形总数量相同但花费的时间明显是前者要快很多。

减少渲染批次的方法主要是尽量减少单独三角形,三角形条带化或使用三角形索引加速渲染,最终目标是尽可能的将多个primitiveset合并成少量的primitiveset。

C. 集群渲染。单机的渲染能力有限,采用集群的方式,每台渲染服务器只负责渲染很小的一部分区域,交界位置同时需要绘制的对象需要特殊对待防止出现只有一半显示的情况。

D. 始终控制场景内的对象渲染数量。预先将场景中的建筑物根据投影面积和高度分配等级及可见范围,越小的建筑物可见距离越近,越大的可见距离越远,同时使用LOD简化从远处看到的建筑物的复杂度。

E. 采用LOD方式划分建筑物等级及可见范围平衡渲染总量。在数据库部分将城市建筑物按照LOD四叉树方式进行区块划分,只有面积占本等级区域1/4及以上面积时建筑物作为本等级,依次按照此规则进行划分,直至达到最高等级或者所有建筑物都划分完毕。然后根据等级分别设置相应的可见距离,理论上等级越小(初始为0级)可见距离越远,下一等级是上一等级可见距离的1/2,如0级可见范围为0-100000米,1级默认为0-50000米,....。这样划分完毕后能够对渲染总量做一些平衡,大部分小建筑物都要到近处才能显示看到。另外对于一些特殊关注的标志性建筑物可以在lod划分完成后单独修改其lod等级及可见范围以满足用户需求。缺陷是当大量的小建筑集中到某个区域时,渲染速度仍然会因为数量的剧增而极速下降。

二. 方案

方案一: LOD方式 【推荐】

第一步,采用LOD四叉树算法在数据库级对城市区域内所有建筑物进行划分,划分方法为首先获取建筑物图层的外包范围(只考虑平面,忽略高度),将外包平面作为0级,根据松散四叉树的划分规则逐级分裂将所有的建筑物分配到合适的等级和区域内(如下图所示)

 

gpu 池化调度_gpu 池化调度_08

 

第二步,根据等级设置建筑物可见距离,一般将相邻等级的对象的可见距离相差1倍,最高等级(0级)一般不会有建筑物的(占整个城市1/4以上的东东怎么可能会有!),这一级的最远可见范围决定着下面所有等级的建筑物的可见距离,它的默认值应该怎样计算?

是不是有一个比较统一的观点,比如在高空多少米的地方能够看清楚的地面建筑物的占地面积,然后根据这个数值推算出最高等级是的可见范围(线型变化)。

 

gpu 池化调度_数据库_09

 

 

第三步,对于一些用户特殊关注的建筑物可以在lod划分完成后单独修改其lod等级及可见范围以满足用户需求。

 

第四步,调度相关的一些配合流程。

当feature图层查询一个可见区域的所有地物时,数据库收到查询命令(参数是可见区域),它的查询是不是要遵循下面的那种规则:

a.从高等级到低等级排列的顺序返回查询结果【先大后小】,

b.还是直接按照与相机的距离来返回查询结果【先近后远】,

c.还是完全没有规则【不管建筑物大小,完全由调度线程可见距离来控制显示顺序】。

 

方案二 建筑物分块打包存储显示方式

就是将建筑物分成一块块的整体加载、渲染和调度,这种方式减少了渲染批次,可以加快渲染速度,但是由于建筑物数据长度的不确定性,打包文件读写和内部某个建筑的快速定位问题将会很麻烦,选择和编辑的逻辑将受打包规则的影响,而且新加一批数据时,可能需要导致所有的数据重新生成一遍才能达到优化渲染的效果。

这种方式最大的问题是我们使用的osg对后台线程生成显示列表和纹理对象是不支持的,所以只能在渲染线程生成显示列表和纹理对象,如果单个调度对象的数据量过大就会导致“帧冲击”,所以怎样将建筑物分成合适而规则的块就成了大问题了,基本无解!!!

 

方案三 倾斜摄影测量数据+建筑物单体化

三. 其它