缩略图

高性能全球动态地形渲染方法研究

作者

朱长德

南京宇天智云仿真技术有限公司

引言

高性能的全球地形渲染在虚拟现实、军事仿真以及飞行模拟等领域扮演着越来越重要的角色,这些领域对全球地形系统的实时性和动态性都有很高的要求。

基于实际的应用需求,我们提出了一种高性能的、GPU 友好的全球动态地形绘制方法。该方法充分利用了现代 GPU 和图形 API 的特点,以立方体球面映射算法和无状态四叉树结构为基础,对球面网格数据和渲染状态进行统一整合,同时利用 bindless 纹理组建地理信息数据集,从而极大减少了渲染状态和数据切换引起的CPU 开销,实现全球地形的高效绘制。

同时,我们的方法整合了 GPU 数据处理管线和图形渲染管线,两者合二为一,为地形数据的实时编辑和更新提供了性能保证,避免数据在CPU 与GPU 之间往复拷贝引起的开销。而通过 GPU 着色器的数据处理管线,可以为地形生成更加精准的信息,比如地形坡度,高差以及向光性等,这些信息会作为地形程序化生成的依据,为最后的全球地形渲染提供更加逼真的效果。

1 地形系统设计与实现

1. 球面构建

1.1 立方体球面映射

渲染全球地形的首要任务就是对球面进行建模,如何使用有限的三角面来构建一个球形表面是该部分的核心内容。我们采用了一种基于立方体的球面投影算法,该算法将立方体六个面各自按照四叉树规则,根据眼点位置进行细分,细分后的坐标通过球面映射,将其转为为以立方体中心点为原点构建的 WGS84 坐标系下。从而完成从本地平面坐标到球面世界坐标的转换。转换的公式如下:

Plocal=(x,y,R) (1.1

Pw=(R+z)*Plocal/|Plocal|

而从世界坐标系到本地平面坐标系的变换,则是上述变换的逆变换,转换公式如下

Plocal=(R*Px/Pz,R*Py/Pz,|P|-R)

球面顶点坐标转换完成后,还需要对所有渲染所需的顶点属性进行计算和转换,为了能够计算顶点的法线转换,我们需要定义顶点的切向空间:

1.2 实现方法

为了最小化 地形网格之间的差异,我们将从本地平面空间到世界球面空间之间的转换过程放到执行 GPU 的顶点着色器上执行。为了实现该过程,我们对每个地形瓦片的网格变换数据进行组织,最后通过 Uniform 缓冲的方式将数据提交到 GPU 显存。最后通过编写顶点着色器对顶点执行变换操作。具体的步骤如下:

1. 根据眼点位置更新六个平面的细节层次

2. 为每个新增的细节瓦片的四个角坐标,使用双精度浮点型数据,将其变换到NDC 空间。这么做是为了保证超大坐标系下,坐标精度丢失的问题。

3. 我们手机四个角的NDC 空间坐标、NDC 空间法线以及当前瓦片在本地空间的偏移量4. 然后我们在顶点着色器中,通过这些数据,根据公式 1 描述的变换,就可以将平面坐标转换到球面坐标。并且尽最大可能保证了数据的精度不丢失。

1.3 总结

该算法可以避免在 CPU 端程序中,为每个细分的瓦片构建一个不同的顶点数组,所有细分网格在本地坐标系中都是相同的,不同的只是它们的变换,因此非常有利于对细分网格进行合批处理,将其放到同一个绘制批次中绘制。同时该方法可以避免在南北极区域出现的数据畸变,进而避免由此引起的视觉和交互上的失真体验。

图1​立方体球面映射展示图

2 构建全球地形细节层次

全球地形的渲染离不开细节层次技术,要同时满足海量的地形数据的调度和渲染的高实时性,就必须选择灵活高效的地形细节层次算法,这样才能在有限的空间和时间下渲染出全球地形。

2.1 无状态四叉树结构

为了达到灵活高效的目的,我们采用了无状态的空间四叉树结构,配合连续细节层次CDLOD 技术,可以高效的对全球地形进行动态细分和更新。相较于传统的空间四叉树结构,每个节点都对应了一个地形瓦片,这些节点本身维护了大量的跟该瓦片相关的渲染上下文,使得每个节点必须对应一个绘制批次,在面对全球地形的超大数据集和超远可见距离时,该方式更加难以满足其性能需求。

因此我们采用的无状态四叉树结构,将每个四叉树节点的渲染状态抽象统一,从而将其从节点中抽离出来,放到一个统一的数据集合中进行管理。从而解耦了节点数量和绘制批次数量,可以利用Indirect 绘制一次性将所有节点全部绘制。

四叉树的细分规则采用了根据节点到眼点的距离进行判定。具体的判定规则是根据节点所持有的瓦片的中心点到视点的距离 d,是瓦片尺寸 L 的 k 倍时,就将该节点细分为四个子节点。k 被称为细分距离因子。它决定了四叉树是否受限,即是否要求四叉树的相邻四边形之间的层级最多相差1。如果 k<1,则四叉树为非受限,反之则为受限四叉树。

图2 四叉树细分示意图,从左只有k 分别为1.1,1.5,2.0,2.5

2.2 实现方法

在设计设计四叉树的数据结构时,就需要将所有与渲染相关的数据进行剥离,比如顶点数组,变换矩阵,纹理以及渲染状态等。只为四叉树保留父子关系和空间细分规则。剥离的数据都为其设计专门的数据管理器,将数据放入数据集统一管理。最后地形细分更新后,遍历四叉树并收集每个四叉树的叶节点 ID,数据集中的数据通过节点 ID 与实际的地形瓦片关联。最后这些数据通过不同的数据缓冲被送入GPU 中进行进一步处理。具体的算法步骤如下:

定义四叉树数据结构,为四叉树节点定义ID(level,tx,ty) 及其他参数,比如最大最小层级,包围盒等信息

根据当前眼点位置对四叉树结构进行更新。为新细分的节点分配相关数据,构建 ID 并且根据当前节点的具体层级、位置等信息生成相应的矩阵变换数据。

为新生成的节点构建与渲染相关的数据,包括网格数据、贴图数据、Uniform 变量以及渲染状态数据等。这些数据以ID 为Key 放入数据管理器持有的集合中。遍历四叉树,收集叶子节点,并对每个叶子节点执行视锥裁剪和地平线裁剪计算。

为通过视锥裁剪的节点生成绘制数据,通过其 ID 找到到其节点数据,然后重新进行组织并填充到相应的数据缓存,准备提交给 GPU 使用。具体的数据组织方式将会在第 3 章节合批渲染中详细描述。

2.3 总结

通过无状态四叉树的设计,我们可以将地形渲染数据和地形细分数据解耦,从而可以将全球地形通过一次绘制全部完成,避免过多的绘制批次引起的开销,极大提升了地形的渲染效率。

图3 地形细节层次展示

3 海量地形瓦片合批渲染

在第 2 章节,我们完成渲染数据的初步收集工作,这些原始的数据是无法直接送入 GPU使用的。由于 openGL 使用的是状态机机制,程序的每次状态设置都是对状态机的改变。如果需要绘制的物体某些状态不同,就需要将它们分成多个批次分别设置状态并渲染。这会带来很多驱动端的切换开销,降低渲染的性能。而如果想合并成一个批次进行渲染,就必须对各个物体的差异数据进行合批,这其中就包括了纹理数据,Uniform 数据,顶点数据等。为了达到此目的,我们使用了现代 OpenGL 的 AZD0[6] 技术,通过一些列扩展对相应的数据进行合并,以求消除数据差异引起的状态切换开销。

4 全球地形实时动态处理

由于全球地形大多都是通过一些静态地理信息数据进行渲染的,并且其涉及的数据体量非常大,所以实时动态的地形编辑、破坏、更新以及回写都是非常困难的。为了满足越来越多的应用场景的需要,我们提出了一套与图形渲染管线紧密融合的基于GPU的数据处理管线。它允许我们高效地对即将显示的地形数据进行实时的编辑、特征提取以及渲染。同时也支持将编辑后的数据再序列化到离线数据文件中。整个数据处理管线充分利用了现代 GPU 的计算能力,将管线嵌套进了我们的图形渲染管线。实现了数据从收集到编辑最后再到渲染的整体架构。

5. 基于物理的光照计算

全球动态地形渲染的最后一步就是着色,按照现代图形管线的基本设计,着色计算都是在片元着色器中完成的。由于光照模型的研究不是本论文的重点,所以在本章节就针对本论文所使用的基于物理的光照模型 [7] 做一个简单的介绍。

结论

本论文从性能和实用性角度出发,提出了一种高效的全球动态地形实时渲染方法。该方法从地形数据的组织调度、地形空间结构的优化和地形实时合批渲染三个方面出发,引入了球面映射算法和无状态空间四叉树,通过现代 OpenGL 的各类扩展和合理组织渲染数据,完成了全球地形的单批次高性能渲染。同时整合基于 GPU 的数据处理管线,利用 GPU 的强大算力,实时动态编辑和修改地形数据,并通过程序化生成技术,实现全球地形的基础生成逻辑。最后使用基于物理的光照模型,提供了逼真的地形光照表现。通过实验结果可知,该方法满足了我们的预期目标,在常规硬件水平下,可以满足全球高精度地形的实时渲染和动态编辑。