目录

问题

研究思路

代码实现


问题

为墙和屋顶贴上重复的贴图,为泳池的水面添加动态效果。

研究思路

(1)重复贴图

设置n*n贴图对应的纹理坐标,使用glTexParameteri设置纹理参数。其中GL_TEXTURE_WRAPT参数使用GL_REPEAT

(2)纹理的动态变化

利用纹理坐标的周期性变化实现

(3)opengl纹理的相关知识

1.使用纹理和载入纹理

就像我们曾经学习过的OpenGL光照、混合等功能一样。在使用纹理前,必须启用它。OpenGL支持一维纹理、二维纹理和三维纹理,可以使用以下语句来启用和禁用二维纹理:

     glEnable(GL_TEXTURE_2D);   // 启用二维纹理
     glDisable(GL_TEXTURE_2D); // 禁用二维纹理

使用纹理前,还必须载入纹理。利用glTexImage2D函数可以载入一个二维的纹理,该函数有多达九个参数(参数暂时不了解)。
第一个参数为指定的目标,这个参数将始终使用GL_TEXTURE_2D。
第二个参数为“多重细节层次”。
第三个参数有两种用法。在OpenGL 1.0,即最初的版本中,使用整数来表示颜色分量数目,例如:像素数据用RGB颜色表示,总共有红、绿、蓝三个值,因此参数设置为3,而如果像素数据是用RGBA颜色表示,总共有红、绿、蓝、alpha四个值,因此参数设置为4。而在后来的版本中,可以直接使用GL_RGB或GL_RGBA来表示以上情况,显得更直观(并带来其它一些好处,这里暂时不提)。注意:虽然我们使用Windows的BMP文件作为纹理时,一般是蓝色的像素在最前,其真实的格式为GL_BGR而不是GL_RGB,在数据的顺序上有所不同,但因为同样是红、绿、蓝三种颜色,因此这里仍然使用GL_RGB。(如果使用GL_BGR,OpenGL将无法识别这个参数,造成错误)
第四、五个参数是二维纹理像素的宽度和高度。

2、纹理坐标
当我们绘制一个三角形时,只需要指定三个顶点的颜色。三角形中其它各点的颜色不需要我们指定,这些点的颜色是OpenGL自己通过计算得到的。
在我们学习OpneGL光照时,法线向量、材质的指定,都是只需要在顶点处指定一下就可以了,其它地方的法线向量和材质都是OpenGL自己通过计算去获得。

纹理的使用方法也与此类似。只要指定每一个顶点在纹理图象中所对应的像素位置,OpenGL就会自动计算顶点以外的其它点在纹理图象中所对应的像素位置。

使用glTexCoord*系列函数来指定纹理坐标。这些函数的用法与使用glVertex*系列函数来指定顶点坐标十分相似。例如:glTexCoord2f(0.0f, 0.0f);指定使用(0, 0)纹理坐标。

glBegin( /* ... */ );
     glTexCoord2f( /* ... */ );   glVertex3f( /* ... */ );
     glTexCoord2f( /* ... */ );   glVertex3f( /* ... */ );
     /* ... */
glEnd();

3、纹理参数
在使用纹理前还有某些参数是必须设置的。
使用glTexParameter*系列函数来设置纹理参数。通常需要设置下面四个参数:
GL_TEXTURE_MAG_FILTER:指当纹理图象被使用到一个大于它的形状上时,有可能纹理图象中的一个像素会被应用到实际绘制时的多个像素。可选择的设置有GL_NEAREST和GL_LINEAR,前者表示“使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色”,后者表示“使用纹理中坐标最接近的若干个颜色,通过加权平均算法得到需要绘制的像素颜色”。
GL_TEXTURE_MIN_FILTER:指当纹理图象被使用到一个小于(或等于)它的形状上时可能纹理图象中的多个像素被应用到实际绘制时的一个像素。可选择的设置有GL_NEARESTGL_LINEAR,GL_NEAREST_MIPMAP_NEAREST,GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_NEAREST和GL_LINEAR_MIPMAP_LINEAR。
GL_TEXTURE_WRAP_S:指当纹理坐标的第一维坐标值大于1.0或小于0.0时,应该如何处理。基本的选项有GL_CLAMP和GL_REPEAT,前者表示“截断”,即超过1.0的按1.0处理,不足0.0的按0.0处理。后者表示“重复”,即对坐标值加上一个合适的整数(可以是正数或负数),得到一个在[0.0, 1.0]范围内的值,然后用这个值作为新的纹理坐标。如果不指定这个参数,则默认为GL_REPEAT。
GL_TEXTURE_WRAP_T:指当纹理坐标的第二维坐标值大于1.0或小于0.0时,应该如何处理。选项与GL_TEXTURE_WRAP_S类似,不再重复。如果不指定这个参数,则默认为GL_REPEAT。

设置参数的代码如下所示:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

代码实现

(1)将需要用到的bmp图片放在工程文件夹下,在代码中设置纹理编号。在初始化里加载启用这两个纹理

//定义两个纹理对象编号
GLuint texWall;
GLuint texRoof;
glEnable(GL_TEXTURE_2D);    // 启用纹理
texWall = load_texture("wall.bmp");  //加载纹理
texRoof = load_texture("roof.bmp");

(2)找到绘制屋顶与墙的代码,设置重复贴图。

墙壁的相关代码。

根据已给的墙壁坐标计算出纹理坐标对应的顶点坐标。

//左右墙壁
glEnable(GL_TEXTURE_2D);//启用纹理
	glBindTexture(GL_TEXTURE_2D, texWall);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//设置纹理参数
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(60, 10, 50);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(60, 10, 247);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(60, 160, 247);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(60, 160, 50);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(440, 10, 50);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(440, 10, 247);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(440, 160, 247);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(440, 160, 50);
//前后墙壁
	glTexCoord2f(0.0f, 0.0f); glVertex3f(60, 10, 50);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(60, 160, 50);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(440, 160, 50);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(440, 10, 50);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(60, 10, 240);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(60, 160, 240);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(440, 160, 240);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(440, 10, 240);
	glEnd();
	glDisable(GL_TEXTURE_2D);

屋顶的相关代码

因为屋顶由几个梯形组成,根据画梯形的代码可知梯形顶点放在二维数组中,为了简便,将纹理绘制直接放在绘制梯形的代码中。

glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texRoof);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//重复绘制参数
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(san[0][0],san[0][1] , san[0][2]);//梯形六个面
	glTexCoord2f(0.0f, 10.0f); glVertex3f(san[1][0], san[1][1], san[1][2]);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(san[2][0], san[2][1], san[2][2]);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(san[3][0], san[3][1], san[3][2]);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(san[4][0], san[4][1], san[4][2]);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(san[5][0], san[5][1], san[5][2]);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(san[6][0], san[6][1], san[6][2]);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(san[7][0], san[7][1], san[7][2]);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(san[1][0], san[1][1], san[1][2]);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(san[5][0], san[5][1], san[5][2]);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(san[4][0], san[4][1], san[4][2]);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(san[0][0], san[0][1], san[0][2]);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(san[3][0], san[3][1], san[3][2]);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(san[7][0], san[7][1], san[7][2]);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(san[6][0], san[6][1], san[6][2]);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(san[2][0], san[2][1], san[2][2]);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(san[2][0], san[2][1], san[2][2]);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(san[6][0], san[6][1], san[6][2]);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(san[7][0], san[7][1], san[7][2]);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(san[3][0], san[3][1], san[3][2]);
	glTexCoord2f(0.0f, 0.0f); glVertex3f(san[2][0], san[2][1], san[2][2]);
	glTexCoord2f(0.0f, 10.0f); glVertex3f(san[6][0], san[6][1], san[6][2]);
	glTexCoord2f(10.0f, 10.0f); glVertex3f(san[5][0], san[5][1], san[5][2]);
	glTexCoord2f(10.0f, 0.0f); glVertex3f(san[1][0], san[1][1], san[1][2]);
	glEnd();
	glDisable(GL_TEXTURE_2D);

(3)纹理的动态变化

设置一个定时改变的变量

float ttrans;
float m_Speed//变化速度
ttrans = ttrans + 0.01f * m_Speed / 50.0f;	//周期变化
if (ttrans == 1.0f) ttrans = 0.0f;


glEnable(GL_TEXTURE_2D);   //泳池纹理
glBindTexture(GL_TEXTURE_2D, texPoor);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(490, 16, 75);//用变量设置纹理坐标
glTexCoord2f(0.0f, ttrans); glVertex3f(490, 16, 425);
glTexCoord2f(ttrans, ttrans); glVertex3f(640, 16, 425);
glTexCoord2f(ttrans, 0.0f); glVertex3f(640, 16, 75);
glEnd();
glDisable(GL_TEXTURE_2D);

Invalidate(FALSE);//刷新重绘