1、计算机图形学计算机图形学课程设计(2015-2016 学年第二学期)学 院 专业班级 学 号 学生姓名 老 师 编写日期:2016 年 xx 月 xx 日2 / 42目 录真实感游戏场景绘制 3一 实验目的 3二 实验内容 3三 实验分工 3四 理论基础 41 雾化模型 .42 颜色模型 .53 光照模型 .64 纹理模型 .6五 系统描述 131 墙壁、地面、箱子 .132 石柱、雪人 .143 玻璃球 .154 天空 .17六 心得体会 19七 附录:程序源代码 19计算机图形学3 / 42真实感游戏场景绘制【摘要】本次课程设计绘制了一个真实感的三维场景,并实现场景漫游。主要绘制了墙壁与地
2、面、天空、石柱、箱子、玻璃球、雪人、雾等对象。以Visual Studio2012 为平台用 OpenGL 基础知识实现此真实感场景的绘制。一 实验目的1熟悉 OpenGL 基础函数,并了解其用法。2通过程序模拟真实感游戏场景,掌握图形综合展示效果,基于专业背景,结合实验课内容与课程设计要求,使用 OpenGL 绘制简单的 3D 真实感游戏场景,包括光栅化算法、多边形裁剪计算以及消隐算法在场景绘制中的应用。二 实验内容和效果光栅化算法、多边形裁剪计算以及消隐算法在场景绘制中的应用,其中真实感场景绘制包括颜色模型、纹理模型、雾化模型、运动模型以及环境光、漫反射、镜面反射等光照模型设置。图 1 游
3、戏场景整体效果4 / 42三 实验分工本次课程设计实验,小组成员齐心协力。首先从自己尝试编写没有成功到后来的各种搜集资料,寻找 3D 游戏场景的绘制代码,到最后小组成员分工解析代码并注释,做 PPT,演讲 PPT 等,大家合作都很用心。这次的实验中我们小组每个成员在每一个环节都参与任务,因代码过多,也都参与到代码解析中。具体安排如下:姓名 任务xxx 搜集资料,代码解析注释,做 PPT,PPT 演讲xxx 搜集资料,代码解析并注释,做 PPT,PPT 演讲xxx 搜集资料,代码解析注释,做 PPT,PPT 演讲xxx 搜集资料,代码解析注释,做 PPT,PPT 演讲四 理论基础1雾化模型Ope
4、nGL 中提供了完整的雾化接口,我们只需要选择合适的雾气的混合因子、密度、颜色、起始位置等。在 OpenGL 中,雾的工作模式有两种:线性模式和指数模式。这两种模式是根据雾的浓度变化来区分的。在线性模式下,只需要提供一个距离视点的开始位置和结束位置。从开始位置到结束位置之间,雾的浓度越来越高,浓度的变化和距离成正比。在指数模式下,雾的浓度随着距离的增加呈指数增长。这种模式通常用来用于烟雾、烟幕等效果。glFogf(GL_FOG_START, 1.0f)确定了雾的开始初离屏幕有多近。glFogf(GL_FOG_END, 5.0),它告诉 OpenGL 雾能离开屏幕有多远glHint(GL_FOG
5、_HINT, GL_DONT_CARE)确定了雾的渲染方式,使用GL_DONT_CARE 是因为并不关心建议值。这个项的不同值之间的区别: 计算机图形学5 / 42GK_DONT_CARE:让 OPENGL 自己来确定雾的渲染方式,每顶点或是每像素。GL_NICEST:对每一像素进行雾的渲染,它看起来是极棒的。GL_FASTEST:对每一顶点进行雾的渲染,它速度较快,但是不够美丽我们的雾气设置如下:修改函数里面的参数改变雾的颜色和浓度:图 2 改变颜色(蓝色)和浓度的雾气2颜色模型OpenGL 支持两种颜色模式:一种是 RGBA,一种是颜色索引模式。不同的是,RGBA 模式中,数据直接就代表了
6、颜色;而颜色索引模式中,数据代表的是一个索引,要得到真正的颜色,还必须去查索引表。RGBA 颜色6 / 42RGBA 模式中,每一个像素会保存以下数据:R 值(红色分量)、G 值(绿色分量)、B 值(蓝色分量)和 A 值(alpha 分量)。其中红、绿、蓝三种颜色相组合,就可以得到我们所需要的各种颜色,而 alpha 不直接影响颜色。3光照模型光照模型包括许多因素,如物体的类型,物体相对光源与其他物体的位置以及场景中所设置的光源属性,物体的透明度,物体的表面光亮程度,甚至物体的各种表面纹理等。光照到物体表面时,物体对光会发生反射、透射、吸收、衍射、折射和干涉。通常观察不透明、不发光的物体,人眼
7、所观察到的是从物体表面的得到的反射光,它是由场景中的光源和其他物体表面的反射光共同作用产生的。简单光照明模型模拟物体表面对直接光照的反射作用,包括镜面反射和漫反射,而物体间的光反射作用没有被充分考虑到,仅仅用一个与物体周围和视点、光源位置都无关的环境光常量来近似表示。可以用如下表达式表示:入射光=环境光+ 漫反射+镜面反射光4纹理模型(因为我们的场景大量使用了纹理模型,且我主要也负责纹理模型,因此处会详细解释。)我们都知道物体表面通常并不是具有简单颜色的平滑面,而是有着花纹图案等丰富细节的。计算机图形学7 / 42计算机三维图形通过给面贴纹理来表现表面细节。OpenGL 默认设置是关闭贴纹理的
8、,所以必须先用命令打开纹理计算。glEnable(GL_TEXTURE_2D); / 启用二维纹理glDisable(GL_TEXTURE_2D); / 禁用二维纹理1、启用纹理和载入纹理如同我们曾经学习过的 OpenGL 光照、混合等功能一样。在使用纹理前,必须启用它。OpenGL 支持一维纹理、二维纹理、三维纹理和四维纹理。 一般情况下使用二维纹理即可。使用纹理前,必须载入纹理。利用 glTexImage2D 函数可以载入一个二维的纹理,该函数有多达九个参数,glTexImage2D(GL_TEXTURE_2D,Glint level,Glint components, Glsizei w
9、idth,Glsizei Height,Glint order,Glenum ype,const Glvoid *pixels)详细说明如下:第一个参数为指定的目标,在我们的入门教材中,这个参数将始终使用 GL_TEXTURE_2D。第二个参数为“多重细节层次”,现在我们并不考虑多重纹理细节,因此这个参数设置为零。第三个参数有两种用法。在 OpenGL 最初的版本中,使用整数来表示颜色分量数目,例如:像素数据用 RGB 颜色表示,总共有红、绿、蓝三个值,因此参数设置为 3,而如果像素数据是用 RGBA 颜色表示,总共有红、绿、蓝、alpha 四个值,因此参数设置为 4。而在后来的版本中,可以直
10、接使用 GL_RGB或 GL_RGBA 来表示以上情况,显得更直观。注意:虽然我们使用 Windows的 BMP 文件作为纹理时,一般是蓝色的像素在最前,其真实的格式为GL_BGR 而不是 GL_RGB,在数据的顺序上有所不同,但因为同样是红、绿、蓝三种颜色,因此这里仍然使用 GL_RGB。如果使用 GL_BGR,OpenGL 将无法识别这个参数,造成错误。第四、五个参数是二维纹理像素的宽度和高度。在使用纹理时要特别注意其大小,必须使用大小为 2 的整数次方的纹理。在很长一段时间内,很多图形程序都喜欢使用 256*256 大小的纹理,不仅因为 256 是 2 的整数次方,也因为8 / 42某些
11、硬件可以使用 8 位的整数来表示纹理坐标,2 的 8 次方正好是 256,这一巧妙的组合为处理纹理坐标时的硬件优化创造了一些不错的条件。第六个参数是纹理边框的大小。最后三个参数分别是纹理的图像数据格式,数据类型和纹理图像的像素数据的存储地址。举个例子,如果有一幅大小为 width*height,格式为 Windows 系统中使用最普遍的 24 位 BGR,保存在 pixels 中的像素图像。则把这样一幅图像载入为纹理可使用以下代码:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_B
12、YTE, pixels);下面一段为我们的游戏场景中的载入纹理的代码:/对于指定的多个纹理,要根据自己的需要映射到不同的面上,需要对位图创建一个数组,/用来存储位图的名称,然后在初始化 OpenGL 的时候,可以读取这些位图,然后生成多个纹理存储到一个纹理数组中,接着就可以指定绘制的某个面,对该指定的面进行纹理映射/加载位图AUX_RGBImageRec *LoadBMP(char *Filename)/ 根据位图文件的名称进行加载。 AUX_RGBImageRec 定义纹理数据的格式FILE *File=NULL; / 文件指针if (!Filename)/确保文件名已提供return NU
13、LL;/如果没有提供,返回 nullFile=fopen(Filename,“r“); / 根据指定的位图文件名称,打开该位图文件if (File)/ 如果位图文件存在计算机图形学9 / 42fclose(File);/ 关闭句柄。 因为只是需要判断问题是否存在,而不需要对位图文件进行写操作,所以关闭位图文件return auxDIBImageLoad(Filename); /载入位图并返回指针(其实,只需要一个真正存在的位图文件的名称,实现加载位图文件,并返回)return NULL;首先,AUX_RGBImageRec 类型是一个 RGB 图像结构类型。该结构定义了三个成员:sizeX 图
14、像的宽度;sizeY 图像的高度;data; 图形所包含的数据,其实也就是该图形在内存中的像素数据的一个指针。AUX_RGBImageRec 类型的变量描述了一幅图像的特征。上述函数中,调用了 glaux.h 库文件中的 auxDIBImageLoad 函数,其实它是一个宏,函数原型为 auxRGBImageLoadW(LPCWSTR)或者auxRGBImageLoadA(LPCSTR),可以在该库文件中找到它的定义,如下所示:/* AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCTSTR); */#ifdef UNICODE#define auxR
15、GBImageLoad auxRGBImageLoadW#else#define auxRGBImageLoad auxRGBImageLoadA#endifAUX_RGBImageRec * APIENTRY auxRGBImageLoadA(LPCSTR);10 / 42AUX_RGBImageRec * APIENTRY auxRGBImageLoadW(LPCWSTR);#ifdef UNICODE#define auxDIBImageLoad auxDIBImageLoadW#else#define auxDIBImageLoad auxDIBImageLoadA#endifAUX_
16、RGBImageRec * APIENTRY auxDIBImageLoadA(LPCSTR);AUX_RGBImageRec * APIENTRY auxDIBImageLoadW(LPCWSTR);宏 auxDIBImageLoad 实现的功能就是:根据指定的位图名称,将该位图的信息加载到内存中,以便用来创建成为纹理。/加载纹理int LoadGLTextures()/用于创建并加载纹理的函数为 LoadGLTexturesint Status=FALSE;/很多函数的返回类型都是 Status,这里 Status 是用typedef 定义的 intl 类型 即: typedef int
17、Status;AUX_RGBImageRec *TextureImage10; /创建一个纹理图像数组,这里指定数组大小为 10memset(TextureImage,0,sizeof(void *)*10); / 创建一个纹理图像数组,这里指定数组大小为 10/创建的位图名称数组,对应 10 幅位图if(TextureImage0=LoadBMP(“Data/Floor.bmp“)/加载位图成功,修改状态标志变量 Status 为 TRUEglGenTextures(10, /纹理标识for(int loop=0;loopsizeX, TextureImageloop-sizeY, 0, G
18、L_RGB, GL_UNSIGNED_BYTE, TextureImageloop-data);/生成纹理for (int loop=0; loopdata!=NULL)free(TextureImageloop-data);12 / 42free(TextureImageloop);return Status; / 创建纹理并加载,返回成功或者失败的标志 Status2、纹理控制OpenGL 的纹理控制实质上就是定义纹理如何包裹物体的表面的,因为纹理的外形并不总是与物体一致,比如纹理通常是矩形的,但会被映射到一个多边形或曲面上,在被变换到屏幕坐标后,纹理的单个纹素很难与屏幕上的像素对应。根据
19、所使用的变换和所用的纹理的映射方式,屏幕上的单个像素可能对应纹理单元中单个纹素的一部分,即放大滤波或对应于多个纹素的,即缩小滤波。而控制缩小和放大滤波的是采用 glTexParameter 函数来实现的。3、纹理坐标纹理的使用只要指定每一个顶点在纹理图像中所对应的像素位置,OpenGL就会自动计算顶点以外的其它点在纹理图像中所对应的像素位置。例如:在绘制一条线段时,我们设置其中一个端点为红色,另一个端点为绿色,则OpenGL 会自动计算线段中其它各像素的颜色,如果是使用glShadeMode(GL_SMOOTH);,则最终会形成一种渐变的效果(例如线段中点,就是红色和绿色的中间色)。类似的,在
20、绘制一条线段时,我们设置其中一个端点使用“纹理图像中最左下角的颜色”作为它的颜色,另一个端点使用“纹理图像中最右上角的颜色”作为它的颜色,则 OpenGL 会自动在纹理图像中选择合适位置的颜色,填充到线段的各个像素(例如线段中点,可能就是选择纹理图像中央的那个像素的颜色)。计算机图形学13 / 42使用 glTexCoord*系列函数来指定纹理坐标。这些函数的用法与使用glVertex*系列函数来指定顶点坐标十分相似。例如:glTexCoord2f(0.0f, 0.0f);指定使用(0, 0)纹理坐标。通常,每个顶点使用不同的纹理,于是下面这样形式的代码是比较常见的。glBegin( /* .
21、 */ );glTexCoord2f( /* . */ ); glVertex3f( /* . */ );glTexCoord2f( /* . */ ); glVertex3f( /* . */ );/* . */glEnd();我们的代码中使用的纹理坐标:五 系统描述本实验绘制的游戏场景可以使用按键、或 W、S、A 、D 控制运动方向,PgDn 和 PgUp 可以改变观察者的高度,鼠标控制转向,按键F可以打开和关闭“雾气”,Esc 退出程序。主要绘制了墙壁与地面、天空、石柱、箱子、玻璃球、雪人、雾等对象下面将依次分析它们的设计思路,这里将使用相同绘制技术的对象放到一起说明。14 / 421
22、墙壁、地面、箱子它们的基本操作对四边形的纹理映射,将一幅纹理图的四个顶点坐标分别映射到四边形的四个顶点上即可。OpenGL 就自动通过插值填充多边形内部的纹理。由于在 OpenGL 中纹理坐标是一个点的属性,故需要在绘制点之前指定该点的纹理坐标。另外在绘制四边形时要保证绘制顺序的一致,这里统一采用逆时针顺序绘制。纹理坐标范围在0,1之间,坐标超过 1 则采用重复的方式(OpenGL 默认处理方式)。这样可以在映射时按四边形的比例设置纹理坐标,从而防止纹理图过度拉伸造成的变形。一个四边形的纹理映射步骤为:glBindTexture(GL_TEXTURE_2D,texture0); glBegin
23、(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(30.0f,0.0f, -170.0f);glTexCoord2f(1.0f, 0.0f); glVertex3f(30.0f,0.0f, -150.0f);glTexCoord2f(1.0f, 1.0f); glVertex3f(30.0f,20.0f,-150.0f);glTexCoord2f(0.0f, 1.0f); glVertex3f(30.0f,20.0f,-170.0f);glEnd();实验效果图如下:图 3 墙壁 地面 箱子计算机图形学15 / 422 石柱、雪人石柱和雪人都属于
24、二次几何体的绘制和纹理映射,其中雪人由圆柱、球体、圆盘、圆锥构成。OpenGL 提供了这些基本几何体的绘制函数,而且在纹理映射时我们采用自动生成纹理坐标的方法,所以这一部分工作量其实很少。另外,为了给雪人的身体、鼻子等部位设置颜色时,我们需要关闭纹理映射、并更改材质的属性(物体的颜色是由光源和材质共同作用的结果)。对于石柱,我们加上了绕自身局部坐标 Y 轴的匀速旋转。我们使用 Glut 库提供的如下函数绘制二次几何体:gluCylinder:绘制圆柱和圆柱gluSphere:绘制球体gluDisk:绘制圆盘使用 gluQuadricTexture 设置自动计算纹理坐标。实验效果如下:图 4 雪
25、人和石柱3 玻璃球在绘制玻璃球时,为了在球面上反射出周围的场景,我们使用了环境映射。由于我们能够在三维场景中漫游,这就需要球面上反射出的场景是随着视点移动而变化的,这一需求可以利用“渲染到纹理”(RTT)技术实现。其基本思16 / 42想是:首先绘制出环境中的所有物体(除了该玻璃球),接着将绘制得到的场景图制作成纹理,在绘制该玻璃球时将此纹理图贴在球面上即可。该场景使用的核心函数是 glCopyTexImage2D,该函数可以将帧缓存中的颜色值复制到纹理缓存中。实验发现该函数性能较低,会拖慢整个程序的速度,为了平衡绘制质量和速度,可以只拷贝一部分像素值。实验效果如下:图 5 玻璃球4、 雾气O
26、penGL 中提供了完整的雾化接口,我们只需要选择合适的雾气的混合因子、密度、颜色、起始位置等。该场景的雾气设置如下:GLfloat fogColor4=0.5f, 0.5f, 0.5f, 0.5f; glFogi(GL_FOG_MODE,GL_EXP2);/模式glFogfv(GL_FOG_COLOR,fogColor);/颜色glFogf(GL_FOG_DENSITY, 0.004f);/密度glFogf(GL_FOG_START, 5.0f);/开始距离glFogf(GL_FOG_END, 300.0f);/结束距离glHint(GL_FOG_HINT,GL_NICEST);/雾化效果计
27、算机图形学17 / 42实验效果如下:图 6 雾气4天空天空包含云、星星、闪电三个对象。我们要实现的目标是:云在空中飘动、且能够遮盖住空中的星星,每间隔一段时间都会有闪电和雷声。天空的绘制主要使用了颜色混合技术。首先将星星的纹理图映射到天空,为了实现云朵覆盖住星星,我们使用了如下技巧:制作一个关于云图(图 6)的二值图像(图 7),其中有云的部分为黑色、无云的部分为白色。将该二值图像作为“掩模”与星星图进行混合,并设置混合因子 glBlendFunc (GL_DST_COLOR,GL_ZERO),该设置可以将星星图中对应“掩模”黑色的部分置为黑色、对应“掩模”白色的部分保留原色。接着再将云图映
28、射至天空,并更改混合因子 glBlendFunc(GL_ONE, GL_ONE),该设置实现源色与目的色相加。至此已经实现云对星星的遮盖,另外,在进行颜色混合时需要打开OpenGL 的颜色混合功能,且要关闭深度测试功能。18 / 42为了实现云的飘动,我们在设置云图纹理坐标时添加一个变量,该变量从0 递增至 1,超过 1 时做减 1 操作,这样就可以模拟云的移动。如下的 roll 即为该变量:glBegin(GL_QUADS); glTexCoord2f(0.0f, 3.0f-roll);glVertex3f(-50.0f, 100.0f, -300.0f);glTexCoord2f(1.0f
29、, 3.0f-roll);glVertex3f( 50.0f, 100.0f, -300.0f);glTexCoord2f(1.0f, 0.0f-roll);glVertex3f( 50.0f, 100.0f, 300.0f);glTexCoord2f(0.0f, 0.0f-roll);glVertex3f(-50.0f, 100.0f, 300.0f);glEnd();图 7 云图和云的二值图计算机图形学19 / 42图 8 天空六 心得体会这次的课程设计不仅考察了书上所学知识点,将所学融合在一起。过程中虽然刚开始感觉有些难,也遇到很多困难,比如电脑配置问题等等,但遇到困难不可怕,重要的是解
30、决困难的过程,我们的游戏场景的绘制,因工程量很大,且代码很多,在实验过程中,我不断查资料,看书去理解各种模型代码,从来不敢相信自己能将看完并理解这么多代码。但是这次我做到了,虽然我重点讲的是纹理模型,其他模型也都去认真学习了一遍。在这个过程中真的学到很多,而大学锻炼的也就是这种自学能力。七 附录:程序源代码#include #include#include20 / 42#include #include #pragma comment( lib, “opengl32.lib“) #pragma comment( lib, “glu32.lib“) #pragma comment( lib, “
31、glaux.lib“) #define KEY_DOWN(vk_code)(GetAsyncKeyState(vk_code) HGLRC hRC=NULL;HWND hWnd=NULL;HINSTANCE hInstance;bool keys256;bool active=TRUE;bool fullscreen=TRUE;int SCREEN_WIDTH =800;/屏幕宽 int SCREEN_HEIGHT =600;/屏幕高GLfloat theta = 0.0f; /左右旋转角度GLfloat viewUp = 0.0f;/向上和向下程度GLfloat speed = 0.23f;
32、/运动速度GLfloat dis=10;/碰撞检测保留距离GLfloat viewAtPosition3;/观察目标位置GLfloat eyePosition3 = 0.0f, 40.0f, 0.0f; /视点初始位置 GLfloat Matblack= 0.0f, 0.0f, 0.0f, 1.0f;GLfloat Matwhite= 0.7f, 0.7f, 0.7f, 1.0f;GLfloat Matred= 0.6f, 0.0f, 0.0f, 1.0f;GLfloat LightAmbient= 0.8f, 0.8f, 0.8f, 1.0f; GLfloat LightDiffuse= 1
33、.0f, 1.0f, 1.0f, 1.0f;计算机图形学21 / 42GLfloat LightPosition=1.0f, 1.0f, 1.0f, 0.0f;GLfloat mat_specular =1.0f, 1.0f, 1.0f, 1.0f;GLfloat mat_shininess = 100; /高光度GLfloat fogColor4= 0.5f, 0.5f, 0.5f, 0.5f;/雾气颜色GLuint texture10;/纹理标识GLUquadricObj *quadratic=gluNewQuadric();/二次几何体GLfloat rotate=0.0f;/石柱旋转角
34、度GLfloat roll=0;/云层移动量GLfloat lightning=0;bool thunder=true;/是否打雷GLboolean fog=false;/是否开启雾化bool fp;/F 键是否按下GLuint EnvTexture;/环境纹理/*/接口集void CollDetec(GLfloat void SetViewByMouse();void Camera();AUX_RGBImageRec *LoadBMP(char *Filename);int LoadGLTextures();GLuint EmptyTexture();int InitGL(GLvoid);v
35、oid DrawCave();void DrawBox();void DrawSnowMan();void Drawcylinder();void DrawGlassBall();22 / 42void DrawSky();int DrawGLScene(GLvoid);GLvoid ReSizeGLScene(GLsizei width, GLsizei height);GLvoid KillGLWindow(GLvoid);BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenfla
36、g);LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);/*/改变宽口大小GLvoid ReSizeGLScene(GLsizei width, GLsizei height) if (height=0)height=1;/下面函数是定义视图窗口在画布上的大小和位置glViewport(0,0,width,height);/设置为投影矩阵glMatrixMode(GL_PROJECTION);/当前矩阵设置为单位矩阵glLoadIdentity();/角度视,景体的宽高比,沿 z 轴方向的两裁面之间的距离的近处,/沿 z轴方向的两裁面之间
37、的距离的远处gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,1000.0f);/模型视图应用这个参数后,表示接下来的矩阵操作都是针对模型视景矩阵堆栈 ,/直到下一次调用这个函数并更改参数为止。glMatrixMode(GL_MODELVIEW);计算机图形学23 / 42/当前矩阵设置为单位矩阵glLoadIdentity();/碰撞检测,防止视点穿过物体,是极为简单的最小外包矩形进行碰撞检测void CollDetec(GLfloat if (z (300-dis)z= 300-dis;if (z=-170/石柱if (z=3
38、0 if (viewUp0.6f)viewUp = 0.6f; if (viewUp30.0f) /向下eyePosition1-=0.5*speed;CollDetec(eyePosition0,eyePosition2);viewAtPosition0 = eyePosition0 + cos(theta);/ 新的参考点的位置 viewAtPosition2 = eyePosition2 + sin(theta);viewAtPosition1 = eyePosition1;gluLookAt( eyePosition0,eyePosition1 ,eyePosition2, / 视点位
39、置viewAtPosition0, viewAtPosition1 + viewUp, viewAtPosition2 ,/参考点位置0.0,1.0,0.0);/向上方向return ;计算机图形学27 / 42/加载位图AUX_RGBImageRec *LoadBMP(char *Filename)/ 根据位图文件的名称进行加载。 AUX_RGBImageRec 定义纹理数据的格式FILE *File=NULL; / 文件指针if (!Filename)/确保文件名已提供return NULL;/如果没有提供,返回 nullFile=fopen(Filename,“r“); / 根据指定的位
40、图文件名称,打开该位图文件if (File)/ 如果位图文件存在fclose(File);/ 关闭句柄。 因为只是需要判断问题是否存在,而不需要对位图文件进行写操作,所以关闭位图文件return auxDIBImageLoad(Filename); /载入位图并返回指针(其实,只需要一个真正存在的位图文件的名称,实现加载位图文件,并返回)return NULL;/加载纹理int LoadGLTextures()/用于创建并加载纹理的函数为 LoadGLTexturesint Status=FALSE;/很多函数的返回类型都是 Status,这里 Status 是用typedef 定义的 int
41、l 类型 即: typedef int Status;28 / 42AUX_RGBImageRec *TextureImage10; /创建一个纹理图像数组,这里指定数组大小为 10memset(TextureImage,0,sizeof(void *)*10); / 创建一个纹理图像数组,这里指定数组大小为 6/创建的位图名称数组,对应 6 幅位图if (TextureImage0=LoadBMP(“Data/Floor.bmp“)/加载位图成功,修改状态标志变量 Status 为 TRUEglGenTextures(10, /纹理标识for(int loop=0;loopsizeX, Te
42、xtureImageloop-sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImageloop-data);/生成纹理for (int loop=0; loopdata!=NULL)free(TextureImageloop-data);free(TextureImageloop);return Status; / 创建纹理并加载,返回成功或者失败的标志 Status/为纹理开辟空间GLuint EmptyTexture()/创建空的 TextureGLuint txtnumber;/定义 Texture 的 IDunsigned int* data;/
43、存储数据30 / 42data = (unsigned int*)new GLuint(SCREEN_WIDTH/2* SCREEN_HEIGHT/2)* 4 * sizeof(unsigned int);/Create Storage Space For Texture Data (屏幕的一半 x 屏幕的一半 x4)这里开辟的大小与 DrawGlassBall()使用的一致ZeroMemory(data,(SCREEN_WIDTH/2* SCREEN_HEIGHT/2)* 4 * sizeof(unsigned int);/置零glGenTextures(1, /创建一个纹理glBindTe
44、xture(GL_TEXTURE_2D, txtnumber);glTexImage2D(GL_TEXTURE_2D, 0, 4, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, 0,GL_RGBA, GL_UNSIGNED_BYTE, data);/使用 data 中的信息创建纹理glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);delete data; /释放 datareturn txtnumber;/返回 textureID/初始化int InitGL(GLvoid)if (!LoadGLTextures()/加载纹理 return FALSE;glClearColor(1.0f, 1.0f, 1.0f, 1.0f);