在使用纹理的时候,有时候会出现超过纹理边界的问题,GL_TEXTURE_WRAP系列参数用来设置当这些超出边界时应该怎样处理。下面结合代码和代码产生的结果进行说明每个参数的作用。代码基于红宝书——《opengl编程指南》7th上的代码,自己再稍微改改,用来产生各种效果。
#include "stdafx.h" #include <GL/glew.h> #include <GL/glut.h> #define checkImageWidth 64 #define checkImageHeight 64 static GLubyte checkImage[checkImageHeight][checkImageWidth][4]; static GLuint texName; //产生纹理的函数 void makeCheckImage(void) { int i, j, c; for ( i = 0; i < checkImageHeight; ++i ) for( j = 0; j < checkImageWidth; ++j ) { c = ((( i & 0x8) == 0 )^ (( j & 0x8)) == 0) * 255; checkImage[i][j][0] = ( GLubyte )c; checkImage[i][j][1] = ( GLubyte )c; checkImage[i][j][2] = ( GLubyte )c; checkImage[i][j][3] = ( GLubyte )255; } } void init( void ) { glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); makeCheckImage(); glPixelStorei( GL_UNPACK_ALIGNMENT,1); glGenTextures(1,&texName); glBindTexture(GL_TEXTURE_2D,texName); // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); //GL_CLAMP GL_CLAMP_TO_BORDER // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); //GL_REPEAT GL_CLAMP_TO_EDGE glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); float color[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); 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,GL_RGBA,checkImageWidth,checkImageHeight, 0,GL_RGBA,GL_UNSIGNED_BYTE,checkImage); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glBindTexture(GL_TEXTURE_2D,texName); glBegin( GL_QUADS ); glTexCoord2f( 0.0, 0.0); glVertex2f( -1.0, -1.0); glTexCoord2f( 0.0, 1.8 ); glVertex2f( -1.0, 1.0 ); glTexCoord2f( 1.8, 1.8 ); glVertex2f( 1.0, 1.0 ); glTexCoord2f( 1.8, 0.0 ); glVertex2f ( 1.0, -1.0 ); glEnd( ); glFlush(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode( GLUT_SINGLE|GLUT_RGBA); glutInitWindowSize(512, 512); glutInitWindowPosition(0, 0); glutCreateWindow("棋盘纹理"); glutDisplayFunc(display); glutIdleFunc(display); init(); glutMainLoop(); return 0; }
1. 首先是GL_REPEAT,这个比较简单,就是重复边界的纹理。产生的效果如下:
2. GL_CLAMP采用这种模式是,opengl就在一个2X2的加权纹理单元数组中使用取自边框的纹理单元。这时候的边框如果没有设置的话,应该就是原纹理的边界的像素值。
3. GL_CLAMP_TO_EDGE,在这种模式下,边框始终被忽略。位于纹理边缘或者靠近纹理边缘的纹理单元将用于纹理计算,但不使用纹理边框上的纹理单元。在实验中,不管有没有设置边框,都与与上面的GL_CLAMP结果相同。在下面的参考文献中给了一个解释:因为很多硬件并不支持边界处理,所以实现GL_CLAMP_TP_EDGE和GL_CLAMP的效果好象是一样的。
4. GL_CLAMP_TO_BORDER如果纹理坐标位于范围[0,1]之外,那么只用边框纹理单元(如果没有边框,则使用常量边框颜色,我想常量边框颜色就是黑色)用于纹理。在靠近纹理坐标边缘的地方,无论是边框还是纹理内部都可能根据一个2X2的数组进行采样。
5. 在GL_CLAMP_TO_BORDER的基础上使用上面的代码设置GL_TEXTURE_BORDER_COLOR(设置边框颜色为红色),可以得到下面的结果:
参考文献:
1.http://blog.csdn.net/superkris/article/details/5567593
2.http://blog.163.com/ray_jun/blog/static/167053642201162493648552/
3.《opengl编程指南》第七版9.6.2节——重复和截取纹理