NeHe OpenGL教程第三十四课,DancingWind翻译

Nehe SDK

第34课

从高度图生成地形:

这一课将教会你如何从一个2D的灰度图创建地形

欢迎来到新的一课,Ben Humphrey写了这一课的代码,它是基于第一课所写的。

在这一课里,我们将教会你如何使用地形,你将知道高度图这个概念。

下面我们来定义一些全局变量,MAP_SIZE是你使用的高度图的大小,在这一课里我们使用1024*1024的地图。STEP_SIZE设置高度图中相邻顶点之间的距离。HEIGHT_RATIO设置在高度方向的缩放比例,越大地形看起来越陡峭。bRender设置使用多边形还是线绘制地形。
#define		MAP_SIZE	1024				
#define		STEP_SIZE	16					// 相邻顶点的距离
#define		HEIGHT_RATIO	1.5f				
bool		bRender = TRUE;					// true为多边形渲染,false为线渲染
下面的代码用来保存高度数据
BYTE g_HeightMap[MAP_SIZE*MAP_SIZE];				// 保存高度数据

float scaleValue = 0.15f;					// 地形的缩放比例
下面的函数从文件中加载高度数据
// 从*.raw文件中加载高度数据
void LoadRawFile(LPSTR strName, int nSize, BYTE *pHeightMap)
{
	FILE *pFile = NULL;

	// 打开文件
	pFile = fopen( strName, "rb" );

	// 如果文件不能打开
	if ( pFile == NULL )
	{
		// 提示错误,退出
		MessageBox(NULL, "不能打开高度图文件", "错误", MB_OK);
		return;
	}
	// 读取文件数据到pHeightMap数组中
	fread( pHeightMap, 1, nSize, pFile );

	// 读取是否成功
	int result = ferror( pFile );

	// 如果不成功,提示错误退出
	if (result)
	{
		MessageBox(NULL, "读取数据失败", "错误", MB_OK);
	}

	// 关闭文件
	fclose(pFile);
}
InitGL函数基本没有变化,只是加入了加载高度图的函数
// 载入1024*1024的高度图道g_HeightMap数组中

	LoadRawFile("Data/Terrain.raw", MAP_SIZE * MAP_SIZE, g_HeightMap);
下面的函数返回(x,y)点的高度
int Height(BYTE *pHeightMap, int X, int Y)			// 下面的函数返回(x,y)点的高度
{
	int x = X % MAP_SIZE;				// 限制X的值在0-1024之间
	int y = Y % MAP_SIZE;				// 限制Y的值在0-1024之间

	if(!pHeightMap) return 0;				// 检测高度图是否存在,不存在则返回0
返回(x,y)的高度
	return pHeightMap[x + (y * MAP_SIZE)];			// 返回(x,y)的高度
}
按高度设置顶点的颜色,越高的地方越亮
void SetVertexColor(BYTE *pHeightMap, int x, int y)			// 按高度设置顶点的颜色,越高的地方越亮
{								
	if(!pHeightMap) return;					

	float fColor = -0.15f + (Height(pHeightMap, x, y ) / 256.0f);

	// 设置顶点的颜色
	glColor3f(0.0f, 0.0f, fColor );
}
下面的函数在OpenGL中,根据高度图渲染输出地形
void RenderHeightMap(BYTE pHeightMap[])				// 根据高度图渲染输出地形
{
	int X = 0, Y = 0;						// 设置循环变量
	int x, y, z;						

	if(!pHeightMap) return;					// 确认高度图存在
	if(bRender)						// 选择渲染模式
		glBegin( GL_QUADS );				// 渲染为四边形
	else
		glBegin( GL_LINES );				// 渲染为直线

下面的函数求得每一点的坐标和颜色,调用OpenGL渲染
	for ( X = 0; X < MAP_SIZE; X += STEP_SIZE )
		for ( Y = 0; Y < MAP_SIZE; Y += STEP_SIZE )
		{
			// 绘制(x,y)处的顶点
	// 获得(x,y,z)坐标
			x = X;
			y = Height(pHeightMap, X, Y );
			z = Y;

			// 设置顶点颜色
			SetVertexColor(pHeightMap, x, z);

			glVertex3i(x, y, z);			// 调用OpenGL绘制顶点的命令

			// 绘制(x,y+1)处的顶点
			x = X;
			y = Height(pHeightMap, X, Y + STEP_SIZE );
			z = Y + STEP_SIZE ;
			SetVertexColor(pHeightMap, x, z);
			glVertex3i(x, y, z);		

	// 绘制(x+1,y+1)处的顶点
			x = X + STEP_SIZE;
			y = Height(pHeightMap, X + STEP_SIZE, Y + STEP_SIZE );
			z = Y + STEP_SIZE ;
			SetVertexColor(pHeightMap, x, z);
			glVertex3i(x, y, z);			

			// 绘制(x+1,y)处的顶点
			x = X + STEP_SIZE;
			y = Height(pHeightMap, X + STEP_SIZE, Y );
			z = Y;
			SetVertexColor(pHeightMap, x, z);
			glVertex3i(x, y, z);		
		}
	glEnd();
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);			// 重置颜色
}
DrawGLScene函数基本没变化,只是设置了视点和缩放系数,调用上面的函数绘制出地形。
// 设置视点
	gluLookAt(212, 60, 194,  186, 55, 171,  0, 1, 0);	
	glScalef(scaleValue, scaleValue * HEIGHT_RATIO, scaleValue);  
	RenderHeightMap(g_HeightMap);				// 渲染高度图

	return TRUE;			
}
WndProc()函数基本没有变化,只是加入了单击左键的相应函数
		case WM_LBUTTONDOWN:				// 是否单击鼠标左键
		{
			bRender = !bRender;			// 改变渲染模式
			return 0;					// 返回
		}
上面就是所有绘制地形的代码了,简单吧。

希望你喜欢这个教程!

版权与使用声明:
我是个对学习和生活充满激情的普通男孩,在网络上我以DancingWind为昵称,我的联系方式是[email protected],如果你有任何问题,都可以联系我。

引子
网络是一个共享的资源,但我在自己的学习生涯中浪费大量的时间去搜索可用的资料,在现实生活中花费了大量的金钱和时间在书店中寻找资料,于是我给自己起了个昵称DancingWind,其意义是想风一样从各个知识的站点中吸取成长的养料。在飘荡了多年之后,我决定把自己收集的资料整理为一个统一的资源库。

版权声明
所有DancingWind发表的内容,大多都来自共享的资源,所以我没有资格把它们据为己有,或声称自己为这些资源作出了一点贡献。故任何人都可以复制,修改,重新发表,甚至以自己的名义发表,我都不会追究,但你在做以上事情的时候必须保证内容的完整性,给后来的人一个完整的教程。最后,任何人不能以这些资料的任何部分,谋取任何形式的报酬。

发展计划
在国外,很多资料都是很多人花费几年的时间慢慢积累起来的。如果任何人有兴趣与别人共享你的知识,我很欢迎你与我联系,但你必须同意我上面的声明。

感谢
感谢我的母亲一直以来对我的支持和在生活上的照顾。
感谢我深爱的女友田芹,一直以来默默的在精神上和生活中对我的支持,她甚至把买衣服的钱都用来给我买书了,她真的是我见过的最好的女孩,希望我能带给她幸福。

源码 RAR格式

< 第33课 第35课 >