王志科,黄长伟
(上海欣能信息科技发展有限公司,上海 200030)
三维可视化系统的研究一直以来是虚拟现实、地理信息系统(GIS)等领域的研究重点。三维场景中大规模数据的展示已经成为三维应用开发中必须要解决的问题。对于三维场景中的大规模数据,不可能一次性将所有的场景数据都加载到内存中。虽然可以通过设置摄像机远裁剪面的距离来对场景的加载进行一些优化,但是在大场景的飞行模拟中,场景视角会比较大,加载到三维场景中的数据量很大,渲染效率会下降。
在基于WebGL 的三维可视化系统中,可用3D Tiles、I3S 等数据规范来实现三维场景中大规模模型数据的渲染。3D Tiles 和I3S 规范均是将三维模型通过树结构空间索引类型对原始模型在空间上分割、转换等细碎化处理,使得场景中局部的加载压力降低,提高渲染性能。这种处理方式虽然能够提升大规模场景展示的效率,但是仍存在一些问题,例如:生成后的模型再次编辑处理比较困难;在三维场景中展示时对象单体化实现也比较困难;对WebGL 的支持较好,目前在Unity 3D 中没有可用的方案。
在Unity 3D 中,处理大规模建筑场景的解决方案主要有Auto LOD,Amplify Impostors 等。
(1)Auto LOD 使用LOD 算法。但是Auto LOD 要求在建模时就要创建出不同精细程度的模型,在三维场景中再配置模型的展示。目前大规模的建筑场景都是通过GIS 数据生成得到的,生成的只有一级精简模型,这种方法对小场景的精细模型效果较好,但对大规模城市场景并不适用。
(2)Amplify Impostors 是把场景中的物体通过不同的角度去渲染,生成图片之后保存下来使用,在场景渲染时,根据位置直接渲染生成图片,提高渲染性能。然而这种方法会导致程序占用的内存增大,而且对程序中模型拆分比较细的场景渲染效果比较好,但对大规模建筑场景的渲染提升效果不大。因此,需要研究一种大规模城市建筑数据的处理方法来提升数据的加载和渲染效率。
城市建筑轮廓,指的是一个城市的建筑平面轮廓图。城市建筑轮廓数据包含城市范围内的所有建筑轮廓,轮廓可以是一个简单的矩形,或者是多边形的封闭区域,表示这个区域内有栋建筑。通过城市建模轮廓进行三维建筑模型的生成,需要城市建筑轮廓数据中包含楼层的高度信息。
建筑轮廓数据存储方式主要为Shapefile 格式。Shapefile 是美国环境系统研究所(ESRI)开发的一种空间数据的开放格式,已经成为地理信息软件界的一个开放标准。Shapefile 是一种用于存储地理要素几何位置和属性信息的非拓扑简单格式。Shapefile 中的地理要素可表示为点、线或面(区域)。Shapefile 的工作空间可以包含dBase表,用于存储可连接到Shapefile 要素的附加属性。
本次选取的基础数据为Shapefile 格式的上海建筑轮廓数据,数据中包含建筑楼层数量信息。在城市建筑数据处理部分,首先从城市的Shapefile 数据中提取出城市建筑轮廓的几何数据和属性数据,然后对数据进行预处理,根据建筑形状及楼层数量等信息,处理生成建筑的白模模型,再根据白模进行贴图,生成模型的侧面纹理和顶面纹理,最后对生成的城市建筑模型进行切片处理,导出特定格式的模型文件。
在城市建筑轮廓数据中会出现坐标系不匹配、楼层面被错误分割等情况,因此在生成城市建筑轮廓数据之前,需要对数据进行预处理,数据预处理主要包含:建筑轮廓数据坐标系处理、城市建筑面融合与分离、建筑轮廓数据边界处理。
1.2.1 建筑轮廓数据坐标系处理
坐标系参考系统(CRS)定义了GIS 中的二维投影地图与地球上真实地址的映射关系。一般可将CRS 分为投影坐标参考系统(笛卡尔或直角坐标参考系)和地理坐标参考系统。
地理坐标参考系统,也被称为WGS84, 它使用经度、纬度和高度值来描述地球表面上的位置信息。
投影坐标参考系统,使用基于X,Y,Z值的坐标系统来描述地球上某个点所处的位置,这个坐标系是从地球的近似椭球体投影得到的,它对应于某个地理坐标系。投影有很多方式,不同的投影构成了不同的投影坐标系,常见的投影坐标系包括:高斯-克吕格投影坐标系统、Albers 投影坐标系统、Web 墨卡托投影坐标系统。
目前常用坐标系对应的欧洲石油调查组织(EPSG)编码为EPSG:4326(WGS84)、EPSG:3857(墨卡托投影)、EPSG:4490(CGCS2000)。本次获取到的上海城市建筑轮廓Shapefile 文件使用的坐标系为EPSG:4236(WGS84),在数据处理时所需的坐标系为EPSG:3857(墨卡托投影),因此在生成建筑白模前需要对数据的坐标系进行处理。
城市建筑轮廓数据坐标系处理比较简单,可使用ArcGIS 或QGIS 软件进行处理。本文使用QGIS 软件处理,处理前需要将Shapefile 文件导入QGIS 图层中,然后使用图层导出功能,将图层要素另存,在另存窗口中填写保存路径,并选择CRS 为EPSG:3857 后点击确定,即可完成建筑数据坐标系统的转换。
1.2.2 城市建筑面融合与分离
城市建筑轮廓基础数据中会出现建筑面被错误切分的情况,若不对数据进行处理,则会出现生成模型后一栋楼被拆分为多个的情况。这样不仅不符合实际情况,而且会增加生成建筑模型的三角形顶点数和面数,增大了三维场景渲染的压力,因此在生成建筑模型之前需要先将出现问题的数据进行处理。处理方法为将具有相同楼层数并相交的建筑面融合,并将不相交的建筑面分离开。因此,需要对建筑轮廓数据进行融合与分离的操作。
ArcGIS 或QGIS 软件提供了矢量数据融合处理的工具,数据融合算法采用的是矢量图层,并将其要素组合成新的要素。可以指定一个或多个属性融合于同一类的要素,也可以将所有的要素融合为单个要素。融合过程中所输出的几何图形都将转换为多个几何图形,如果输入的是多边形图层,将擦除被融合的邻接多边形的公共边界。融合过程中,启用“将不可相交的要素分开”,可在融合后将不相交的建筑面进行分离[1]。
1.2.3 建筑轮廓数据边界处理
将建筑轮廓数据融合、分离处理完成后,需要进行数据渲染将数据拆分处理。本次数据处理中可以根据行政边界将建筑轮廓数据进行分割处理。数据边界处理方法为相交处理,相交算法是提取输入图层和叠加图层中矢量要素的重叠部分,输出相交图层中的要素及属性信息[1]。
将城市建筑轮廓数据导入QGIS 软件中,并将上海各个区县行政边界也同时导入其中。选取地理处理工具中的相交功能,在相交功能里选择建筑轮廓数据图层为输入图层,选择行政边界图层作为叠加图层,选取需要保留的属性字段后,点击运行,执行完成后即可将建筑轮廓和区域边界融合。
使用分割矢量图层的功能,选取上一步处理过的模型,通过区域边界中的区县字段进行分割,分割完成后,输出各个区段的Shapefile 文件,随后可以进行城市建筑模型的构建。
通过三维建模工具,可以生成城市建筑模型,再使用Blender GIS 插件完成城市建筑白模的快速生成。Blender 是一款免费开源的三维图形图像处理软件,提供了从建模、动画、材质、渲染到音频处理、视频裁剪等一系列的数据处理解决方案。Blender GIS 是Blender 中的一款插件,提供了GIS数据文件的导入,支持大多数公共GIS 数据格式,如:Shapefile 矢量数据、光栅图像、GeoTiff DEM、OpenStreetMap xml 等。
使用Blende GIS 导入工具中的Shapefile 导入功能,选择处理后的Shapefile 文件,导入数据类型选择几何数据,扩展字段选择基面(向下取整),其他保持默认,点击确定,等待处理完成即可。导入的一个Shapefile 文件,会生成一个对象节点的城市建筑模型,若要将城市建筑单体分开,需要在导入时勾选分割对象。
城市建筑模型导入后,默认的楼层高度是1 m,故需要对建筑的高度进行调整,通过模型对象变换中的缩放,调整Z轴缩放为单层楼房的高度即可。
城市建筑白模生成后,还需要对楼的模型进行侧面贴材质和顶面贴材质处理,由于生成模型时整个城市为单独的一个对象,因此在模型处理时需要将模型进行拆分处理,将建筑模型的楼顶面和楼体侧面分离,然后再在分离后的模型上进行贴纹理等操作。
1.4.1 城市建筑模型面分离
由于生成的城市建筑白模属于同一个对象,在三维建模软件中不能单独选取进行操作,需要将建筑模型的顶面与侧面进行分离。通过分析,只需要将建筑模型的顶面单独提取拆分出来,即可以实现顶面与侧面的分离工作,在Blender 工具中,可在编辑模式下选取一个面或多个面,但如果操作方法不当,会导致选取的顶面不全或者选取的侧面不对。研究发现,所有的顶面都拥有相同的法向量,通过在场景中选取一个建筑的顶面,然后使用相似选取功能中的法向相似,即可达到选取所有顶面的目的,并且不会出现错误或者遗漏的情况[2],选取结果如图1 所示。
图1 城市建筑模型面分离选取结果
完成顶面的选取后,可通过面的拆分或分离功能,实现对建筑模型顶面和侧面的拆分或分离工作。
1.4.2 城市建筑模型材质贴图
建筑模型顶面与侧面分离完成后,需要对模型进行材质贴图。模型贴图需要对顶面和侧面分别进行UV 贴图操作。
楼体侧面贴图处理流程如下。
(1)新建一个名称为侧面的材质;
(2)进入编辑模式,通过特征选取工具,按照侧面特征选取场景中所有建筑的侧面;
(3)通过柱面投影,进行所有建筑侧面的UV映射;
(4)通过楼层高度和贴图的大小,计算UV 位置及缩放比例;
(5)给选中的建筑侧面指定侧面材质。
楼体顶面贴图处理流程如下:
(1)新建一个名称为顶面的材质;
(2)进入编辑模式,通过相似选取工具,按照法向量相同特征选取场景中所有建筑的顶面;
(3)通过视角投影,进行所有建筑顶面的UV映射;
(4)调整UV 位置及缩放比例;
(5)给选中的建筑顶面指定顶面材质。
Unity 3D 是由Unity Technologies 公司开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台综合型游戏开发工具。
Unity 3D 可以运行在Windows 和MacOS下,可将程序打包发布至Windows,Mac,iPhone,Android,Web GL 等平台,是一个全面整合的专业的游戏引擎。
VRS 平台是基于Unity 3D 打造的一个虚拟现实电网生产管理平台,平台在Unity 3D 的基础上引入了数字地球、卫星影像、地理高程等三维GIS 平台的基础支撑应用,还增加了针对变电站、架空线路、地下电缆等业务应用的实用化功能。
城市建筑数据在三维场景中展示,能够使三维场景内容更丰富,更能够真实还原出周围环境的真实情况。然而在三维场景中渲染海量城市模型,会导致需要渲染的三角面数增加,增加系统渲染的压力,因此需要有对应的算法优化渲染过程,解决海量数据加载可能导致的卡顿问题。
渲染是由一个三维场景出发,生成一张二维图像的过程,计算机需要从一系列的顶点数据、纹理数据等开始,把这些信息最终转换成一张人眼可以看到的图像,这个工作通常是由CPU 和GPU 共同完成的。可以把计算机的渲染过程分为3 个阶段:应用阶段、几何阶段、光栅化阶段[3]。
应用阶段由应用程序主导,由CPU 负责实现,此阶段需要准备好场景数据,如摄像机位置、场景中包含哪些模型、使用的光源特效等,为了提升渲染性能,还需要进行一个粗粒度的剔除工作,将场景中不可见的物体剔除出去,从而减少渲染的数据量。此阶段完成后,输出的结果为包含点、线、三角面等数据的渲染图元[3]。
几何阶段由GPU 负责,处理所有和需要绘制的几何相关的内容,会对渲染图元进行逐点、逐多边形的操作,将顶点坐标变换到屏幕空间中,输出屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息,并传递到下一阶段。
光栅化阶段是根据屏幕上的像素渲染出最终的图像。此阶段需要对上一阶段得到的逐点数据进行插值,然后再进行逐像素处理,最终决定每个渲染图元中的哪些像素应该被绘制在屏幕上[3]。
在三维场景的渲染流程中,CPU 与GPU 间的通信会使用一个命令缓冲区,Draw Call 就是其中命令的一种,提交大量很小的Draw Call,会造成CPU 的性能瓶颈。因此,在三维场景渲染时,需要减少Draw Call 的开销,避免使用大量很小的网格,同时避免使用过多的材质,进而提升渲染效率[4]。
要在三维场景中实现高效、稳定地渲染大量的城市建筑、地形地貌等地理信息系统数据,需研究一套有效的三维场景数据管理方法。
在三维场景中渲染大批量数据时,如果只是用List 将渲染对象存储,然后送入GPU 进行渲染,这种方式虽然简单,但渲染效率很低。目前比较好的方法是使用具有层次结构的空间数据结构存储待渲染的物体,如包围体层次结构(BVH)、二叉空间分割(BSP)树、四叉树、八叉树和模糊K-D 树等,在进行空间查找时将时间复杂度从O(n)降低到O(lgn)[5]。
BVH 是包含一组物体的空间体,它要比所包含的几何物体形状简单得多,所以在使用包围体进行碰撞检测等操作时比使用物体本身更快。常见的包围体有轴对齐包围盒(AABB),有向包围盒(OBB),以及离散定向多面体(k-DOP)。
对于三维场景的实时渲染来说,BVH 是最常使用的数据结构,例如BVH 经常用于视椎体裁剪。场景以层次树形结构进行组织,包含一个根节点、内部节点和叶子节点。最高节点是根,没有父节点;叶子节点保存着需要绘制的实际几何体(BVH 只能存储几何体,实际渲染的物体除了几何属性还有其他属性,一般使用场景图表示)。树中的每个节点,包括叶子节点,都有一个包围体,可以将其子树的所有几何体包围起来。
在场景中的物体移动时,需要对BVH 进行更新。如果物体移动以后仍然在原先的包围体内,则不需要更新;若不在原先的包围体内,则需要删除这个物体所在节点,并重新计算其父节点的包围体,然后从根节点开始,以递归形式将这个节点插入这棵树中。另一种方法则是以递归形式增大父节点的包围体,直到这个包围体可以包含这个子节点为止。无论使用哪种方法,随着编辑操作的增多,这棵树会变得越来越不平衡,效率也会越来越低。
在计算机图形学中,BSP 树有两种不同的形式:轴对齐(axis-aligned)和多边形对齐(polygonaligned)。要创建BSP 树,首先用一个平面将空间一分为二,然后将几何体按类别划分到这两个空间中,随后以递归形式反复进行这个过程。这种树有一个非常有趣的特性,如果按照一定的方式对树进行遍历,那么会从某个视点将这棵树包含的几何体进行排序(对于轴对齐的方式来说,它是粗略的排序;对于多边形对齐方式来说,它是准确的排序)。
八叉树类似轴对齐BSP 树。沿着轴对齐包围盒的3 条轴对其进行分割,分割点必须位于包围盒的中心点,以这种方式生成8 个新的包围盒。八叉树通过将整个场景包含在一个最小的轴对齐包围盒中进行构造,递归分割,直到达到最大递归层次或包围盒中包含的图元小于某个阈值。八叉树的使用方式与轴对齐BSP 树一样,可以处理同类型的查询,也可以用于遮挡裁剪算法中。八叉树具有规则的结构,有些查询会比BSP 树更高效。
在八叉树结构中,通常将物体保存在叶子节点中,其中有些物体必须保存在多个叶子节点中。这种做法的一个最大弊端就是数据量增大,而如果使用指针,则会导致八叉树的编辑变得更加困难。“松散的八叉树”算法对这个问题进行了改进。
海量的城市模型场景,属于大规模的室外场景,场景中的物体比较分散,而且没有出现太多遮挡的情况,由于不用存储分割平面位置,使用八叉树这种规则的空间结构能够提高效率,因此在进行城市场景管理时经常使用八叉树结构进行数据管理。
对于海量城市模型的渲染,根据对三维渲染过程的分析,设计城市模型数据存储结构,对数据进行拆分处理,同时根据数据分页技术,提高对模型渲染状态的管理效率,实现动态加载、卸载模型,进而实现大规模城市建筑模型的渲染。
遮挡剔除算法,是预先计算出一组潜在的可见候选多边形,然后在运行时编制索引,以便快速获得可见几何体的估计值。具体实现步骤如下。
(1)将地图场景切割成Tile,再将Tile 切割成Portal(视口)和Cell(大物件、中物件、小物件)。
(2)检测场景物件所属Cell,一个物件可以属于多个Cell。
(3)利用蒙特卡洛方法Portal 随机一些起点,Cell 随机一些终点(根据大、中、小随机不同数量的点)。
(4)双层遍历每个Portal 和Cell,射线检测是否阻挡,如果阻挡,判断阻挡物是否在当前检测Cell内,如果是,Cell可见;如果不是,Cell不可见。
(5)保存检测数据,运行时加载解析,根据位置检测当前Portal,然后遍历场景所有Cell 内Item,判断显示和隐藏。
这种方式进行裁剪,更适合大地图场景操作,能够支持动态加载,占用内存也可忽略不计,同时消耗的CPU 也比较少。
在城市三维场景中,可以采用数据分页的方式进行三维场景的动态调度。数据分页是指随着窗口视角范围的不断变化,场景中只加载和渲染当前视角窗口范围内的数据,并将离开视角范围内的数据进行清理或者设置其他的数据卸载策略,使得这部分数据不再渲染。这样能够保证内存中只有有限的数据量,场景中的每一帧也只有有限的数据被送到图形渲染管道,从而提升渲染性能。
数据分页算法设计如下。
(1)服务端设定一个分页参数,将场景数据按照经纬度位置进行数据分页加载配置,并将场景数据按照分页配置,加载到Redis 内存库中保存。
(2)客户端通过摄像机当前所处的经纬度位置进行分页数据计算,根据视野的最远裁剪面和当前位置,计算出在摄像机可视范围内的分页。
(3)客户端向服务端请求相关的分页数据,并将分页场景数据保存至客户端内存中。
(4)客户端根据内存中的分页场景数据进行判断,卸载掉不在视野范围内的数据,并装载新增加在视野范围内的数据。
(5)客户端将变化后的内存分页数据进行处理并在三维场景中渲染。
本文主要研究了如何通过城市的GIS 数据,生成大规模的城市建筑模型,并提出了一种海量城市模型三维场景的管理方法,实现了大规模城市建筑模型数据的可视化渲染,并提高了场景渲染效率,具有一定的实用价值。
在以后的研究中将继续对数据处理方法进行精简,编写数据处理插件,完善城市模型快速构建的方法。