最近在看OGRE怎样载入地形的内容,因为terrain.cfg中涉及了很多的LOD(细节层次)的问题,看得我一把鼻涕一把眼泪的,所以就想说先看看LOD地形再去研究ogre本身地形实现的具体操作应该会好一些,主要资料参考的是曾凡喜,周炜,潘运亮等的《Direct3D
实时渲染技术》这本书,其对于用四叉树实现的LOD地形有比较详细的描述。
【LOD出现原因】
由于大的地形绘制需要在短时间内处理上亿个三角形,其实时绘制要求仍然是飞行仿真、数字娱乐等虚拟现实应用中的一个难点。尽管近年来硬件技术飞速法阵,显卡的性能指标已经有很大的增长,但是仍旧不能满足大地形的实时绘制要求,比如在进行飞行模拟的时候,要穿越一个km为单位的地形,每个网格都用三角形绘制,则此时就算是再好的显卡在每秒至少24帧的要求下也不能进行实时的处理,所以多分辨率技术(Multi-resolution)就此诞生。
多分辨率网格简化技术/细节层次模型技术(LOD技术),引入“分而治之”的思想,根据地形的不同复杂程度和人眼观察地形的特点,对地形的不同区域采取不同细节的描述和绘制。采用LOD技术绘制地形,在不降低表现效果的前提下,可以尽量减少三角形的数量,以提高图形绘制效率,实现地形的实时交互可视化,通俗具体讲就是将一块地形划分为无数小块区域,对于离视点越近的区域,或者该区域地形越复杂(起伏大,如山区),绘制的三角形数目越多,地形描述精度越高;对于离视点越远的区域,或者该区域越平坦,绘制的三角形数目越少,地形描述精度越低。
LOD技术按照所生成的网格的形状可以分为不规则三角形网(TIN)和规则格网两类。这两类网格模型,在以同样的表达精度绘制同样的地形时候,基于TIN的多分辨率地形表示法所需要的三角形数量更少,而基于网格的多分辨率地形表示法构建网格的速度更快,实时性更好,算法更易于程序实现。
Lindstrom等人于1996年提出了基于四叉树的连续细节层次模型(Continuous level of Detail)的构建算法,是基于规则格网类的具有代表性的研究成果之一。算法的“连续”特性包含了3个意思:
1) 帧更新时,地形表面保持连续性,即“时间的连续性”;
2) 不同分辨率的地形分块之间保持连续性,没有裂缝,即空间连续性;
3) 算法的实时构网能力很强,以保持较高的屏幕刷新率。
【基于四叉树的视相关LOD地形算法】
l 地形的四叉树结构
为了更加清楚的描述算法的思想,对三维地形有如下的要求:
1) 地形必须是一块正方形区域;
2) 地形大小必须是(2^n+1)X(2^n+1)
如下图所示,我们将一块地形的高程数据用一个四叉树结构组织起来,其中每个正方形代表一个节点,每个节点包含9个高程点,其中有一个中心点、4个角点和4个位于4条边上的中点。一个大正方形里面包含4个小正方形(叶子节点除外),这四个小正方形所代表的节点就是大正方形节点的子节点。
地形的四叉树结构
首先按照地形的大小把整个地形分割成一棵满四叉树,满四叉树的概念是从满二叉树引申过来的,它必须满足以下的条件:
1) 除了叶子节点,每个节点都有4个子节点,并且其所有子节点都位于同一层上;
2) 地形越大,四叉树的深度越大
![LOD地形绘制 LOD地形绘制](http://s3.sinaimg.cn/middle/5e3213f3hbb969508fcd2&690)
满四叉树
这样我们就可以看出来,每个节点表示一块地形,节点的层次越低(根节点的层次最低,为0),所代表的正方形的面积越大,该节点的细节程度(Level)也越低。显然,叶子节点的层次最高,它的Level也最高。
地形的高程数据保存在一个二维数组中,由于该算法是规则网格的,很容易找到每个节点的9个高程点在二维数组中的对应元素。
用一个四叉树表示地形有很多优点:
1) 便于可视地形区域测试的节点裁剪;
2) 四叉树遍历的快捷性适合对网格进行实时更新
l 如何绘制地形
一般采用三角形扇的方式来绘制细节已经满足要求的节点,这是一种很自然的方式,因为每个节点包括一个中心点和若干围绕中心点的点,刚好排成一个三角形扇(如图所示,这样排列的好处是便于将相邻的三角形合并(后面会讲到为了消除T型裂缝,我们有时需要将两个三角形合并。
用LOD算法来简化地形的过程就是自上而下(或者自下而上)遍历四叉树的过程。如果节点的细节程度(Level)已经满足某种简化准则,则绘制该节点,否则不绘制该节点,继续考察他的4个子节点,因此,必须建立一种能对节点进行评估的简化准则,以决定对某块地形简化到何种程度。
【节点简化准则】
节点简化准则是地形简化的核心,不论其采用何种节点误差计算方法,都要符合以下的规则:
1) 如某节点离视点很近,或者它代表的地形块很“粗糙”,则应该对该节点往下细化,即继续考察它的4个子节点;
2) 如果某节点离视点很远,或者它代表的地形很“平滑”,则应该对该节点往上简化,即考察它的父节点;
3) 如果某节点与视点的距离适中,或者不太粗糙也不太平滑,则应该独立地绘制该节点。
采用简化准则对节点进行评估的时候,应该考虑下面的3种因素:
1) 地形块的大小;
2) 地形块与视点之间的距离;
3) 地形块的粗糙度。
简化准则通常都是通过误差模型(Error Model)来实现的。除了Level最高的节点外,其他的节点相对于原始地形数据都有一定的误差,因此可以用误差的大小来决定节点的Level是否符合简化准则。
Lindstrom在其文章中提出了基于顶点的简化准则(Veterx-based Simplification),但是这种方法计算量十分大,所以需要利用下面的简化方法来进行顶点的误差估计:
LindStrom提出了基于块的简化准则(Block-basedSimplification),该准则用地形的整体粗糙度来确定节点的误差大小,而且适用于“自上而下”的遍历顺序。它假设块内的所有顶点是非常“紧密”的,即块内任意两点之间的举例远远小于节点到视点之间的距离d,根据一定的算法可以求出该及诶单的“粗糙度”u,如果u/d大于常数t,则应该对该节点往下细化,否则进行独立的绘制。于是问题就转化成为构造一种合适的能描述地形粗糙度的算法。
在书中提出了一种简便的粗糙度求取算法——最小二乘法。用Zx,y表示地形块中的某顶点的高度,因为地形块为一个方形区域,满足条件Xmin<X<Xmax,Ymin<Y<Ymax.X和Y都取整数值
【裂缝处理】
LOD算法“分而治之”的思想带来了地形“裂缝”这个难题。如图,当同事绘制两相邻的分辨率不同的节点的时候,就会产生T型裂缝:
![LOD地形绘制 LOD地形绘制](http://s1.sinaimg.cn/middle/5e3213f3hbb9696b78820&690)
如图,裂缝产生的原因是左侧节点在交点B处的高度值来自原始准确数据,而右侧节点的Level比左侧的低,在交点B处的高度值是A和C的平均值。这样,同一点在相邻的两个节点之间的高度差便会产生三角形裂缝。
有两种技术可以解决裂缝的初级问题:
1) 边删除技术
边删除技术在Level较高的节点T型裂缝处删除一条边这样把两个相邻的三角形合并成为了一个。如图中所示,要解决裂缝问题,共需要删除3条边,删除边之后的网格如图所示
![LOD地形绘制 LOD地形绘制](http://s13.sinaimg.cn/middle/5e3213f3hbb969824704c&690)
2) 边插入技术,就是在Level较低的节点内部添加一条边,这样就把一个三角形分割成两个
![LOD地形绘制 LOD地形绘制](http://s3.sinaimg.cn/middle/5e3213f3hbb96986acb42&690)
然而,要避免T型裂缝现象,仅仅依靠边删除或者边插入技术是不够的,地形网格还需要满足一个条件:相邻两个节点之间的Level差值不能大于或者等于2.这时候边删除是无能为力的,采用边插入技术将使得算法变得过于复杂,不易实现。
l 解决办法
当两个相邻节点之间的Level之差大于1的时候,强制把Level较低的节点分裂成4个子节点。Rottger介绍了一种更加灵活的方法,它将四叉树中各个节点的状态用一个布尔矩阵表示,节点状态要么为‘1‘,要么为’0’,要么为‘?’。
Bool值1表示该节点Level较低,需要进一步向下细化,0表示该节点Level适中,应该对它进行独立绘制:‘?’表示该节点Level太高,应该对该节点向上简化,如果布尔矩阵同时满足以下条件:
1) 所有0节点的父节点状态为1;
2) 所有1节点的相邻同Level节点的状态不为‘?‘
则称该矩阵是完备的,使用完备矩阵方法再配合边删除或者边插入技术就可以很容易地构造一个无裂缝的多分辨率地形。
【突起现象】
当视点移动的时候,地形网格不断更新,当节点Level发生变化的时候,地形中的某点会由一个高度突然跳变到另一个高度,这种称之为“突起”现象(Poping-up)。在地形漫游系统中,“突起”现象给人 一种不真实的感觉。为消除这种不自然的行为,引入了一种”形变“算法。形变的含义是,当节点从一个Level过渡到另一个Level的时候,其中某点平稳缓慢地从一个高度过渡到另一个高度。形变虽然没有本质上消除地形高度变化,但这种“缓变”往往肉眼难以察觉。