OpenGL可以把纹理映射到指定的图形的表面上。
简单一点的,就是给平面映射纹理,比如一个四边形,一个长方体的6个面,都关于将一个位图作为纹理映射到某个或者多个面上,可以学习Jeff Molofee的OpenGL系列对于指定的多个纹理,要根据自己的需要映射到不同的面上,需要对位图创建一个数组,用来存储位图的名称,然后在初始化Op成多个纹理存储到一个纹理数组中,接着就可以指定绘制的某个面,对该指定的面进行纹理下面,在的Jeff Molofee教程的第六课的基础上,实现对6个面分别进行不同的纹理映射准备工作就是制作6幅不同的位图,如图所示:关键代码及其说明如下。
创建全局纹理数组GLuint texture[6]; // 创建一个全局的纹理数组,用来存储将位图转换之后得到的纹理,对应于立方加载位图文件加载位图,也就是把位图读取到内存空间,实现纹理的创建,加载位图的函数说明一下AUX_RGBImageRec *LoadBMP(char *Filename) // 根据位图文件的名称进行加载{FILE *File=NULL; // 文件指针if (!Filename) // 如果没有指定位图文件名称就返回NULL{return NULL;}File=fopen(Filename,"r"); // 根据指定的位图文件名称,打开该位图文件if (File) // 如果位图文件存在{fclose(File); // 因为只是需要判断问题是否存在,而不需要对位图文件进行写操作,所以关闭位return auxDIBImageLoad(Filename); // 其实,只需要一个真正存在的位图文件的名称,实现加载位图文}return NULL; // 位图文件加载失败就返回NULL}上面实现加载位图的函数中,AUX_RGBImageRec是glaux.h中定义的类型,该类型的定义如下/*** RGB Image Structure*/typedef struct _AUX_RGBImageRec {GLint sizeX, sizeY;unsigned char *data;} AUX_RGBImageRec;首先,AUX_RGBImageRec类型是一个RGB图像结构类型。
该结构定义了三个成员:sizeX ——图像的宽度;sizeY ——图像的高度;data; ——图形所包含的数据,其实也就是该图形在内存中的像素数据的一个指针。
AUX_RGBImageRec类型的变量描述了一幅图像的特征。
上述函数中,调用了glaux.h库文件中的auxDIBImageLoad函数,其实它是一个宏,函数原型为auxRGBImageLoadW(LPCWSTR在该库文件中找到它的定义,如下所示:/* AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCTSTR); */#ifdef UNICODE#define auxRGBImageLoad auxRGBImageLoadW#else#define auxRGBImageLoad auxRGBImageLoadA#endifAUX_RGBImageRec * APIENTRY auxRGBImageLoadA(LPCSTR);AUX_RGBImageRec * APIENTRY auxRGBImageLoadW(LPCWSTR);#ifdef UNICODE#define auxDIBImageLoad auxDIBImageLoadW#else#define auxDIBImageLoad auxDIBImageLoadA#endifAUX_RGBImageRec * APIENTRY auxDIBImageLoadA(LPCSTR);AUX_RGBImageRec * APIENTRY auxDIBImageLoadW(LPCWSTR);宏auxDIBImageLoad实现的功能就是:根据指定的位图名称,将该位图的信息加载到内存中,以便用来创建纹理并加载纹理用于创建并加载纹理的函数为LoadGLTextures,实现如下所示:int LoadGLTextures() // 根据加载的位图创建纹理{int Status=FALSE; // 指示纹理创建是否成功的标志AUX_RGBImageRec *TextureImage[6]; // 创建一个纹理图像数组,这里指定数组大小为memset(TextureImage,0,sizeof(void *)*6); // 初始化纹理图像数组,为其分配内存char *pictures[] = { // 创建一个位图名称数组,对应6幅位图"Data/No1.bmp","Data/No2.bmp","Data/No3.bmp","Data/No4.bmp","Data/No5.bmp","Data/No6.bmp"};for(int i=0; i<6; i++) // 遍历位图名称数组,根据位图名称分别生成{if (TextureImage[i]=LoadBMP(pictures[i])) // 加载位图i成功,修改状态标志变量Status为{Status=TRUE;glGenTextures(1, &texture[i]); // 为第i个位图创建纹理glBindTexture(GL_TEXTURE_2D, texture[i]); // 将生成的纹理的名称绑定到指定的纹理glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[i]->sizeX, TextureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNEDglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);}if (TextureImage[i]) // 释放位图数组占用的内存空间{if (TextureImage[i]->data){free(TextureImage[i]->data);}free(TextureImage[i]);}}return Status; // 创建纹理并加载,返回成功或者失败的标志Status}上述函数是创建和加载纹理的核心实现。
1、glGenTextures函数其中,调用了glGenTextures函数,查看MSDN可以看到,声明如下所示:void glGenTextures(GLsizei n,GLuint * textures);函数参数的含义:n ——生成的纹理的名称的个数;textures ——生成的纹理名称所存储位置的指针,也就是一个纹理数组的内存地址,或者说是数组首元函数被调用,会生成一系列纹理的名字,并存储到指定的数组中。
2、glBindTexture函数glBindTexture函数实现了将调用glGenTextures函数生成的纹理的名字绑定到对应的目标纹理上。
该函数void glBindTexture(GLenum target,GLuint texture);函数参数的含义:target ——纹理被绑定的目标,它只能取值GL_TEXTURE_1D或者GL_TEXTURE_2D;texture ——纹理的名称,并且,该纹理的名称在当前的应用中不能被再次使用。
3、glTexImage2D函数调用glTexImage2D函数,用来指定二维纹理图像。
该函数的声明如下所示:void glTexImage2D(GLenum target,GLint level,GLint components,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid *pixels);函数参数的含义:target ——指定目标纹理,必须为GL_TEXTURE_2D;level ——指定图像级别的编号,0表示基本图像,其它可以参考MSDN;components ——纹理中颜色组件的编号,可是是1或2或3或4;width ——纹理图像的宽度;height ——纹理图像的高度;border ——纹理图像的边框宽度,必须是0或1;format ——指定像素数据的格式,一共有9个取值:GL_COLOR_INDEX、GL_RED、GL_GREEN、GL_BLUE、GL_ALPHA、GL_REXT、GL_LUMINANCE、GL_LUMINANCE_ALPHA ,具体含义可以参考MSDN;type ——像素数据的数据类型,取值可以为GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORFLOAT;pixels ——内存中像素数据的指针。
4、glTexParameteri函数glTexParameteri函数或者glTexParameterf函数用来设置纹理参数,声明如下所示:void glTexParameterf(GLenum target,GLenum pname,GLfloat param);void glTexParameteri(GLenum target,GLenum pname,GLint param);函数参数的含义:target ——目标纹理,必须为GL_TEXTURE_1D或GL_TEXTURE_2D;pname ——用来设置纹理映射过程中像素映射的问题等,取值可以为:GL_TEXTURE_MIN_FILTER、GL_TEXTURE_MAG_FILTEWRAP_T,详细含义可以查看MSDN;param ——实际上就是pname的值,可以参考MSDN。
另外,该类函数还有两个:void glTexParameterfv(GLenum target,GLenum pname,const GLfloat *params);void glTexParameteriv(GLenum target,GLenum pname,const GLint *params);上述程序中调用如下:glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);功能就是实现线形滤波的功能,当纹理映射到图形表面以后,如果因为其它条件的设置导致纹理不能更好地显示的时候,进行过掉显示不正常的纹理像素。