背景
在介绍层次细节算法之前,先来看两幅图片。
图一
图二
这两幅图片是用层次细节算法也即LOD算法绘制的地形网格。为了更清晰的看清地形网格的结构,我没有给其贴上纹理。这两幅图片看上去给人第一感觉就是分辨率不同,图一分辨率较低,图二分辨率很高。图一图二是由同一个程序生成的,图一时在调节系数为1的情况下生成的,图二是在调节系数为25的情况下生成的。为了增加对比度,我故意把两幅图片的分辨率调节的差别很大。这个地形网格如果达到全分辨率的话将会是513像素*513像素。然而读者看到的图片并没有达到全分辨率。为什么呢?大家想一下,在现实世界中,人眼的视角是有一个范围的并不能看到360度范围的场景;随着视线的往远处移动,看到的东西越来越模糊;大家在想一下另外一个问题,把图片贴到一个物体上,如果这个物体的表面是平的,那么任务肯定非常容易完成,如果物体表面凸凹不平,那么你就不能把图片直接贴在上面,你必须把图片简称小的片段然后在艰难的贴在物体表面。同理层次细节算法就是模拟上述现实场景的技术,只不过我们将换一套专有名词来描述。上述地形网格在满足下面三个条件时候被绘制,一,不在照相机视景体内的网格部分将不会被绘制;二,距离相机视点远的地方网格以低分辨率来绘制,近的地方以高分辨率来绘制;三,粗糙的部分以高分辨率绘制,平坦的部分以较低的分辨率来绘制。这三个条件合称节点评价系统。
地形高程图
在层次细节地形绘制的过程中,每一个顶点坐标(x,y,z)被分为两部分处理,(x,z)与y两个部分。至于为什么这样做,当你看完本篇文章之后你就会明白。在OpenGL里面Y轴是垂直向上的,因此顶点的y坐标值代表顶点的高度。高程图就是存储y坐标值得,其中一种方法就是使用raw格式的文件。raw格式文件是8为的,也就是说把raw格式的图片看成width*hight大小的矩形的话,其中每个元素表示一个8位的数据,范围是0到256。在层次细节算法中要求地形的大小必须是正方形,而且必须满足边长的像素数为(2的n次方)+1;后文大家会明白为什么会有这两个限制。本文我们使用.raw格式的高程图,其制作方法有很多,本文介绍一种最简单的方法,用photoshop生成,如果要想生成自己想要的那种地形需要使用专业的方法来生成高程图,本文使用的是随机生成的高程图。方法很简单,打开PS快捷键crtl+N新建一个513*513像素大小的项目,确定后从工具栏里选择滤镜->渲染->分层云彩,然后存储为选择.raw格式,至此高程图就完成了。下面给出加载高程图的程序代码:
void GLLod::loadRawFile(LPSTR strName, int nSize)
{
FILE *pFile=NULL;
pFile=fopen(strName,"rb");
if(pFile==NULL)
{
MessageBox(NULL,TEXT("不能打开高度图文件"),TEXT("错误"),MB_OK);
return;
}
fread(pHeightMap,1,nSize,pFile);
int result=ferror(pFile);
if(result)
{
MessageBox(NULL,TEXT("读取数据失败"),TEXT("错误"),MB_OK);
}
fclose(pFile);
}
从高程图中得到坐标(x,z)处的高度值的程序代码:
int GLLod::getRawHeight(int x, int z)
{
int xx=x%(map_size+1);
int zz=z%(map_size+1);
if(!pHeightMap) return 0;
return pHeightMap[xx+(zz*(map_size+1))];
}
层次细节算法(LOD算法)
现在要步入正题了,我将会向大家介绍层次细节算法的原理。LOD算法采用的是四叉树的结构来处理的。
我们看上图,网格一是最初始的没有分割的正方形,其边长是如果以像素表示边长的话那么边上有
个像素。那么在这里我们可以看出每一个网格的边长是5个像素,若每个像素间的距离为一的话,那么每个网格的边长是4,下文中我们默认每个像素间的距离唯一。将网格一等分为4个小网格,那么这四个小网格是原网格的四个儿子节点,继续划分,图二中的每个儿子网格继续划分为四个儿子。我们可以有选择的划分某些网格,每个网格一旦划分的话,就必需划分为四个相等的小网格。这种划分方法很明显是符合四叉树的,只不过这个四叉树每个节点要么有四个儿子,要么没有儿子。上面描述的网格是在x-z平面上,至此还没有考虑y坐标呢。等划分到一定标准的时候就