ImageVerifierCode 换一换
格式:DOCX , 页数:17 ,大小:355.65KB ,
资源ID:6211535      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6211535.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(基于OpenGL的3D旋转魔方实现汇总.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

基于OpenGL的3D旋转魔方实现汇总.docx

1、基于OpenGL的3D旋转魔方实现汇总华中科技大学电子科学与技术系课程设计报告( 2010- 2011年度第 2 学期)名 称: 软件课程设计 题 目: 基于OpenGL的3D旋转魔方实现 院 系: 班 级: 学 号: 学生姓名: 指导教师: 设计周数: 成 绩: 日期: 年 月 日1.1目的. 21.2内容. 21.3取得的成果22.1 程序原理32.2 程序流程42.3 数据结构132.4 重要函数133.程序分析与结果演示16 3.1 成果演示16 3.2 程序分析174.出现过的问题185.心得和小节191.课程设计介绍 1.1目的 21世纪是高科技时代,是信息技术时代,而计算机技术无

2、疑会引领各行各业,为我们带来一个全新的时代。作为新世纪的接班人,我们必须拥有良好的计算机应用能力,才能跟上世界发展的大流,不至于在激烈的竞争中被淘汰。而程序作为计算机的灵魂,因此编程能力对当代大学生来说至关重要。通过本课程单元的学习,可以对软件工程项目从整体上有一个较清晰的了解和认识;可以提高自身软件编程能力,培养对计算机编程兴趣,培养良好的编程习惯。同时编程时的态度和方法对我们今后的学习和工作也有重要影响。所以整体看来软件课程设计这门课程提高了我们计算机使用水平,培养了我们良好的学习态度,对我们个人的发展而言有着重要的意义。 1.2 内容 (1)巩固和加强c语言相关编程知识,学会用Visua

3、l C+6.0进行c语言编程。(2)掌握程序设计流程和思想,模块化结构分析以及程序设计流程,初步培养需求分析、软件测试、调试的能力。 (3)掌握win32相关编程知识,了解windows程序内部运行机制。 (4)掌握OpenGL贴图技术原理与函数实现,掌握OpenGL几何的移动、旋转等模式变化的原理。 (5)掌握魔方图形构造原理,在掌握二阶魔方构造原理的基础上,构造出三阶魔方并实现其旋转。 1.3 取得的成果 在理解和掌握老师所给的范例程序的基础上,借助Win32平台进行了一系列调试和学习,熟练掌握了Win32 Application开发流程。同时也学习和了解了OpenGL的基本知识,掌握了一

4、些OpenGL的重要技术与重要函数的使用,编写了一些简单的OpenGL程序。在比较透彻的了解了二阶魔方的构造原理后,成功地构造出了三阶魔方,换上了自己班级同学的图片,并且在一个小立方体的六个面上贴上了不同的图片。能够比较完美的实现三阶魔方各个层面的随机旋转,并且把窗口背景设置为红色。为了使程序更加有趣,我在程序中导入了刘德华的爱你一万年这首歌,使魔方在旋转的同时能够播放歌曲。除此之外,我还实现了一种三阶魔方自由移动的屏保效果:即三阶魔方在旋转的同时能够在屏幕内部自由移动,并且在边缘无限次的反弹。在魔方平移的过程中同样可以通过四个方向键来控制魔方的移动。当松开方向键后,魔方会继续按照先前的方式自

5、由移动。2.程序分析2.1 程序原理(1)OpenGLOpenGL是为Open Graphics Library的简称,它是3D绘图工业标准,广泛地应用于计算机3D绘图领域。它是个专业的开放的3D程序接口,是一个功能强大,调用方便的底层3D图形库。它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C+紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性;它具有七大功能:建模、变换、颜色模式设置、光照和材质设置、纹理映射、位图显示和图象增强和双缓存动画功能。OpenGL使用简便,效率高。 本项目是在Visual

6、 C+6.0开发环境下,使用OpenGL函数库,绘制魔方并实现魔方贴图、随机旋转、以及键盘控制等功能。采用基本图形的绘图函数及定位函数,添加相应纹理来实现魔方模型的绘制。通过读取载入BMP文件,应用纹理贴图技术来完成对魔方旋转面的处理。通过OpenGL中对图形的旋转和平移函数来实现对魔方整体的旋转和平移。 (2)旋转 在建立好空间三维模型后,要实现魔方体每一层面的旋转。而魔方体每一层面的旋转归结于每一个小立方体的旋转。每个小立方体的旋转又最终归结于每个点的旋转。对于一个坐标为(x,y,z)的点,如果围绕z轴逆时针旋转角度为a,则旋转之后z坐标不变,x和y坐标分别变为x*cosa - y*sin

7、a,x*sina + y*cosa,如图1所示: 图1 这样,实现了每个点的旋转,针对每个立方体只需采用循环对8个点均采取旋转操作就可实现一个立方体的旋转。 (3)消息循环与定时器 由于程序在运行时CPU只能执行一个任务,然而此项目中魔方在旋转的同时要实现平移,所以需要用到Win32中的定时器功能。此程序中要用到的定时器的函数原型为:SetTimer(HWND hWnd ,UINT nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc) HWND hWnd为窗口句柄,使程序和定时器建立联系,UINT nIDEvent是定时器ID,用于区分不同的定时器;UINT

8、 uElapse为定时器触发周期,意味着多长时间执行一次;,TIMERPROC lpTimerFunc为该定时器执行时触发的函数。所以控制好不同定时器的触发周期和触发函数,就能使魔方的各个层面的旋转和平移互不冲突。 2.2 程序流程(1)WinMain主函数 WinMain主函数是所有Win32程序的入口点。在WinMain函数里窗体的建立和消息循环,在消息循环中实现键盘、鼠标输入事件处理响应。在本程序中,要创建Window窗体和构建OpenGL设备绘图环境。Window窗体创建步骤:窗体类注册:RegisterClass设置显示分辨率:ChangeDisplaySettings设置窗体大小:

9、AdjustWindowRectEx创建窗体:CreateWindowExOpenGL绘图环境搭建:获取设备绘图环境(DC,DeviceContext):hDC=GetDC(hWnd)选择绘图环境像素格式:ChoosePixelFormat(hDC,&pfd),其中pfd为像素格式描述符,如果设置不对,OpenGL绘图失败,看不到正确的显示结果。设置绘图环境像素格式:SetPixelFormat(hDC,PixelFormat,&pfd)获取OpenGL绘图环境:hRC =wglCreateContext(hDC)设置OpenGL绘图环境:wglMakeCurrent(hDC,hRC)(2)三

10、维建模一个三阶魔方体由27个小立方体构成,每个小立方体由8个顶点组成,而每个顶点又有x,y,z三个方向上的坐标值。这样由结构体的层层嵌套就可以对魔方体的每个小立方体、每个顶点进行操作。typedef struct GLfloat p3; /定义一个点的x,y,z坐标值stPoint;typedef struct stPoint CubePoint8;/定义一个小立方体的8个顶点stCube;如图2: 图2 stCube Cube27; /定义魔方体的27个小立方体其中一个难点是怎样根据各个点的坐标值构造出魔方体,其实只要定义好每个顶点的坐标就行了。但是三阶魔方必须定义27*8=216个顶点的坐

11、标值,而且很难用for循环实现,因为各个顶点的x,y,z坐标值几乎没有什么规律。但是如果能够将一个小魔方体作为一个整体来看待,工作量似乎会减轻很多。先在整个魔方体中间定义一个基准小立方体,则整个魔方体的各个小立方体均可以通过这个基准立方体的平移来实现,各个小立方体上各点的平移向量和小立方体中心的平移向量相同。static stPoint CubePoint8= /定义好基准小立方体,边长为1 -0.5f, -0.5f, 0.5f, /0 - 0.5f, -0.5f, 0.5f , /1 0.5f, 0.5f, 0.5f , /2 - -0.5f, 0.5f, 0.5f, /3 -0.5f, -

12、0.5f, -0.5f, /4 - -0.5f, 0.5f, -0.5f, /5 0.5f, 0.5f, -0.5f, /6 - 0.5f, -0.5f, -0.5f, /7; 基准小立方体平移得到一个小立方体Cube0:for(int i=0;i8;i+) Cube0.CubePointi.p0 = CubePointi.p0 + 1.0f; Cube0.CubePointi.p1 = CubePointi.p1 - 1.0f; Cube0.CubePointi.p2 = CubePointi.p2 - 1.0f; 其他26个立方体可通过同样的方法得到。我认为这是整个程序中最难也是最麻烦的一

13、点。本程序是通过reset_model()这一函数来构造出整个魔方体的。(3)OpenGL贴图实现glGenTextures(1, &texturei),作用是利用载入的图像生成纹理。glTexCoord2f(GLfloat s, GLfloat t) 函数用于绘制图形时指定纹理的坐标。第一个参数是X坐标,0.0是纹理的左侧,0.5是纹理的中点,1.0是纹理的右侧。第二个参数是Y坐标,0.0是纹理的底部,0.5是纹理的中点,1.0是纹理的顶部。为了将纹理正确的映射到四边形上,必须将纹理的四个角与四边形的四个角相对应。否则图形在四边形上显示时将会有错误。如果要将一张格式合格的图片(采用的是256

14、*256的图片)贴到正方体的一个面上,则需要联合使用glTexCoord2f和glVertex3f函数,如下:glBegin(GL_QUADS);/ 发布四边形绘图指令glTexCoord2f(0.0f, 0.0f); glVertex3fv( CubePoint0.p); glTexCoord2f(1.0f, 0.0f); glVertex3fv( CubePoint1.p);glTexCoord2f(1.0f, 1.0f); glVertex3fv( CubePoint2.p);glTexCoord2f(0.0f, 1.0f); glVertex3fv( CubePoint3.p);这样可

15、以用同样的方法在其他5个面贴上相应的纹理图。这样就可以得到6个面均贴好纹理图的小立方体。glBindTexture是OpenGL核心函数库中的一个函数。作用是选择生成的纹理。glBindTexture(GL_TEXTURE_2D,texturei),作用是选择生成的纹理。将texture1中的图片纹理绑定到程序中,然后就可以画出6个面均是该纹理的小立方体。这样画出的小立方体的六个面上的图片是相同的。以此类推,便可画出其他的小立方体。而我在该程序中实现了将小立方体的六个面贴上不同的图片,原理与上面类似。只需要在给每个面贴图片时都载入不同的纹理即可。OpenGL贴图具体流程如下: 图3(4)魔方整

16、体旋转和平移OpenGL中有给定的函数来实现图形的旋转和平移:glTranslatef和glRotatef。其中,glTranslatef用于平移和确定图形在界面上的位置。glTranslatef(x,y,z)作用是将图形平移到坐标为(x,y,z) 的点。其中,x,y分别为屏幕横向和纵向。z轴为垂直屏幕方向,沿屏幕向外为正方向。屏幕中心默认坐标为(0,0,0)。glRotatef函数控制魔方整体的旋转。如glRotatef(xrot,1.0f,0.0f,0.0f); 控制魔方围绕向量为(1,0,0)的直线(即x轴)旋转 xrot角度。控制魔方整体绕y轴和z轴的旋转可以用同样的方法实现。综合以上

17、分析结果,便可以写出控制有纹理贴图的一阶立方体的旋转程序。程序运行效果如下图4: 图4(5)魔方各个层面的随机旋转和同步更新索引27个立方体构成3X3魔方矩阵,对每个立方体进行编号。魔方体某层的旋转是基于选中的9个立方体绕魔方体的中心轴变化的。由此定义魔方体每个层面包含的子立方体集合初始索引编号:const BYTE SZP9 = 0,1,2,3,4,5,6,7,8; const BYTE SZS9 = 9,10,11,12,13,14,15,16,17; const BYTE SZM9 = 18,19,20,21,22,23,24,25,26; const BYTE SYM9 = 0,1,2

18、,11,10,9,18,19,20;const BYTE SYS9 = 3,4,5,14,13,12,21,22,23; const BYTE SYP9 = 6,7,8,17,16,15,24,25,26;const BYTE SXM9 =2,3,8,17,12,11,20,21,26;const BYTE SXS9 =1,4,7,16,13,10,19,22,25;const BYTE SXP9 = 0,5,6,15,14,9,18,23,24;预定义好这些层面目的是确定好旋转前后各个子立方体的相对位置。为了记录魔方体旋转之后各子立方的绝对位置,为此专门定义了同上类似的数组结构:BYTE Z

19、P9 = 0,1,2,3,4,5,6,7,8; BYTE ZS9 = 9,10,11,12,13,14,15,16,17; BYTE ZM9 = 18,19,20,21,22,23,24,25,26; BYTE YM9 = 0,1,2,11,10,9,18,19,20; BYTE YS9 = 3,4,5,14,13,12,21,22,23; BYTE YP9 = 6,7,8,17,16,15,24,25,26; BYTE XM9 =2,3,8,17,12,11,20,21,26; BYTE XS9 = 1,4,7,16,13,10,19,22,25; BYTE XP9 = 0,5,6,15,1

20、4,9,18,23,24; 魔方体几何位置旋转本质上就是同步更新各层面内的小立方的索引表。如,更新z方向上的第一层的小立方的索引表的部分代码如下:for( i=0;i27;i+)for( j=0;j9;j+)if( is_equal( &Cubei, &Static_Cube SZMj ) ZMk+ = i;is_equal()是判断旋转后的魔方体Cube的那些子立方Cubei与静态的魔方体Static_Cube的SZM层面内的子立方重合,找出之后作为ZM的新成员。最终能找到9个子立方作为新成员。而在前面已经讨论了如何实现立方体围绕某个轴旋转的问题。对某一层面内的9个小立方体均进行旋转操作,然

21、后进行更新索引,就可以得到旋转之后的魔方体。在本程序中我定义了Rotate_XM(),Rotate_XS(),Rotate_XP(),Rotate_YM(),Rotate_YS(),Rotate_YP(),Rotate_ZM(),Rotate_ZS(),Rotate_ZP()这9个函数,分别控制各个层面的旋转。由于魔方体各个方向上不同层面不能同时旋转,所以要在程序中保证各个层面之间的旋转互不冲突。在本程序中我定义了enable_XM_roatate(),enable_XS_roatate(),enable_XP_roatate(),enable_YM_roatate(),enable_YS_r

22、oatate(),enable_YP_roatate(),enable_ZM_roatate(),enable_ZS_roatate(),enable_ZP_roatate()这9个函数,用于判断某一方向上某一层面是否可以旋转。并且设置了rotX,rotY,rotZ三个全局变量。在以上9个函数中分别对这3个变量之一进行赋值。在enable_XM_roatate(),enable_XS_roatate(),enable_XP_roatate()三个函数中分别将rotX赋值为1,2,3,在enable_YM_roatate(),enable_YS_roatate(),enable_YP_roata

23、te()三个函数中分别将rotY赋值为1,2,3,在enable_ZM_roatate(),enable_ZS_roatate(),enable_ZP_roatate()三个函数中分别将rotZ赋值为1,2,3,同时保证rotX,rotY,rotZ一次只有一个不为零,这样就保证了各个层面旋转之间互相不冲突。(6)背景音乐的添加我在该程序中载入了背景音乐,方法比较简单。#include /提供与多媒体有关的接口#pragma comment(lib, WINMM.LIB) /导入winmm.lib库,实现对多媒体编程的支持在所建工程的文件夹中新建名为sound的文件夹,并在其中放入wav格式的音

24、乐爱你一万年。编写函数loadsound(),其调用函数PlaySound(sound爱你一万年.wav,NULL,SND_LOOP|SND_ASYNC|SND_FILENAME)加载爱你一万年背景音乐。(7)定时器的调用我认为本程序中使用Win32系统的定时器很关键,因为程序只能一次执行一个线程,而魔方在自身旋转的同时还有各个层面的自由随机旋转,还加上自身的平移等,所以必须用到定时器。在本程序中我用到了3个定时器::SetTimer(hWnd,1,2,NULL),:SetTimer(hWnd,2,1,TimerProc),:SetTimer(hWnd,3,0.5,CubeWalk)。定时器:

25、SetTimer(hWnd,1,2,NULL)的作用是把把其产生的消息加入消息队列中,由WM_TIMER接收并处理,以实现立方体的旋转。定时器:SetTimer(hWnd,2,1,TimerProc)的回调函数是TimerProc。函数TimerProc用来产生随机数。要控制各个层面的随机旋转,一共有18种情况,包括每个方向上每个层面上的正转和反转。故在TimerProc函数中对随机数的情况进行判断:int r = rand(); if( r%18=0)enable_XM_roatate(1);以上是18中情况中的一种,使魔方的XM层能够旋转,即在enable_XM_roatate(1)中进行

26、如下赋值:rotAngle = 1 rotCount = 0 rotX = 1 rotDirect =1在WM_TIMER中判断rotX,rotY,rotZ的值并进行相应的旋转操作。本程序中的另外一个定时器:SetTimer(hWnd,3,0.5,CubeWalk)作用是控制魔方的平移。前面已经介绍了魔方自身的平移函数glTranslatef。在程序的最开始定义变量RX和RY,glTranslatef(RX,0.0f,0.0f);glTranslatef(0.0f,RY,0.0f);则RX和RY代表魔方中心的横纵坐标。在回调函数CubeWalk中对RX和RY值进行处理和改变就可以控制魔方的平移

27、了。定时器的使用及其控制魔方的旋转和平移流程图如图5: 图5 定时器使用流程图2.3 数据结构分析 在本程序中为了很好的表示一个魔方体并且便于更好地计算,采用结构体和数组层层嵌套的形式。定义一个点的结构体,由3个坐标值构成: typedef struct GLfloat p3; stPoint;定义一个立方体的结构体,由8个顶点构成:typedef struct stPoint CubePoint8; stCube;定义由27个小立方体构成的数组:stCube Cube27; 2.4 重要函数分析 (1)窗口创建 程序中的函数GLvoid resizeScene(GLsizei width,G

28、Lsizei height )目的是重置OpenGL窗口的大小,具体又包含以下几个函数: glViewport(0,0,width,height)是OpenGL中的视口变化函数,作用是把视景体截取的图像按照怎样的高和宽显示到屏幕上。 glMatrixMode():指定哪一个矩阵是当前矩阵。glMatrixMode设置当前矩阵模式:GL_MODEVIEW,对模型视景矩阵堆栈应用随后的矩阵操作。GL_PROJECTION,对投影矩阵应用随后的矩阵操作。 glLoadIdentity()将矩阵清为单位矩阵,避免受其它矩阵操作的干扰,作用是将当前的用户坐标系的原点移到屏幕中心。 gluPerspect

29、ive的作用是设置透视投影矩阵,即越远的东西看起来越小的效果。gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f)45.0f表示将视角设置为45度,(GLfloat)width/(GLfloat)height表示窗口的纵横比,0.1f表示沿z轴方向的两裁面之间的距离的近处为0.1,100f表示沿z轴方向的两裁面之间的距离的远处为100,即图像在z轴方向上的坐标必须介于-0.1到-100之间,否则无法显示出来。(2)初始化在InitGL(GLvoid)中对窗体进行初始化效果:glShadeModel(GL_SMOOTH)作用是启用阴影平滑。glClearColor(0.5f, 0.0f, 0.0f, 0.5f)作用是设置背景为红色。glClearDepth(1.0f),作用是设置深度缓存。glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST),作用是做精细的透视修正。loadsound(),作用是导入歌曲爱你一万年。(3)OpenGL贴图 glGenTextur

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1