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

Nehe SDK

第23课

球面映射:

这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围的场景一样。

球体环境映射是一个创建快速金属反射效果的方法,但它并不像真实世界里那么精确!我们从18课的代码开始来创建这个教程,教你如何创建这种效果。

在我们开始之间,看一下红宝书中的介绍。它定义球体环境映射为一幅位于无限远的图像,把它映射到球面上。

在Photoshop中创建一幅球体环境映射图。

首先,你需要一幅球体环境映射图,用来把它映射到球体上。在Photoshop中打开一幅图并选择所有的像素,创建它的一个复制。
接着,我们把图像变为2的幂次方大小,一般为128x128或256x256。
最后使用扭曲(distort)滤镜,并应用球体效果。然后把它保存为*.bmp文件。

我们并没有添加任何全局变量,只是把纹理组的大小变为6,以保存6幅纹理。

GLuint	texture[6];								// 保存6幅纹理 
下面我们要做的就是载入这些纹理
int LoadGLTextures()								
{
	int Status=FALSE;							

	AUX_RGBImageRec *TextureImage[2];						// 创建纹理的保存空间

	memset(TextureImage,0,sizeof(void *)*2);  		         			// 清空为0

	// 载入*.bmp图像
	if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) &&				// 背景图
		(TextureImage[1]=LoadBMP("Data/Reflect.bmp")))			// 反射图(球形纹理图)
	{
		Status=TRUE;							

		glGenTextures(6, &texture;[0]);					// 创建6个纹理

		for (int loop=0; loop<=1; loop++)
		{
			// 创建临近点过滤纹理图
			glBindTexture(GL_TEXTURE_2D, texture[loop]);			// 创建纹理0和1
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
			glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
				0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

			// 创建线形过滤纹理图
			glBindTexture(GL_TEXTURE_2D, texture[loop+2]);		// 创建纹理2,3
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
				0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

			// 创建线形Mipmap纹理图
			glBindTexture(GL_TEXTURE_2D, texture[loop+4]);		// 创建纹理4,5
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
			gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
				GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
		}
		for (loop=0; loop<=1; loop++)
		{
	        if (TextureImage[loop])						// 如果图像存在则清除
		    {
			        if (TextureImage[loop]->data)			
				    {
					        free(TextureImage[loop]->data);	
					}
					free(TextureImage[loop]);		
			}
		}
	}

	return Status;				
}
我们对立方体的绘制代码做了一些小的改动,把法线的范围从[-1,1]缩放到[-0.5,0.5]。如果法向量太大的话,会产生一些块状效果,影响视觉效果。
GLvoid glDrawCube()
{
		glBegin(GL_QUADS);
		// 前面
		glNormal3f( 0.0f, 0.0f, 0.5f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
		// 背面
		glNormal3f( 0.0f, 0.0f,-0.5f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
		// 上面
		glNormal3f( 0.0f, 0.5f, 0.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
		// 下面
		glNormal3f( 0.0f,-0.5f, 0.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
		// 右面
		glNormal3f( 0.5f, 0.0f, 0.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
		// 左面
		glNormal3f(-0.5f, 0.0f, 0.0f);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
	glEnd();
}
在初始化OpenGL中,我们添加一些新的函数来使用球体纹理映射。
下面的代码让OpenGL自动为我们计算使用球体映射时,顶点的纹理坐标。
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);			// 设置s方向的纹理自动生成
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);			// 设置t方向的纹理自动生成
我们几乎完成了所有的工作!接下来要做的就是就是绘制渲染,我删除了一些二次几何体,因为它们的视觉效果并不好。当然我们需要OpenGL为这些几何体自动生成坐标,接着选择球体映射纹理并绘制几何体。最后把OpenGL状态设置正常模式。
int DrawGLScene(GLvoid)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			
	glLoadIdentity();							// 重置视口

	glTranslatef(0.0f,0.0f,z);

	glEnable(GL_TEXTURE_GEN_S);						// 自动生成s方向纹理坐标
	glEnable(GL_TEXTURE_GEN_T);						// 自动生成t方向纹理坐标

	glBindTexture(GL_TEXTURE_2D, texture[filter+(filter+1)]);		// 绑定纹理
	glPushMatrix();
	glRotatef(xrot,1.0f,0.0f,0.0f);
	glRotatef(yrot,0.0f,1.0f,0.0f);
	switch(object)
	{
	case 0:
		glDrawCube();
		break;
	case 1:
		glTranslatef(0.0f,0.0f,-1.5f);					// 创建圆柱
		gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);			
		break;
	case 2:
		gluSphere(quadratic,1.3f,32,32);					// 创建球
		break;
	case 3:
		glTranslatef(0.0f,0.0f,-1.5f);					// 创建圆锥
		gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);			
		break;
	};

	glPopMatrix();
	glDisable(GL_TEXTURE_GEN_S);						// 禁止自动生成纹理坐标
	glDisable(GL_TEXTURE_GEN_T);					

	xrot+=xspeed;
	yrot+=yspeed;
	return TRUE;								// 成功返回
}
最后我们使用空格来切换各个不同的几何体
				if (keys[' '] && !sp)
				{
					sp=TRUE;
					object++;
					if(object>3)
						object=0;
				}

我们成功了!现在你可以使用环境映射纹理做一些非常棒的特效了。我想做一个立方体环境映射的例子,但我现在的显卡不支持这种特效,所以只有等到以后了。

谢谢,并祝你好运!

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

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

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

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

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

源码 RAR格式

< 第22课 第24课 >