3D地形编程——之GeoMipMap基础(3)

来源:互联网 发布:科幻世界淘宝店怎么了 编辑:程序博客网 时间:2024/04/27 03:07

 

5.10

5.10为了防止与右边图块断裂,需要移除最右边列的扇面的右边顶点的图块。

 

实现Geomipmapping仅是稍微弱地CLOD

你知道Geomipmapping基础背后的理论,但是现在我们需要实现它。这应该不会使你脑袋很头痛。难的部分已经完结了,象往常一样,我们将每一次谈论一步。拿一些咖啡,锁上你的门,放一些好的音乐,开始吧!

 

拼凑它

因为Geomipmapping是一系列块组成的,实现从构造图块的数据结构开始,大概是一个好主意。结构真的不需要包含很多信息,我们需要包含的越少就越好。事实上,这始终是你在这本书看到的构造的最小的结构。别不太习惯它漂亮的大小!

 

所有的块结构真正需要的是2个变量。一个变量将记录当前块的细节级别(LOD),而另一个变量将存储从块中心到摄像机位置的距离。这就是给它的所有了!这是完整的块的数据结构。它们的代码在这里:

 

Struct SGEOMM_PATCH

{

       float m_fDistance;

      

       int   m_iLOD;

};

 

它看起来象一个极小的结构,但是记住:大东西得到了小包装。如同这个包小一样,我们将时常地使用它,所以确定你花了时间记熟它的成员。

创造Geomipmapping实现的基础

是的,不再说那2个成员数据结构的无用的东西。现在我们开始从Geomipmapping引擎最劳累的地方工作――Geomipmapping类。在开始,我们需要一个指针保持我们的块信息,它会在我们的演示中在一些地方被动态的分配。接下来,我们需要算出块的尺寸(用顶点),还有在地形中每一边有多少块。块的大小会完整地给使用者,那么我们能让用户在他初始化这个类时具体指定他喜欢的块的大小。(我倾向于固定块的大小为17×17顶点,因为它提供漂亮的细节和速度的平衡。在这章的描述中假定这就是块的大小。)

 

小心

Geomipmapping的实现是基于一个 像素的正方形高度图。这意味着你不能用中心点有位移的,不规则的高度图生成器生成的高度图。确保你所有高度图是由这个有缺陷组成的生成器生成。(应该是指需要使用中心点正中的高度图,至少是矩形的吧,不能是不规则的。)

 

Geomipmapping的初始化

Geomipmapping初始化系统中,我们需要的所有东西是用户希望的块的大小。(我将重声我的建议是17×17的顶点。)在我们得到它之后,我们就能初始化这个系统了。

 

首先,我们需要计算出地形的每条边有多少块。我们通过把高度图大小按照单个块大小划分计算结果,如图5.11所示。

 

P代表每条边块的数量,h代表高度图的大小,s代表单独一块的大小。借助那个公式,看一下前面的图5.12,看一会之后我们将把什么变量带进这个公式。

 

在我们计算出每条边有多少块之后,我们需要分配每条边块数量(我们刚完成了这个值的计算。)的平方大小的地形块的缓冲区。

 

m_pPatches= new SGEOMM_PATCH [SQUARE( m_iNumPatchesPerSide )];

 

下一步,虽然这不是必要的初始化部分,我希望计算图块能完成的最大数的细节级别。注意这个最大数的细节级别是指最少细节的级别,最多细节级别是0。随着级别数的增大,细节减少。

 

 

5.11

5.11 计算地形网格每条边块的数量的公式。

 

这是计算方法:

 

iDivisor= m_iPatchSize-1;

while( iDivisor>2 )

{

       iDivisor= iDivisor>>1;

iLOD++;

}

 

我们在这里所要做的就是看有多少个循环让iDivisor下降成2。当iDivisor到达2,我们不能再下降任何更深一层了,由我们所控制我们已计算出细节级别。以17×17块的大小为例,我们最大数细节级别是3,这意味着对于任何单一的块我们有4个不同细节级别(0123)选择。那些是为了初始化!现在我们继续前进到极其大的停工部分。

 

Geomipmapping的停工

这很简单并且照惯例的停止Geomipmapping系统。我们所需要做的是释放分配给图块缓冲区的内存和重置所有类的成员变量。

 

Geomipmapping的维护

这个地形的工作与我们过去的3章不同,连续层次细节(CLOD)地形算法需要每帧都更新(这也是为什么被叫做连续层次细节的原因)。大部分基本的连续层次细节(CLOD)算法需要在更新时期间做大量的维护工作,但是Geomipmapping不是其中之一。我们在更新函数中所要做的工作是相当微小的;它简单的由计算出我们的图块应该是什么细节级别(LOD)构成。

 

在我们的Geomipmapping实现的update函数中,我们需要更新每个块;因此,我们需要用双层for循环:

 

for( z=0; z<m_iNumPatchesPerSide; z++)

{

       for( x=0; x<m_iNumPatchesPerSide; x++)

       {

 

在循环里面我们要做的第一件事是计算从观看者的位置(摄像机视点位置)到当前块中心的距离。这个计算在你的高中数学课上看起来应该很熟悉,在那里他们播种距离公式到你的脑袋里。正好假使你象我一样你也在那个所有课程上从头到尾的睡过去了,它在这里(看图5.12):

 

 

5.12

5.12 3D的距离公式。

 

伴随这个公式,看下图5.13看我们将把什么变量带进公式。

 

 

5.13

5.13 与距离计算(从观看者到当前图块中心)有关的变量。

 

一样的距离计算的代码:

 

m_pPatches[iPatch].m_fDistance= sqrtf(

                          SQUARE( ( fX-camera.m_vecEyePos[0] ) )+

                          SQUARE( ( fY-camera.m_vecEyePos[1] ) )+

                          SQUARE( ( fZ-camera.m_vecEyePos[2] ) ) );

 

在我们计算出从观看者的距离,我们就能计算给块多少细节级别。在代码中,我计算这个级别用的硬编码距离。(我在代码片段的一些段落中是这么做的;你也许想掠过一点前面的直接看我说的是什么。)在你的引擎里,虽然,你会想更精确的方法计算图块应该的细节级别。例如,在Geomipmapping白皮书中,Willem de Boer 展示了一种屏幕像素测定算法所以当块改变它的细节级别时,太多的突变不会被呈现。

 

突变是当一个多边形物体改变到不同细节级别时出现的。这个变化也许明显或者不明显。例如,从级别1变到级别0不会导致许多突变因为一个级别1的块仍然很细致(对17×17块而言,至少是这样)。然而,从级别3变到级别2会引起相当小部分的突变因为三角形从8个变成了32个。虽然是同样的比例的三角形被添加到前者的块中,级别3到级别2的变化更明显。任何连续层次细节(CLOD)算法的一个重要目标是减少甚至是完全的消除突变。我们将在随后谈论更多。

 

无论如何,这本书里我的Geomipmapping实现,我简单的把细节级别(LOD)距离的变换硬编码。(我想留下这个习题公开给你,读者。是的,我知道我是个漂亮的家伙。)这里是细节级别变换的代码片段:(所谓把细节度变换的距离固定下来及是硬编,这样做好像是容易出现突变)

 

if( m_pPatches[iPatch].m_fDistance<500 )

原创粉丝点击