1、Comment u1: glGenTextures()将本次由 LoadBMP()函数中auxDIBImageLoad()载入内存的位图纹理进行编号,将本次编号得到的纹理号存储在 texturei中创建第六个 OpenGL程序多面体与纹理 GLuinttexture1; / Storage For One Texture ( NEW )LRESULTCALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);/ Declaration For WndProcAUX_RGBImageRec *LoadBMP(char *Filename) / Loads A Bit
2、map ImageFILE *File=NULL; / File Handleif (!Filename) / Make Sure A Filename Was Givenreturn NULL; / If Not Return NULLFile=fopen(Filename,“r“); / Check To See If The File Existsif (File) / Does The File Exist?fclose(File); / Close The Handlereturn auxDIBImageLoad(Filename); / Load The Bitmap And Re
3、turn A Pointerreturn NULL; / If Load Failed Return NULLint LoadGLTextures() / Load Bitmaps And Convert To Texturesint Status=FALSE; / Status IndicatorAUX_RGBImageRec *TextureImage1; / Create Storage Space For The Texturememset(TextureImage,0,sizeof(void *)*1); / Set The Pointer To NULL/ Load The Bit
4、map, Check For Errors, If Bitmaps Not Found Quitif (TextureImage0=LoadBMP(“Data/NeHe.bmp“)Status=TRUE; / Set The Status To TRUEglGenTextures(1, / Create The Texture/ Typical Texture Generation Using Data From The BitmapglBindTexture(GL_TEXTURE_2D, texture0);glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureI
5、mage0-sizeX, TextureImage0-sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage0-data);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);多面体的创建还是利用上面的程序,没有使用新添加的函数:一个多面体是由多个平面组成的。程序中只是创建了个金字塔椎体:这个空间三维图形主要是由四个三角形和一个矩形组成的封闭的多面体。所以
6、,只是在绘制三角形的基础上多添加了相应封闭图形的坐标的位置添加三角形和矩形。说到纹理是,NeHe 教程中有下面一段话需要注意:关于用作纹理的图像我想有几点十分重要,并且您必须明白。此图像的宽和高必须是 2 的 n 次方;宽度和高度最小必须是 64 象素;并且出于兼容性的原因,图像的宽度和高度不应超过 256 象素。如果您的原始素材的宽度和高度不是 64,128,256 象素的话,使用图像处理软件重新改变图像的大小。可以肯定有办法能绕过这些限制,但现在我们只需要用标准的纹理尺寸。 纹理贴图使用到了中不同的方式进行纹理图形的加载。一种是在 glaux 库的基础上,采用auxDIBImageLoad
7、 函数进行加载位图到相应的纹理存储空间;一种是采用微软的 api 函数BITMAPINFOHEADER 加载到相应的 BITMAPINFOHEADER 变量在存储到相应的纹理存储空间中。下面是 auxDIBImageLoad 函数的介绍:auxDIBImageLoadauxDIBImageLoad 函数,其实它是一个宏,函数原型为 auxRGBImageLoadW(LPCWSTR)或者auxRGBImageLoadA(LPCSTR),可以在该库文件中找到它的定义,如下所示:/* AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCTSTR); */#if
8、def 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 auxDIBImag
9、eLoadA#endifAUX_RGBImageRec * APIENTRY auxDIBImageLoadA(LPCSTR);AUX_RGBImageRec * APIENTRY auxDIBImageLoadW(LPCWSTR);宏 auxDIBImageLoad 实现的功能就是:根据指定的位图名称,将该位图的信息加载到内存中,以便用来创建成为纹理。接下来是 auxDIBImageLoad 函数的返回值的介绍:AUX_RGBImageRectypedef struct _AUX_RGBImageRec GLint sizeX, sizeY;unsigned char *data; AUX_
10、RGBImageRec;首先,AUX_RGBImageRec 类型是一个 RGB 图像结构类型。该结构定义了三个成员:sizeX 图像的宽度;sizeY 图像的高度;data; 图形所包含的数据,其实也就是该图形在内存中的像素数据的一个指针。AUX_RGBImageRec 类型的变量描述了一幅图像的特征。下面是使用 microsoft 来加载位图的:需要说明的是这种方式加载的位图需要符合下面的标准:此图像的宽和高必须是 2 的 n 次方;图像的宽度和高度必须符合下面的形式,(宽和高可以调换):eg. 64x64, 128x128, 256x128, etc. 宽和高的最小限制应该是从开始,反正
11、我试了从开始的没有问题。还有就是图像的宽高比例不能超过 256x256.这个原因还没有找到,以后我会进行分析。主要使用到的是一些 c 库函数还有就是 BITMAPINFOHEADER、BITMAPFILEHEADER 这连个结构体,先看看 BITMAPINFOHEADER 这个结构体的内容:This structure contains information about the dimensions and color format of a device-independent bitmap (DIB). /bitmapinfoheader 结构包含了一个设备不相关的位图(DIB )的尺寸
12、和颜色信息格式。typedef struct tagBITMAPINFOHEADER DWORD biSize;LONG biWidth;LONG biHeight;WORD biPlanes;WORD biBitCount;DWORD biCompression;DWORD biSizeImage;/LONG biXPelsPerMeter;LONG biYPelsPerMeter;DWORD biClrUsed;DWORD biClrImportant; BITMAPINFOHEADER;接着看看 BITMAPFILEHEADER 这个结构体的内容:This structure conta
13、ins information about the type, size, and layout of a file that containing a device-independent bitmap (DIB). typedef struct tagBITMAPFILEHEADER WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; BITMAPFILEHEADER; 为了是本篇文章的结构不会很乱,这两个结构体的具体解释我会放到另外一个帖子上面来。具体步骤是使用 fopen 函数将
14、位图文件读取到一个 FILE 里面,然后使用 fread 函数叫位图文件的文件头信息读到一个 BITMAPFILEHEADER 对象里面,接着是判断这个文件是否是位图文件,if (bmpFile.bfType != 0x4D42)这句很重要,他就是判断使用的文件是否是位图文件 。如果是位图文件,那么将进行以下的操作。使用 fread 函数将位图文件读取到一个 BITMAPINFOHEADER 对象里面,文件内容保存到BITMAPINFOHEADER 对象里面以后可以关闭 FILE 文件对象了。定位位图文件的内容,拷贝到一个unsigned char 指针里面,在 unsigned char 对
15、象里面对位图进行一定的转换操作,使之转换成为像上面glaux 库中操作返回的位图信息。这里需要有点时间进行深入的研究。 接下来是纹理的创建、纹理的绑定、位图映射到纹理存储空间、滤波的使用、纹理映射到坐标点和启用纹理。纹理的创建glGenTextures其中,调用了 glGenTextures 函数,查看 MSDN 可以看到,声明如下所示:void glGenTextures(GLsizei n, GLuint * textures );函数参数的含义:n: 生成的纹理的名称的个数;textures: 生成的纹理名称所存储位置的指针,也就是一个纹理数组的内存地址,或者说是数组首元素的内存地址。函
16、数被调用,会生成一系列纹理的名字,并存储到指定的数组中。纹理的绑定 glBindTexture 函数glBindTextureglBindTexture 函数实现了将调用 glGenTextures 函数生成的纹理的名字绑定到对应的目标纹理上。该函数的声明如下所示:void glBindTexture(GLenum target, GLuint texture );函数参数的含义:target: 纹理被绑定的目标,它只能取值 GL_TEXTURE_1D 或者 GL_TEXTURE_2D;texture:纹理的名称,并且,该纹理的名称在当前的应用中不能被再次使用。位图映射到纹理存储空间 glTe
17、xImage2D 函数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 表示基本图像,其它可以参考 MS
18、DN;components :纹理中颜色组件的编号,可是是 1 或 2 或 3 或 4;width :纹理图像的宽度;height :纹理图像的高度;border :纹理图像的边框宽度,必须是 0 或 1;format :指定像素数据的格式,一共有 9 个取值:GL_COLOR_INDEX、GL_RED、GL_GREEN 、GL_BLUE 、GL_ALPHA、GL_RGB、GL_RGBA、GL_BGR_EXT、GL_BGRA_EXT、GL_LUMINANCE、GL_LUMINANCE_ALPHA ,具体含义可以参考MSDN;type :像素数据的数据类型,取值可以为 GL_UNSIGNED_B
19、YTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, and GL_FLOAT;pixels :内存中像素数据的指针。滤波的使用使用到 glTexParameteri 函数glTexParameteri 函数或者 glTexParameterf 函数用来设置纹理参数,声明如下所示:void glTexParameterf(GLenum target, GLenum pname, GLfloat param );void glTexParameteri(GLenum target, GLenu
20、m pname, GLint param );函数参数的含义:target :目标纹理,必须为 GL_TEXTURE_1D 或 GL_TEXTURE_2D;pname :用来设置纹理映射过程中像素映射的问题等,取值可以为:GL_TEXTURE_MIN_FILTER、GL_TEXTURE_MAG_FILTER、GL_TEXTURE_WRAP_S 、GL_TEXTURE_WRAP_T,详细含义可以查看 MSDN;param :实际上就是 pname 的值,可以参考 MSDN。另外,该类函数还有两个:void glTexParameterfv(GLenum target, GLenum pname,
21、 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);功能就是实现线形滤波的功能,当纹理映射到图形表面以后,如果因为其它条件的设置导致纹理不能更好地显示的时候,进行过滤,按照指定的方式进行显示,可能会过滤掉显示不正常的纹理像素。纹理映射到坐标点使用到 glTexCoord2f 函数glTexCoord2f 函数,设置纹理坐标,该函数的声明如下所示:void glTexCoord2f(GLfloat s, GLfloat t );glTexCoord2f 的第一个参数是 X 坐标,当 s=0.0f 时是纹理的左侧,s=0.5f 时是纹理的中点,s=1.0f 时是纹理的右侧。 glTexCoord2f 的第二个参数是 Y 坐标,t=0.0f 是纹理的底部,t=0.5f 是纹理的中点, t=1.0f 是纹理的顶部。