看了《OpenGL编程指南》第九章纹理贴图之后,一开始还对纹理的理解思路还是有点乱,后面不断的阅读别人的博客之后才慢慢的有了更加清晰的认识,于是通过博客再进一步理顺一下思路。
1.关于纹理的一些基本概念理解
纹理:简单的说,纹理就是矩形的数据数组。例如颜色、亮度数据等,之所以复杂,是因为矩形纹理可以映射到非矩形的区域。
纹理映射:就是要实现如何把纹理像素映射到几何对象的每个点。
2.纹理贴图的基本步骤
2.1. 创建纹理,并为它指定一个纹理
在书中并没有讲到关于加载图片作为纹理的例子,通篇都是通过makeImage()函数为每个像素点赋值不同的颜色生成纹理,所以最后给出一个关于加载纹理的例子。
纹理的定义主要通过下面这个函数:
void glTexImage2D(GLenum target,GLint level,GLint components,GLsizei width, glsizei height,GLint border,GLenum format,GLenum type, const GLvoid *pixels);//定义2D纹理
关于1D、2D和3D纹理,其实3D纹理稍微难理解一点,书中的解释是可以看成是一层层的二维子图像矩形构成的。
而声明一个位图作为纹理,在调用glTextImage**之前还需要用的两个函数:
1.glGenTextures:为这个纹理对象申明一个名称,其实就是ID。两个参数:第一个是你要申请名称的个数,第二个是一个GLuint类型的数组指针
2.glBindTexture:这个函数有两个参数,第一个是要绑定的纹理对象的类型,第二个是要绑定 的纹理对象的名称,也就是glGenTextures函数申请的名字并返回到数组里面的数值。
2.2设置过滤和重复
1.过滤
一般来说,纹理图像为正方形或长方形。但当它映射到一个多边形或曲面上并变换到屏幕坐标时,纹理的单个纹素很少对应于屏幕图像上的象素。根据所用变换和所用纹理映射,屏幕上单个象素可以对应于一个纹素的一小部分(即放大)或一大批纹素(即缩小)。
放大和缩小通过以下函数实现:
glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
这里主要是第三个参数,GL_NEAREST常常采用双线性插值。
2.重复
纹理坐标可以超出(0, 1)范围,并且在纹理映射过程中可以重复映射或约简映射。在重复映射的情况下,纹理可以在s,t方向上重复,即:
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
若将参数GL_REPEAT改为GL_CLAMP,则所有大于1的纹素值都置为1,所有小于0的值都置为0。
3.提供纹理坐标和几何坐标
在绘制纹理映射场景时,不仅要给每个顶点定义几何坐标,而且也要定义纹理坐标。经过多种变换后,几何坐标决定顶点在屏幕上绘制的位置,而纹理坐标决定纹理图像中的哪一个纹素赋予该顶点。并且顶点之间的纹理坐标插值与基础篇中所讲的平滑着色插值方法相同。
1.指定纹理坐标
将纹理坐标与顶点坐标绑定,主要用到的接口是glTexCoord()。
void glTexCoord{1234}{sifd}(TYPE coords);
void glTexCoord{1234}{sifd}v(const TYPE* coords);
以二维纹理图片为例,举个简单的例子,画一个四边形,并且将纹理坐标映射到这个四边形上面,如下面的代码片段所示:
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(3.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(3.0f, 3.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 3.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();
2.坐标自动产生
在某些场合(环境映射等)下,为获得特殊效果需要自动产生纹理坐标,并不要求为用函数gltexCoord*()为每个物体顶点赋予纹理坐标值。OpenGL提供了自动产生纹理坐标的函数,其如下:
void glTexGen{if}[v](GLenum coord,GLenum pname,TYPE param);
4.清除纹理对象
清除纹理对象的绑定,它们的数据可能还保存在纹理资源的,但是如果纹理资源有限的话,删除纹理显然是释放纹理资源有效的方法之一,清除纹理对象的接口是glDeleteTextures()。
3.关于多重纹理
在进行标准的纹理处理时,一次是把1幅图像应用到1个多边形上。多重纹理允许应用几个纹理,在纹理操作管线中把它们逐个应用到一个多边形上。
3.1使用步骤
- 建立每个纹理单元的纹理状态,包括纹理图像数据,过滤器,环境,矩阵,纹理函数生成方式等。
- 可以用glMultiTexCoord*()函数规定每个顶点上不同纹理单元的纹理坐标。下面的代码片段演示该函数的用法:
glBegin(GL_TRIANGLES);
glMultiTexCoord2f(GL_TEXTURE0,0.0f,0.0f);
glMultiTexCoord2f(GL_TEXTURE1,1.0f,0.0f);
glVertex2f(0.0f,0.0f);
glMultiTexCoord2f(GL_TEXTURE0,0.5f,1.0f);
glMultiTexCoord2f(GL_TEXTURE1,0.5f,0.0f);
glVertex2f(50.0f,100.0f);
glMultiTexCoord2f(GL_TEXTURE0,1.0f,0.0f);
glMultiTexCoord2f(GL_TEXTURE1,1.0f,1.0f);
glVertex2f(100.0f,0.0f);
glEnd();
3.恢复使用单个纹理。在使用多重纹理时,如果想要恢复使用单个纹理,需要禁用除纹理单位0之外的所有纹理单位。如下面的代码片段所示:
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);