计算机图形学课程教学设计_第1页
计算机图形学课程教学设计_第2页
计算机图形学课程教学设计_第3页
计算机图形学课程教学设计_第4页
计算机图形学课程教学设计_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、计算机图形学课程设计(2015-2016学年第二学期)学院专业班级学号学生姓名老师编写日期:2016年xx月xx日真实感游戏场景绘制3.1 实验目的3.2 实验内容3.3 实验分工4.4 理论基础4.1 雾化模型4.2 颜色模型5.3 光照模型6.4 纹理模型6.5 系统描述1.31 墙壁、地面、箱子1.32 石柱、雪人143 玻璃球1.54 天空1.76 心得体会1.97 附录:程序源代码 19真实感游戏场景绘制【摘要】本次课程设计绘制了一个真实感的三维场景, 并实现场景漫游。主 要绘制了墙壁与地面、天空、石柱、箱子、玻璃球、雪人、雾等对象。以 Visual Studio2012为平台用Op

2、enGL基础知识实现此真实感场景的绘制。一 实验目的1 .熟悉OpenGL基础函数,并了解其用法。2 .通过程序模拟真实感游戏场景,掌握图形综合展示效果,基于专业背景, 结合实验课内容与课程设计要求,使用OpenGL绘制简单的3D真实感游戏场景, 包括光栅化算法、多边形裁剪计算以及消隐算法在场景绘制中的应用。实验内容和效果光栅化算法、多边形裁剪计算以及消隐算法在场景绘制中的应用,其中真实感场景绘制包括颜色模型、纹理模型、雾化模型、运动模型以及环境光、漫反射、 镜面反射等光照模型设置。图1游戏场景整体效果三实验分工本次课程设计实验,小组成员齐心协力。首先从自己尝试编写没有成功到 后来的各种搜集资

3、料,寻找3D游戏场景的绘制代码,到最后小组成员分工解析 代码并注释,做PPT,演讲PPT等,大家合作都很用心。这次的实验中我们小 组每个成员在每一个环节都参与任务,因代码过多,也都参与到代码解析中。具体安排如下:姓名任务xxx搜集资料,代码解析注释,做 PPT, PPT演讲xxx搜集资料,代码解析并注释,做 PPT, PPT演讲xxx搜集资料,代码解析注释,做 PPT, PPT演讲xxx搜集资料,代码解析注释,做 PPT, PPT演讲四理论基础1雾化模型OpenGL中提供了完整的雾化接口 ,我们只需要选择合适的雾气的混合因子、 密度、颜色、起始位置等。在OpenGL中,雾的工作模式有两种:线性

4、模式和指 数模式。这两种模式是根据雾的浓度变化来区分的。在线性模式下,只需要提供一个距离视点的开始位置和结束位置。从开始位置到结束位置之间,雾的浓度越来越高,浓度的变化和距离成正比。在指数模式下,雾的浓度随着距离的增加呈指数增长。这种模式通常用来用 于烟雾、烟幕等效果。glFogf(GL_FOG_START, 1.0f)确定了雾的开始初离屏幕有多近。glFogf(GL_FOG_END, 5.0),它告诉OpenGL雾能离开屏幕有多远glHint(GL_FOG_HINT, GL_DONT_CARE)确定了雾的渲染方式,使用 GL_DONT_CARE是因为并不关心建议值。这个项的不同值之间的区别:

5、GK_DONT_CARE :让OPENGL自己来确定雾的渲染方式,每顶点或是每 像素。GL_NICEST:对每一像素进行雾的渲染,它看起来是极棒的。GL_FASTEST:对每一顶点进行雾的渲染,它速度较快,但是不够美丽我们的雾气设置如下:GLfioett fogColor4=0.5f. 0.5f 0 5t D 5f) giFogiGL_FOG_MODE GL_EXP2;ff gfiFog(/( gl_fog_color rogco lor) giFogfGL_ FOG_DENS!TY. 0 004。/幅度 giFogf(GL_FOG_STAQT, 5 Of)山开始£巨离 glF3&#

6、171;GL_FQG_EHO 300 口号/搜言束距离 g旧/门氏GL_FOG_Hff JT GL_NiCEST)小雾化效果修改函数里面的参数改变雾的颜色和浓度:图2改变颜色(蓝色)和浓度的雾气2颜色模型OpenGL支持两种颜色模式:一种是 RGBA , 一种是颜色索引模式。不同的 是,RGBA模式中,数据直接就代表了颜色;而颜色索引模式中,数据代表的是 一个索引,要得到真正的颜色,还必须去查索引表。RGBA颜色RGBA模式中,每一个像素会保存以下数据:R值(红色分量)、G值(绿 色分量)、B值(蓝色分量)和 A值(alpha分量)。其中红、绿、蓝三种颜色 相组合,就可以得到我们所需要的各种颜

7、色,而alpha不直接影响颜色。3光照模型光照模型包括许多因素,如物体的类型,物体相对光源与其他物体的位置以 及场景中所设置的光源属性,物体的透明度,物体的表面光亮程度,甚至物体的 各种表面纹理等。光照到物体表面时,物体对光会发生反射、透射、吸收、衍射、 折射和干涉。通常观察不透明、不发光的物体,人眼所观察到的是从物体表面的 得到的反射光,它是由场景中的光源和其他物体表面的反射光共同作用产生的。简单光照明模型模拟物体表面对直接光照的反射作用,包括镜面反射和漫反射,而物体间的光反射作用没有被充分考虑到,仅仅用一个与物体周围和视点、 光源位置都无关的环境光常量来近似表示。可以用如下表达式表示:入射

8、光=环境光+漫反射+镜面反射光77光源属性glLiehtfvCGL_LT(;HTO, GL.AMBIEMT, Lightkmbient) 光源中的环境光播度 £lLielrtfv(GL_LIGHTO, GlZdIFFUSE, Light Diffused ;“丸源中的散射光强度 jlLithtfvCGL_LL&HTO, GL_F05IT工0他 HghtFgitioii)指定光漉庙位置 /材质属性slMaterialfvfGL.FEONT GL_OEIEMT, Light Ambient).v (CL-FEONT, CL_DIFFUSE, LrghtDiffuse);glHar

9、teriaLf v (GL_FONT, CLSPECULAR, jnat_sj)ecular ;sUIaterialf (GL.FRONT, GL_SHININESSFmatZshinmess) ; /材质属性的箱面反射指数 ?lEnable(&L_LIGHrO):/glEnable(GL_LIGHTING):4纹理模型(因为我们的场景大量使用了纹理模型,且我主要也负责纹理模型,因此处会详细解释。)我们都知道物体表面通常并不是具有简单颜色的平滑面,而是有着花纹 图案等丰富细节的。计算机三维图形通过给面贴纹理来表现表面细节。OpenGL默认设置是关闭贴纹理的,所以必须先用命令打开纹理计算

10、 glEnable(GL_TEXTURE_2D); / 启用二维纹理 glDisable(GL_TEXTURE_2D); 禁用二维纹理 1、启用纹理和载入纹理如同我们曾经学习过的OpenGL光照、混合等功能一样。在使用纹理前,必 须启用它。OpenGL支持一维纹理、二维纹理、三维纹理和四维纹理。一般情况下使用二维纹理即可。使用纹理前,必须载入纹理。利用 glTexImage2D函数可以载入一个二维的 纹理,该函数有多达九个参数,glTexImage2D( GL_TEXTURE_2D , Glint level, Glint components, Glsizei width, Glsizei

11、Height, Glint order, Glenum ype, const Glvoid *pixels )详细说明如下:第一个参数为指定的目标,在我们的入门教材中,这个参数 将始终使用 GL_TEXTURE_2D。第二个参数为“多重细节层次”,现在我们并不考虑多重纹理细节,因此这 个参数设置为零。第三个参数有两种用法。在OpenGL最初的版本中,使用整数来表示颜色分 量数目,例如:像素数据用 RGB颜色表示,总共有红、绿、蓝三个值,因此参 数设置为3,而如果像素数据是用 RGBA颜色表示,总共有红、绿、蓝、alpha 四个值,因此参数设置为4。而在后来的版本中,可以直接使用 GL_RGB或

12、 GL_RGBA来表示以上情况,显得更直观。注意:虽然我们使用 Windows的BMP 文件作为纹理时,一般是蓝色的像素在最前,其真实的格式为GL_BGR而不是GL_RGB,在数据的顺序上有所不同,但因为同样是红、绿、蓝三种颜色,因此 这里仍然使用GL_RGB o如果使用GL_BGR, OpenGL将无法识别这个参数,造 成错误。第四、五个参数是二维纹理像素的宽度和高度。在使用纹理时要特别注意其 大小,必须使用大小为2的整数次方的纹理。在很长一段时间内,很多图形程序 都喜欢使用256*256大小的纹理,不仅因为256是2的整数次方,也因为某些硬 件可以使用8位的整数来表示纹理坐标,2的8次方正

13、好是256,这一巧妙的组 合为处理纹理坐标时的硬件优化创造了一些不错的条件。第六个参数是纹理边框的大小最后三个参数分别是纹理的图像数据格式,数据类型和纹理图像的像素数据 的存储地址。举个例子,如果有一幅大小为 width*height,格式为Windows系统中使用最 普遍的24位BGR,保存在pixels中的像素图像。则把这样一幅图像载入为纹理 可使用以下代码:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);下面一段为我们的游戏场景中的载入纹理的代码:

14、/对于指定的多个纹理,要根据自己的需要映射到不同的面上,需要对位图 创建一个数组,/用来存储位图的名称,然后在初始化OpenGL的时候,可以读取这些位图, 然后生成多个纹理存储到一个纹理数组中,接着就可以指定绘制的某个面,对该指定的面进行纹理映射/加载位图AUX_RGBImageRec *LoadBMP(char "Filename)/ 根据位图文件的名称进行 加载。 AUX_RGBImageRec定义纹理数据的格式FILE *File=NULL; / 文件指针if (Filename)/确保文件名已提供return NULL; 如果没有提供,返回 nullFile=fopen(Fi

15、lename,"r"); /根据指定的位图文件名称,打开该位图文件 if (File) /如果位图文件存在 fclose(File);/关闭句柄。因为只是需要判断问题是否存在,而不需要对位图文件进行写操作,所以关闭位图文件return auxDIBImageLoad(Filename); 载入位图并返回指针(其实,只 需要一个真正存在的位图文件的名称,实现加载位图文件,并返回) return NULL;首先,AUX_RGBImageRec类型是一个RGB图像结构类型。该结构定义 了三个成员:sizeX 图像的宽度;sizeY 图像的高度;data;图形所包含的数据,其实也就

16、是该图形在内存中的像素数据的 一个指针。AUX_RGBImageRec类型的变量描述了一幅图像的特征。上述函数中,调用了 glaux.h库文件中的auxDIBImageLoad 函数,其实它 是一个宏,函数原型为 auxRGBImageLoadW(LPCWSTR) 或者 auxRGBImageLoadA(LPCSTR),可以在该库文件中找到它的定义,如下所示:/* AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCTSTR); */#ifdef UNICODE#define auxRGBImageLoad auxRGBImageLoadW#else#d

17、efine 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(LP

18、CSTR);AUX_RGBImageRec * APIENTRY auxDIBImageLoadW(LPCWSTR);宏auxDIBImageLoad实现的功能就是:根据指定的位图名称,将该位图的 信息加载到内存中,以便用来创建成为纹理。/加载纹理int LoadGLTextures()用于创建并加载纹理的函数为 LoadGLTexturesint Status=FALSE;/很多函数的返回类型都是 Status这里Status是用 typedef 定义的 intl 类型 即:typedef int Status;AUX_RGBImageRec *TextureImage10; /创建一个纹理

19、图像数组,这里 指定数组大小为10memset(TextureImage,0,sizeof(void *)*10); / 创建一个纹理图像数组, 这里指定数组大小为10/创建的位图名称数组,对应10幅位图if(TextureImage0=LoadBMP("Data/Floor.bmp")&&(TextureImage1=Load BMP("Data/Wall.bmp")&&(TextureImage2=LoadBMP("Data/Door.bmp")&&(Te xtureImage3=L

20、oadBMP("Data/Box.bmp")&&(TextureImage4=LoadBMP("Data/ Hat.bmp")&&(TextureImage5=LoadBMP("Data/Cylinder.bmp")&&(TextureImag e6=LoadBMP("Data/Star.bmp")&&(TextureImage7=LoadBMP("Data/Mask.bmp ")&&(TextureImage8=L

21、oadBMP("Data/Sky.bmp")&&(TextureImage9=LoadB MP("Data/Lightning.bmp")Status=TRUE;/加载位图成功,修改状态标志变量Status为TRUEglGenTextures(10, &texture0);/纹理标识 for(int loop=0;loop<10;loop+) /遍历位图名称数组,根据位图名称分别生成glBindTexture(GL_TEXTURE_2D,textureloop); 进行绑定纹理。glTexParameteri(GL_TEXT

22、URE_2D,GL_TEXTURE_MAG_FILTER,GL_LINE AR);/设置滤波模式,功能就是实现线形滤波的功能,当纹理映射到图形表面以 后,glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINE AR);/如果因为其它条件的设置导致纹理不能更好地显示的时候,进行过滤,按 照指定的方式进行显示,可能会过滤掉显示不正常的纹理像素。/纹理的定义,此处用到的是二维纹理glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImageloop->sizeX, TextureImageloop-&

23、gt;sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImageloop->data);/生成纹理for (int loop=0; loop<10; loop+) /释放位图数组占用的内存空间 if (TextureImageloop!=NULL)if (TextureImageloop->data!=NULL)free(TextureImageloop->data);free(TextureImageloop);return Status;/创建纹理并加载,返回成功或者失败的标志Status2、纹理控制OpenGL的纹理控制实质上

24、就是定义纹理如何包裹物体的表面的,因为纹理的外形并不总是与物体一致,比如纹理通常是矩形的,但会被映射到一个多边形或 曲面上,在被变换到屏幕坐标后,纹理的单个纹素很难与屏幕上的像素对应。根据所使用的变换和所用的纹理的映射方式,屏幕上的单个像素可能对应纹理单元中单个纹素的一部分,即放大滤波或对应于多个纹素的,即缩小滤波。而控制缩 小和放大滤波的是采用glTexParameter函数来实现的。“设置超装槿式,功能就是实现线电通装的功能,当纹理映射到图形表面以后, 如果因为其它条件的谩置m致纹理不能更好地显示的时候,迸行过速按照 指关的方式进行显示,可能会过速掉显示不正常的纹理像素。(GL_TEXTO

25、RE_2口,L_ TEXTURE. W.FILTER, GL.LINEAR);glTexParaneteri (GL_TEKTW_2D. GLTEXTURE.MIN.FILTER, GL.LTUEW : tl MM tl 3、纹理坐标纹理的使用只要指定每一个顶点在纹理图像中所对应的像素位置,OpenGL就会自动计算顶点以外的其它点在纹理图像中所对应的像素位置。例如:在绘制一条线段时,我们设置其中一个端点为红色,另一个端点为绿色,则OpenGL会 自动计算线段中其它各像素的颜色,如果是使用glShadeMode(GL_SMOOTH);,则最终会形成一种渐变的效果(例如线段中点,就是红色和绿色的中

26、间色)。类 似的,在绘制一条线段时,我们设置其中一个端点使用“纹理图像中最左下角的 颜色”作为它的颜色,另一个端点使用“纹理图像中最右上角的颜色”作为它的 颜色,则OpenGL会自动在纹理图像中选择合适位置的颜色,填充到线段的各个像素(例如线段中点,可能就是选择纹理图像中央的那个像素的颜色)。使用glTexCoord*系列函数来指定纹理坐标。这些函数的用法与使用 glVertex*系列函数来指定顶点坐标十分相似。例如:glTexCoord2f(0.0f, 0.0f);指定使用(0, 0)纹理坐标。通常,每个顶点使用不同的纹理,于是下面这样形式的代码是比较常见的。glBegin( /* .*/)

27、;glTexCoord2f( /* .*/);glVertex3f( /* .*/);glTexCoord2f( /* .*/);glVertex3f( /* .*/);/* . */glEnd();我们的代码中使用的纹理坐标:rr左墙glBimiTEKtUEe (GL_TEXnJRE_2D, texturel);IBesin(GL_QUADS). £LTcxCoord2f(4.Of, tlTexCoord2f(4. Ofr glTsxCoordlif (0. Of, SlTexCoord2f (0- Ofn IHndO : /右墙O.Cf): 1.Of); l.Of): O.Of)

28、.glVertef (-50. Of,jlVerteiJf (-50. Of,g LVertsx3f (-50. Of,glTertexSf (-50. Of,.此100. Df,100. Of,0. Of,-300. Of):-300. Of);300.Of);300. Of):glBindTexture CGL_TEXTURE_2D, tewture 1);SlBesia(CL_QUADS). £lTeCootd2f(4.Of, fflTexCoord2f(0. Ofr glTesCoord2f(0. 0£. lTe3tCoard2f (4. Of, ClEzkd ()

29、:l.Of) : gnerten3f (50. Of1. Of) : dV«rtex3f(5O.OfO.Of) : IVertexSf (50, OfO.Of) ! glTertBzaf (EO-OflOO.Of,1 OO. Of,O.Of,O.Of,300. Of):-3C0, Of);-3C0, Of):300. Of):五系统描述本实验绘制的游戏场景可以使用按键T、J、一、一或 W、S、A、D控制 运动方向,PgDn和PgUp可以改变观察者的高度,鼠标控制转向,按键F'可 以打开和关闭“雾气”,Esc退出程序。主要绘制了墙壁与地面、天空、石柱、箱子、玻璃球、雪人、雾等对

30、象下面 将依次分析它们的设计思路,这里将使用相同绘制技术的对象放到一起说明。1墙壁、地面、箱子它们的基本操作对四边形的纹理映射,将一幅纹理图的四个顶点坐标分别映 射到四边形的四个顶点上即可。OpenGL就自动通过插值填充多边形内部的纹理。 由于在OpenGL中纹理坐标是一个点的属性,故需要在绘制点之前指定该点的纹 理坐标。另外在绘制四边形时要保证绘制顺序的一致,这里统一采用逆时针顺序 绘制。纹理坐标范围在0, 1之间,坐标超过1则采用重复的方式(OpenGL默 认处理方式)。这样可以在映射时按四边形的比例设置纹理坐标,从而防止纹理图过度拉伸造成的变形。一个四边形的纹理映射步骤为:glBindT

31、exture(GL_TEXTURE_2D,texture0);glBegin(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墙

32、壁地面箱子2石柱、雪人石柱和雪人都属于二次几何体的绘制和纹理映射,其中雪人由圆柱、球体、 圆盘、圆锥构成。OpenGL提供了这些基本几何体的绘制函数,而且在纹理映射 时我们采用自动生成纹理坐标的方法, 所以这一部分工作量其实很少。另外,为 了给雪人的身体、鼻子等部位设置颜色时,我们需要关闭纹理映射、并更改材质 的属性(物体的颜色是由光源和材质共同作用的结果)。对于石柱,我们加上了 绕自身局部坐标Y轴的匀速旋转。我们使用 Glut库提供的如下函数绘制二次几 何体:gluCylinder:绘制圆柱和圆柱gluSphere绘制球体gluDisk:绘制圆盘使用gluQuadricTexture设置自动

33、计算纹理坐标实验效果如下:图4雪人和石柱3玻璃球在绘制玻璃球时,为了在球面上反射出周围的场景,我们使用了环境映射。 由于我们能够在三维场景中漫游,这就需要球面上反射出的场景是随着视点移动 而变化的,这一需求可以利用“渲染到纹理" (RTT)技术实现。其基本思想是: 首先绘制出环境中的所有物体(除了该玻璃球),接着将绘制得到的场景图制作 成纹理,在绘制该玻璃球时将此纹理图贴在球面上即可。该场景使用的核心函数是glCopyTexImage2D,该函数可以将帧缓存中的颜 色值复制到纹理缓存中。实验发现该函数性能较低,会拖慢整个程序的速度,为 了平衡绘制质量和速度,可以只拷贝一部分像素值。实

34、验效果如下:理 3m图5玻璃球4、雾气OpenGL中提供了完整的雾化接口,我们只需要选择合适的雾气的混合因 子、密度、颜色、起始位置等。该场景的雾气设置如下: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_FO

35、G_HINT,GL_NICEST); 雾化效果实验效果如下:图6雾气4天空天空包含云、星星、闪电三个对象。我们要实现的目标是:云在空中飘动、 且能够遮盖住空中的星星,每间隔一段时间都会有闪电和雷声。天空的绘制主要使用了颜色混合技术。首先将星星的纹理图映射到天空,为了实现云朵覆盖住星星,我们使用了如下技巧:制作一个关于云图(图6)的二值图像(图7),其中有云的部分为黑色、无云的部分为白色。将该二值图像作 为“掩模”与星星图进行混合,并设置混合因子glBlendFunc(GL_DST_COLOR,GL_ZERO),该设置可以将星星图中对应“掩模”黑色的部分 置为黑色、对应“掩模”白色的部分保留原色

36、。接着再将云图映射至天空,并更 改混合因子glBlendFunc(GL_ONE, GL_ONE),该设置实现源色与目的色相力口。 至此已经实现云对星星的遮盖,另外,在进行颜色混合时需要打开OpenGL的颜 色混合功能,且要关闭深度测试功能。为了实现云的飘动,我们在设置云图纹理坐标时添加一个变量,该变量从 0 递增至1,超过1时做减1操作,这样就可以模拟云的移动。如下的 roll即为该 变量:glBegin(GL_QUADS);glTexCoord2f(0.0f, 3.0f-roll);glVertex3f(-50.0f, 100.0f, -300.0f);glTexCoord2f(1.0f,

37、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云图和云的二值图图8天空六心得体会这次的课程设计不仅考察了书上所学知识点,将所学融合在一起。过程中虽 然刚开始感觉有些难,也遇到很多困难,比如电脑配置问题等等,但遇到困难不 可怕,重要的是解决困难的过程,我们的游戏场景的绘制,因工

38、程量很大,且代 码很多,在实验过程中,我不断查资料,看书去理解各种模型代码,从来不敢相 信自己能将看完并理解这么多代码。 但是这次我做到了,虽然我重点讲的是纹理 模型,其他模型也都去认真学习了一遍。 在这个过程中真的学到很多,而大学锻 炼的也就是这种自学能力。七附录:程序源代码#include <windows.h>#include<math.h>#include<stdio.h>#include <glglut.h>#include <glglaux.h>#pragma comment( lib, "opengl32.li

39、b")#pragma comment( lib, "glu32.lib")#pragma comment( lib, "glaux.lib")#define KEY_DOWN(vk_code)(GetAsyncKeyState(vk_code) & 0x8000) ? 1 :0)HDChDC=NULL;HGLRChRC=NULL;HWND hWnd=NULL;HINSTANCE hInstance;bool keys256;bool active=TRUE;bool fullscreen=TRUE;int SCREEN_WIDTH =8

40、00;/ 屏幕宽int SCREEN_HEIGHT =600; 屏幕高GLfloat theta = 0.0f; /左右旋转角度GLfloat viewUp = 0.0f;/向上和向下程度GLfloat speed = 0.23f;/运动速度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,

41、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.0f, 1.0f, 1.0f, 1.0f;GLfloat 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;/ 雾

42、气颜色GLuint texture10;/ 纹理标识GLUquadricObj *quadratic=gluNewQuadric();/ 二次几何体GLfloat rotate=0.0f;/石柱旋转角度GLfloat roll=0;/ 云层移动量GLfloat lightning=0;bool thunder=true;/促否打雷GLboolean fog=false;/是否开启雾化bool fp;/F键是否按下GLuint EnvTexture;/环境纹理*11/接口集void CollDetec(GLfloat &x,GLfloat &z);void SetViewByMo

43、use();void Camera();AUX_RGBImageRec *LoadBMP(char "Filename);int LoadGLTextures();GLuint EmptyTexture();int InitGL(GLvoid);void DrawCave();void DrawBox();void DrawSnowMan();void Drawcylinder();void DrawGlassBall();void DrawSky();int DrawGLScene(GLvoid);GLvoid ReSizeGLScene(GLsizei width, GLsize

44、i height);GLvoid KillGLWindow(GLvoid);BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag);LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);* *11/改变宽口大小GLvoid ReSizeGLScene(GLsizei width, GLsizei height) if (height=0)height=1;/下面函数是定义视图窗口在画布上的大小和位置glViewport(0,0

45、,width,height);/设置为投影矩阵glMatrixMode(GL_PROJECTION);/当前矩阵设置为单位矩阵glLoadIdentity();/角度视,景体的宽高比,沿z轴方向的两裁面之间的距离的近处,沿z轴 方向的两裁面之间的距离的远处gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,1000.0f);/模型视图应用这个参数后,表示接下来的矩阵操作都是针对模型视景矩 阵堆栈,/直到下一次调用这个函数并更改参数为止。glMatrixMode(GL_MODELVIEW);/当前矩阵设置为单位矩阵glLoadIden

46、tity();/碰撞检测,防止视点穿过物体,是极为简单的最小外包矩形进行碰撞检测void CollDetec(GLfloat &x,GLfloat &z) if (x<-(50-dis)x= -(50-dis);/ 房间if (x> (50-dis)x= 50-dis;if (z<-(300-dis)z= -(300-dis);if (z> (300-dis)z= 300-dis;if (z>=-170&&z<=-150&&x>(30-dis)&&eyePosition1<=60)x

47、=30-dis;/ 箱 子与玻璃球if (x>=30&&z>=-170&&z<-(150-dis)&&eyePosition1<=60)z=-(150-dis);if (x>=30&&z<=-150&&z>-(170+dis)&&eyePosition1<=60)z=-(170+dis);if (z>=150&&z<=170&&x<-(30-dis)&&eyePosition1<=

48、55) x=-(30-dis);/ 雪人if (x<=-30&&z<=170&&z>(150-dis)&&eyePosition1<=55)z=(150-dis);if (x<=-30&&z>=150&&z<(170+dis)&&eyePosition1<=55)z=(170+dis);if (z<=-280&&x>(30-dis)x=30-dis;/ 石柱if (z<=-280&&x<-(30-

49、dis)x=-(30-dis);if (x>=30&&z<-(280-dis)z=-(280-dis);if (x<=-30&&z<-(280-dis)z=-(280-dis);利用鼠标控制转向void SetViewByMouse()POINT mousePos;/鼠标位置POINT middlePos;屏幕中心位置middlePos.x =SCREEN_WIDTH/2;middlePos.y =SCREEN_HEIGHT/2;GetCursorPos(&mousePos);/得到鼠标当前位if(mousePos.x=middl

50、ePos.x&&mousePos.y=middlePos.y) /加果鼠标没有动,返回。return ;/如果鼠标动了,/旋转改变量/上下改变量SetCursorPos(middlePos.x, middlePos.y);则恢复到屏幕中心/通过鼠标在x轴上的移动分量,计算旋转改变量theta += GLfloat(-middlePos.x +mousePos.x)/500;/通过鼠标在Y轴上的移动分量,计算旋转改变量viewUp +=GLfloat( middlePos.y - mousePos.y)/500; return ;/视点改变void Camera()SetView

51、ByMouse();/通过鼠标获得if (KEY_DOWN(VK_LEFT)|KEY_DOWN('A')/ 向左eyePosition0+=(viewAtPosition2-eyePosition2)*speed; / 利用相似 三角形计算eyePosition2+= -(viewAtPosition0-eyePosition0)*speed;/向右 if (KEY_DOWN(VK_RIGHT)|KEY_DOWN('D') eyePosition0-=(viewAtPosition2-eyePosition2)*speed;eyePosition2-= -(vi

52、ewAtPosition0-eyePosition0)*speed;if(theta>360) theta=0.0f;if (viewUp>0.6f)viewUp = 0.6f;if (viewUp<-0.6f)viewUp =-0.6f;if (KEY_DOWN(VK_UP)|KEY_DOWN('W)前进eyePosition0+= (viewAtPosition0-eyePosition0)*speed;eyePosition2+= (viewAtPosition2-eyePosition2)*speed; if(KEY_DOWN(VK_DOWN)|KEY_DOW

53、N('S')/后退eyePosition0-= (viewAtPosition0-eyePosition0)*speed;eyePosition2-= (viewAtPosition2-eyePosition2)*speed; if(KEY_DOWN('F') /后退 fog = true;/*eyePosition0-= (viewAtPosition0-eyePosition0)*speed;eyePosition2-= (viewAtPosition2-eyePosition2)*speed;*/ if(KEY_DOWN('G')/后退 f

54、og = false;/*eyePosition0-= (viewAtPosition0-eyePosition0)*speed;eyePosition2-= (viewAtPosition2-eyePosition2)*speed;*/ if(KEY_DOWN(VK_PRIOR)&&eyePosition1<70.0f) / 向上 eyePosition1+=0.5*speed;if(KEY_DOWN(VK_NEXT)&&eyePosition1>30.0f) / 向下 eyePosition1-=0.5*speed;CollDetec(eyePo

55、sition0,eyePosition2);viewAtPosition0 = eyePosition0 + cos(theta);/ 新的参考点的位置viewAtPosition2 = eyePosition2 + sin(theta);viewAtPosition1 = eyePosition1;gluLookAt( eyePosition0,eyePosition1 ,eyePosition2, /视点位置viewAtPosition0, viewAtPosition1 + viewUp, viewAtPosition2, /参考点位置0.0,1.0,0.0);/向上方向 return

56、;/加载位图AUX_RGBImageRec *LoadBMP(char *Filename)/ 根据位图文件的名称进 行加载。AUX_RGBImageRec定义纹理数据的格式FILE *File=NULL; / 文件指针if (Filename)确保文件名已提供 return NULL;如果没有提供,返回 nullFile=fopen(Filename,"r"); /根据指定的位图文件名称,打开该位图文件if (File)/ 如果位图文件存在fclose(File);/关闭句柄。因为只是需要判断问题是否存在,而不需要对位图文件进行写操作,所以关闭位图文件return aux

57、DIBImageLoad(Filename); /雷入位图并返回指针(其实,只 需要一个真正存在的位图文件的名称,实现加载位图文件,并返回)return NULL;/加载纹理int LoadGLTextures()/用于创建并加载纹理的函数为 LoadGLTexturesint Status=FALSE;/很多函数的返回类型都是 Status这里Status是用 typedef 定义的 intl 类型 即:typedef int Status;AUX_RGBImageRec *TextureImage10; /创建一个纹理图像数组,这里 指定数组大小为10memset(TextureImage,0,sizeof(void *)*10); / 创建一个纹理图像数组, 这里指定数组大小为6/创建的位图名称数组,对应6幅位图 if(Tex

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论