使用基于GPU的Geometry Clipmaps进行地形渲染
Terrain Rendering Using
GPU-Based Geometry Clipmaps
Arul Asirvatham
Microsoft Research
Hugues Hoppe
Microsoft Research
1
Geometry Clipmap
简介
本文系手工翻译,因为最近比较忙,所以分成5篇来完成。翻译的目的是为了促进算法的学习和改进,具体C++实现会集成到AthenaMTRE中,故不会放出源代码。由于图片暂时没有找到合适的国内空间,如需要请查看原文内图片http://research.microsoft.com/~hoppe/#geomclipmap,或http://liruzhan.blogspot.com/。有些地方翻译得有些难懂,如觉得不明白,请留言或查看原文对比。Shader翻译成着色器;Texture材质;Buffer缓存;grid指在地形技术中的正方形的网格,在这里和多边形网格mesh不同义;Terrain地形;Landscape地貌;Clipmap暂时不翻译,没想好;finer level更加精细的层次;coarser level更加粗糙的层次。如有问题请留言。
2004
年,
Losasso
和
Hoppe
介绍了一种全新的用于地形渲染的
LOD
结构:
Geometry clipmap
。这种方法将地形的几何形状缓存在一组嵌套规则栅格
(nested regular grids)
里,这个嵌套栅格伴随着视点的移动而被增量地推移。这种栅格结构提供了比以往的非规则网格
(Irregular Mesh)
技术更多的好处:数据结构的简化,边界的视觉平滑,平稳的渲染速率,优美的分解,高效的压缩,以及实时的细节融合。在这一章,我们将描述一种基于
GPU
使用顶点材质
(Vertex Texture)
来实现的
Geometry Clipmap
算法。在将地形的几何形状作为一组图象集合来处理的时候,我们能够在
GPU
上实现几乎所有的计算,以此来降低
CPU
负载。这种技术易于实现,并且能够以大约
90
帧
/
秒的渲染速率,
355
兆的内存空间,交互式地飞过一个由
200
亿采样网格组成的美国地形模型。
1.1
回顾
Geometry Clipmap
在大型室外场景中,地形外貌的几何形状会要求巨大的存储空间和渲染带宽。很多
LOD
技术被开发出来,使地形网格的三角化过程像一个视见函数一样被适应。然而大多数这种技术需要实时地建立和修改网格结构(顶点和索引缓存),这在当前的显示架构中会导致昂贵的开销。而且不规则网格的使用通常需要
CPU
处理,在许多程序例如游戏中
CPU
资源已经是非常有限的了。
Geometry clipmap
框架(
Losasso
和
Hoppe
,
2004
)把地形作为一张
2
维高度图来对待,
把它预先分解为一个多分辨率的
L
层金字塔(见图
1
-
1
)。对于复杂的地形而言,一个完整的金字塔相对于内存而言太大了。
Geometry clipmap
结构在每一层里缓存了一个由
n
×
n
几何采样点构成的
正方形窗口,很像
1998
年
Tanner
的
texture clipmaps
。这些窗口与一系列中心位于视点的嵌套规则栅格相关联(见图
1
-
2
)。需要注意的是,更加精确的层次窗口(
finer-level windows
)的空间范围比更加粗糙的层次窗口(
coarse-level windows
)小。这样做的目的是为了在屏幕空间中保证一致的三角形大小。在一个
n = 255
的
Clipmap
中,位于分辨率
1024
×
768
窗口中的每个三角形大约
5
个象素宽。
只有最精细的层次被渲染为一个完整地栅格方块。在所有其他层次中,我们只渲染一个空心的环,环的中心区域被忽略,因为它已经在更精细的层次中被渲染出来了。当视点移动时,Clipmap窗口被移动并更新数据。为了允许高效的增量更新,Clipmap窗口在每一个层次中与环面相关联,这意味着2维环绕寻址(见1.4节)
对于clipmap结构的挑战之一是,如何消除连续层次之间的边界,这意味着同时维持网格的连续性和紧密性,以及防止暂时性的跳跃现象(popping)。Geometry clipmap的嵌套栅格结构提供了一个简单的解决方案,在每一层次的外层边界处设置一个过渡区域,在这个过渡区域里几何形状和材质被平滑地变形插值到下一个粗糙层次(见图1-3)。这些过渡过程可以使用顶点和像素着色器(vertex and pixel shaders)来实现。
Geometry clipmap
的嵌套栅格结构也能够实现高效的压缩和合成。它允许对通过对上一个粗糙层次的数据的采样来预测当前一层的高度数据。因此只需要存储或合成附加到这个预测信号的剩余细节(或差值)。
1.2
GPU
实现的简介
在2004年Losasso和Hoppe的展示的Geometry Clipmap的原始算法中,每一个细节层次使用传统的顶点缓存(vertex buffer)来实现。鉴于当时的GPU缺少修改顶点缓存的能力,那个原始算法需要CPU干涉clipmap的更新和渲染(见表1-1)。
在这一章里,我们介绍一种通过顶点材质(vertex texture)来实现geometry clipmaps的方法。这种方法的优势在于,相对于将每一个clipmap窗口的2维栅格数据手动地线性化到一个1维顶点缓存里,这些2维栅格数据可以更自然地存储在一个2维材质中。
需要重新指出,clipmap有L个层次,每个层次包含了一个
n
×
n
几何采样点的栅格。我们的目标是将采样点的(
x
,
y
,
z
)几何坐标分割成两部分:
l
(x,y)坐标被当作常量的顶点数据存储。
l
z
坐标被存储在一个单通道2维材质中
à
高度图。我们为每一个clipmap层次定义一个单独的
n
×
n
高度图材质。伴随着视点运动,这些材质在
clipmap
层次被移动的时候被更新。
因为
clipmap
层次是统一的
2
维栅格,它们的(
x
,
y
)坐标是规则的,并且相对于位移和缩放而言是常数。因此我们定义了一组只读的顶点和索引缓存用来
描述2维“足迹”(footprints),并且重复地在层次内和层次之间实例化这些足迹,这个过程将在1.3.2中介绍。
顶点通过从顶点材质里采样来获得z坐标。在顶点着色器里访问一个材质是DirectX 9 Shader Model 3.0的一个新特性,并且被例如NVIDIA的Geforce 6系列的GPU支持。
将高度数据存储在一组图象中,可实现直接通过GPU的光栅流水线来操作。 对于合成地形的情况,所有实时计算(高度图取样,地形细节合成,向量图计算以及渲染)全部在显卡上被执行,从而保持CPU空闲。对于压缩地形而言,CPU递增地解压缩和上传数据到显卡(见1.4节)。
1.2.1
数据结构
总的来说,主要的数据结构在接下来介绍。我们预定义一小组常量顶点和索引缓存,用来对
clipmap
栅格的(
x
,
y
)几何坐标进行编码。并且对于每一个从
0
到
L-1
的层次,我们分配一张高度图(一个单通道浮点
2
维材质)和一张法向量图(一个
4
通道
8
位
2
维材质)。所有这些数据结构都存储在显卡内存里。
1.2.2
Clipmap
尺寸
因为每一层次的外边界必须位于下一个粗糙层次的栅格上(见图
1
-
4
),栅格尺寸
n
必须是奇数。硬件可以根据材质尺寸进行
2
次幂优化,因此我们选择
n
=
2
k
−
1
来保证材质中的
1
行和
1
列不被使用。大多数例子中我们使用
n
=
255
。
选择
n
=
2
k
−
1
作为栅格尺寸有一个额外的好处:一个精细的层次永远不会正好位于与它关联的下一个粗糙层次的中心。换句话说,依赖于视点的位置,它们之间总是存在一个栅格单位的偏移(上下左右,见图
1
-
4
)。事实上,当一个精细层次的关联的下一个粗糙层次保持固定的时候,应该允许这个精细层次被移动,因此它有时候必须偏离与它关联的下一个粗糙层次的中心。栅格尺寸的另外一个选择是
n
= 2k
−
3
,这将提供精确置中的可能性,但是这仍然要求处理偏离中心的情况,而导致实现起来比前一种情况更加复杂。