最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

基于OpenGL的3D旋转魔方实现

来源:动视网 责编:小OO 时间:2025-09-29 18:58:46
文档

基于OpenGL的3D旋转魔方实现

华中科技大学电子科学与技术系课程设计报告(2010--2011年度第2学期)名称:软件课程设计题目:基于OpenGL的3D旋转魔方实现院系:班级:学号:学生姓名:指导教师:设计周数:成绩:日期:年月日1.1目的………………………………………………………………………………………………..……21.2内容………………………………………………………………………………………………..……21.3取得的成果……………………………………………………………………………………………22.1程序原理………………
推荐度:
导读华中科技大学电子科学与技术系课程设计报告(2010--2011年度第2学期)名称:软件课程设计题目:基于OpenGL的3D旋转魔方实现院系:班级:学号:学生姓名:指导教师:设计周数:成绩:日期:年月日1.1目的………………………………………………………………………………………………..……21.2内容………………………………………………………………………………………………..……21.3取得的成果……………………………………………………………………………………………22.1程序原理………………
华中科技大学电子科学与技术系

课程设计报告

( 2010-- 2011年度第 2 学期)

名    称: 软件课程设计                  

  题    目: 基于OpenGL的3D旋转魔方实现 

院    系:             

班    级:                     

学    号:                   

学生姓名:                        

指导教师:                        

设计周数:                            

成    绩:                                   

           

日期:    年   月   日

1.1目的……………………………………………………………………………………………….. ……2

1.2内容……………………………………………………………………………………………….. ……2

1.3取得的成果……………………………………………………………………………………………2

2.1 程序原理………………………………………………………………………………………………3

2.2 程序流程………………………………………………………………………………………………4

2.3 数据结构………………………………………………………………………………………………13

2.4 重要函数………………………………………………………………………………………………13

3.程序分析与结果演示…………………………………………………………16

   3.1 成果演示………………………………………………………………………………………………16

   3.2 程序分析………………………………………………………………………………………………17

4.出现过的问题……………………………………………………………………18

5.心得和小节………………………………………………………………………19

1.课程设计介绍

   1.1目的

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

   1.2 内容

      (1)巩固和加强c语言相关编程知识,学会用Visual C++6.0进行c语言编程。

(2)掌握程序设计流程和思想,模块化结构分析以及程序设计流程,初步培养需求分析、软件测试、调试的能力。

      (3)掌握win32相关编程知识,了解windows程序内部运行机制。

     (4)掌握OpenGL贴图技术原理与函数实现,掌握OpenGL几何的移动、旋转等模式变化的原理。

     (5)掌握魔方图形构造原理,在掌握二阶魔方构造原理的基础上,构造出三阶魔方并实现其旋转。

   1.3 取得的成果

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

2.程序分析

2.1 程序原理

(1)OpenGL

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

      本项目是在Visual C++6.0开发环境下,使用OpenGL函数库,绘制魔方并实现魔方贴图、随机旋转、以及键盘控制等功能。采用基本图形的绘图函数及定位函数,添加相应纹理来实现魔方模型的绘制。通过读取载入BMP文件,应用纹理贴图技术来完成对魔方旋转面的处理。通过OpenGL中对图形的旋转和平移函数来实现对魔方整体的旋转和平移。

     (2)旋转

      在建立好空间三维模型后,要实现魔方体每一层面的旋转。而魔方体每一层面的旋转归结于每一个小立方体的旋转。每个小立方体的旋转又最终归结于每个点的旋转。对于一个坐标为(x,y,z)的点,如果围绕z轴逆时针旋转角度为a,则旋转之后z坐标不变,x和y坐标分别变为x*cosa - y*sina,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 uElapse为定时器触发周期,意味着多长时间执行一次;,TIMERPROC lpTimerFunc为该定时器执行时触发的函数。所以控制好不同定时器的触发周期和触发函数,就能使魔方的各个层面的旋转和平移互不冲突。

     2.2 程序流程

(1)WinMain主函数

     WinMain主函数是所有Win32程序的入口点。在WinMain函数里窗体的建立和消息循环,在消息循环中实现键盘、鼠标输入事件处理响应。在本程序中,要创建Window窗体和构建OpenGL设备绘图环境。

Window窗体创建步骤:

●窗体类注册:RegisterClass

●设置显示分辨率:ChangeDisplaySettings

●设置窗体大小:AdjustWindowRectEx

●创建窗体:CreateWindowEx

OpenGL绘图环境搭建:

●获取设备绘图环境(DC,DeviceContext):hDC=GetDC(hWnd)

●选择绘图环境像素格式:ChoosePixelFormat(hDC,&pfd),其中pfd为像素格式描述符,如果设置不对,OpenGL绘图失败,看不到正确的显示结果。

●设置绘图环境像素格式:SetPixelFormat(hDC,PixelFormat,&pfd)

●获取OpenGL绘图环境:hRC =wglCreateContext(hDC)

●设置OpenGL绘图环境:wglMakeCurrent(hDC,hRC)

(2)三维建模

一个三阶魔方体由27个小立方体构成,每个小立方体由8个顶点组成,而每个顶点又有x,y,z三个方向上的坐标值。这样由结构体的层层嵌套就可以对魔方体的每个小立方体、每个顶点进行操作。

typedef struct 

{

    GLfloat p[3];       //定义一个点的x,y,z坐标值

}stPoint;

typedef struct 

{

    stPoint CubePoint[8];//定义一个小立方体的8个顶点

}stCube;

如图2:

                       图2 

stCube  Cube[27];      //定义魔方体的27个小立方体

其中一个难点是怎样根据各个点的坐标值构造出魔方体,其实只要定义好每个顶点的坐标就行了。但是三阶魔方必须定义27*8=216个顶点的坐标值,而且很难用for循环实现,因为各个顶点的x,y,z坐标值几乎没有什么规律。但是如果能够将一个小魔方体作为一个整体来看待,工作量似乎会减轻很多。先在整个魔方体中间定义一个基准小立方体,则整个魔方体的各个小立方体均可以通过这个基准立方体的平移来实现,各个小立方体上各点的平移向量和小立方体中心的平移向量相同。

static stPoint CubePoint[8]=   //定义好基准小立方体,边长为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, -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

}; 

基准小立方体平移得到一个小立方体Cube[0]:

for(int i=0;i<8;i++)

    {

        Cube[0].CubePoint[i].p[0] = CubePoint[i].p[0] + 1.0f;

        Cube[0].CubePoint[i].p[1] = CubePoint[i].p[1] - 1.0f;

        Cube[0].CubePoint[i].p[2] = CubePoint[i].p[2] - 1.0f;

    }

其他26个立方体可通过同样的方法得到。我认为这是整个程序中最难也是最麻烦的一点。本程序是通过reset_model()这一函数来构造出整个魔方体的。

(3)OpenGL贴图实现

glGenTextures(1, &texture[i]),作用是利用载入的图像生成纹理。

glTexCoord2f(GLfloat s, GLfloat t) 函数用于绘制图形时指定纹理的坐标。第一个参数是X坐标,0.0是纹理的左侧,0.5是纹理的中点,1.0是纹理的右侧。第二个参数是Y坐标,0.0是纹理的底部,0.5是纹理的中点,1.0是纹理的顶部。为了将纹理正确的映射到四边形上,必须将纹理的四个角与四边形的四个角相对应。否则图形在四边形上显示时将会有错误。如果要将一张格式合格的图片(采用的是256*256的图片)贴到正方体的一个面上,则需要联合使用glTexCoord2f和glVertex3f函数,如下:

glBegin(GL_QUADS);// 发布四边形绘图指令

glTexCoord2f(0.0f, 0.0f); glVertex3fv( CubePoint[0].p); 

glTexCoord2f(1.0f, 0.0f); glVertex3fv( CubePoint[1].p);

glTexCoord2f(1.0f, 1.0f); glVertex3fv( CubePoint[2].p);

glTexCoord2f(0.0f, 1.0f); glVertex3fv( CubePoint[3].p);

这样可以用同样的方法在其他5个面贴上相应的纹理图。这样就可以得到6个面均贴好纹理图的小立方体。

glBindTexture是OpenGL核心函数库中的一个函数。作用是选择生成的纹理。glBindTexture(GL_TEXTURE_2D,texture[i]),作用是选择生成的纹理。

将texture[1]中的图片纹理绑定到程序中,然后就可以画出6个面均是该纹理的小立方体。这样画出的小立方体的六个面上的图片是相同的。以此类推,便可画出其他的小立方体。

而我在该程序中实现了将小立方体的六个面贴上不同的图片,原理与上面类似。只需要在给每个面贴图片时都载入不同的纹理即可。OpenGL贴图具体流程如下:

                        图3

(4)魔方整体旋转和平移

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轴的旋转可以用同样的方法实现。

综合以上分析结果,便可以写出控制有纹理贴图的一阶立方体的旋转程序。程序运行效果如下图4:

          图4

(5)魔方各个层面的随机旋转和同步更新索引

27个立方体构成3X3魔方矩阵,对每个立方体进行编号。魔方体某层的旋转是基于选中的9个立方体绕魔方体的中心轴变化的。由此定义魔方体每个层面包含的子立方体集合初始索引编号:

const BYTE    SZP[9] = {0,1,2,3,4,5,6,7,8}; 

const BYTE   SZS[9] = {9,10,11,12,13,14,15,16,17}; 

const BYTE   SZM[9] = {18,19,20,21,22,23,24,25,26}; 

const BYTE   SYM[9] = {0,1,2,11,10,9,18,19,20};

const BYTE   SYS[9] = {3,4,5,14,13,12,21,22,23}; 

const BYTE   SYP[9] = {6,7,8,17,16,15,24,25,26};

const BYTE   SXM[9] ={2,3,8,17,12,11,20,21,26};

const BYTE   SXS[9] ={1,4,7,16,13,10,19,22,25};

const BYTE   SXP[9] = {0,5,6,15,14,9,18,23,24};

预定义好这些层面目的是确定好旋转前后各个子立方体的相对位置。为了记录魔方体旋转之后各子立方的绝对位置,为此专门定义了同上类似的数组结构:

BYTE   ZP[9] = {0,1,2,3,4,5,6,7,8}; 

BYTE   ZS[9] = {9,10,11,12,13,14,15,16,17}; 

BYTE   ZM[9] = {18,19,20,21,22,23,24,25,26}; 

BYTE   YM[9] = {0,1,2,11,10,9,18,19,20}; 

BYTE   YS[9] = {3,4,5,14,13,12,21,22,23}; 

BYTE   YP[9] =  {6,7,8,17,16,15,24,25,26};  

BYTE   XM[9] ={2,3,8,17,12,11,20,21,26}; 

BYTE   XS[9] = {1,4,7,16,13,10,19,22,25}; 

BYTE   XP[9] = {0,5,6,15,14,9,18,23,24};   

魔方体几何位置旋转本质上就是同步更新各层面内的小立方的索引表。如,更新z方向上的第一层的小立方的索引表的部分代码如下:

for( i=0;i<27;i++)

{

for( j=0;j<9;j++)

if( is_equal(  &Cube[i], &Static_Cube[ SZM[j] ]  ) 

{

ZM[k++] = i;

}

}

is_equal()是判断旋转后的魔方体Cube的那些子立方Cube[i]与静态的魔方体Static_Cube的SZM层面内的子立方重合,找出之后作为ZM的新成员。最终能找到9个子立方作为新成员。

而在前面已经讨论了如何实现立方体围绕某个轴旋转的问题。对某一层面内的9个小立方体均进行旋转操作,然后进行更新索引,就可以得到旋转之后的魔方体。在本程序中我定义了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_roatate(),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_roatate()三个函数中分别将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格式的音乐《爱你一万年》。

编写函数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)。

定时器::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)中进行如下赋值:

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值进行处理和改变就可以控制魔方的平移了。定时器的使用及其控制魔方的旋转和平移流程图如图5:

                   图5 定时器使用流程图

2.3 数据结构分析

   在本程序中为了很好的表示一个魔方体并且便于更好地计算,采用结构体和数组层层嵌套的形式。

定义一个点的结构体,由3个坐标值构成:   

typedef struct {

GLfloat p[3];   

}stPoint;

定义一个立方体的结构体,由8个顶点构成:

typedef struct {

    stPoint CubePoint[8];  

}stCube;

定义由27个小立方体构成的数组:

stCube  Cube[27];   

2.4 重要函数分析

   (1)窗口创建

        程序中的函数GLvoid resizeScene(GLsizei width,GLsizei height )目的是重置OpenGL窗口的大小,具体又包含以下几个函数:

        glViewport(0,0,width,height)是OpenGL中的视口变化函数,作用是把视景体截取的图像按照怎样的高和宽显示到屏幕上。

        glMatrixMode():指定哪一个矩阵是当前矩阵。glMatrixMode设置当前矩阵模式:GL_MODEVIEW,对模型视景矩阵堆栈应用随后的矩阵操作。GL_PROJECTION,对投影矩阵应用随后的矩阵操作。

         glLoadIdentity()将矩阵清为单位矩阵,避免受其它矩阵操作的干扰,作用是将当前的用户坐标系的原点移到屏幕中心。

         gluPerspective的作用是设置透视投影矩阵,即越远的东西看起来越小的效果。

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贴图

 glGenTextures(1, &texture[i]),作用是利用载入的图像生成纹理。

glBindTexture(GL_TEXTURE_2D, texture[i]),作用是选择生成的纹理。

glTexCoord2f(0.0f,0.0f),作用是设置纹理坐标。

glVertex3fv( CubePoint[0].p),作用是设置对应的立方体的顶点坐标。

glEnable(GL_TEXTURE_2D),作用是启用纹理映射,此点很关键。 如果不用这个函数,图片将不能贴到立方体的六个面上。

(4)旋转和平移

在本程序中用到了OpenGL中的平移函数glTranslatef(x,y,z)和旋转函数。

glTranslatef(x,y,z)表示图形中心平移到坐标为(x,y,z)的点处。

与其类似,glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)表示图形绕经过原点和点(x,y,z)的轴旋转角度angle。方向满足右手定则。

而本程序中控制魔方层面旋转的函数前面已经介绍过,一共有9个函数,分别控制三个方向上各三个层面的旋转,旋转方向由全局变量rotDirect是1或-1来决定。

(5)消除累计误差

为了避免魔方体层面的旋转之后带来的累计误差,在判断两个立方体是否重合时,必须消除这种累计误差。所以判断两个点是否重合时,如果两个点的三个坐标值均相差较小,应该令其分别相等,以消除误差。

if( fabs(x1 - x2)<1e-1 && fabs(y1-y2)<1e-1 && fabs(z1-z2)<1e-1){

 }

(6)屏保函数

控制魔方移动是通过定时器Timer3来实现的,而Timer3的回调函数为CubeWalk()。在该函数中,只要控制RX和RY的增减即可。RX和RY为全局变量,初值为零,所以魔方最初的位置是在屏幕的中心。

RX+=0.1

RY+=0.1

就可以控制魔方每次向斜方向运动。为了实现魔方的反弹效果,需要另外定义两个全局变量turn_x和turn_y,初值分别为1。且令

RX+=(turn_x*0.01)

RY+=(turn_y*0.01)

当魔方达到边界时,将turn_x和turn_y中的一个值取相反值,就可以使RX或RY反向增长,从而达到反弹的效果。经过试验,确定屏幕横向宽大致为16,纵向宽大致为8。而判断魔方达到边界时不能用“==”来进行判断,因为会有误差。为了消除误差,采用fabs()函数来进行一定范围内的判断。

if(fabs(RX+8)<0.01||fabs(RX-8)<0.01)

else if(fabs(RY+4)<0.01||fabs(RY-4)<0.01)

3.程序分析与结果演示

   3.1 成果展示

3.2程序分析

程序整体流程图分析如下:

图6 程序整体流程图

 

4.出现过的问题

其实编程不可能一遍成功,我在编程的过程中也遇到了很多问题。

(1)我开始将范例程序看懂之后,一气呵成将三阶魔方的程序编写出来了,但是写出来的程序只能控制三阶魔方的一部分层面旋转。于是我想实现三阶魔方任一层面随机旋转的效果,但是程序写完时候运行结果却出人意料之外。

可以明显的看到魔方各个层面的旋转发生冲突,导致魔方产生扭曲。于是我仔细分析产生这种的原因,想了很久,后来想到会不会是写程序时控制各个层面的旋转的控制量的值有重复,从而产生冲突。然后我就把一个方向上的三个层面旋转的控制量的值改成不同的1,2,3,结果就可以正常运行了。

(2)我在实现三阶魔方效果后,就想实现三阶魔方的自由反弹效果,我构思的算法自认为是对的,其实也比较简单,当时控制其反弹的源码如下:

if(RX=-8||RX=8)

 

 

  RY=-4||RY=4)

 

 

 

 

但是实际运行效果就是与我预想的不一样。魔方到了边界,总是不反弹,径直的跑到屏幕外面去,不见了踪影。这个问题困扰了我很久,一直得不到解决。我曾经想过是不是与屏幕长宽表示错了有关,但是无论我把屏幕长宽设为多少,魔方总是不反弹。后来我偶然想到,会不会是因为定时器的执行周期太短,一次移动距离太短,产生了误差,所以到达边界时程序没有判断出来。于是我用了fabs函数,给RX和RY设定了一定的误差范围,程序竟然可以运行成功了。这说明我的假设是对的。所以以后碰到问题要认真思考,也许灵感就在一瞬间闪现。

5 心得和小节

   这段时间以来觉得自己收获还是挺大的。开始选这个课题是觉得三阶旋转魔方肯定比较有意思,看着也比较有挑战性。经过这段时间以来的学习,我加深了对三阶旋转魔方实现的认识,觉得这个课题的确是在我们的能力范围内,除了OpenGL的绘图知识比较陌生以外,其他的比如魔方的建模、控制魔方的旋转以及定时器的使用等函数或算法都是我们能力所能及的,当然这必须建立在有比较好的c语言基础上,能对c语言的数组、函数、指针及结构体有比较好的掌握。

 的效果。虽然看起来有点难,但是我会继续研究这个程序,争取能够实现预期的效果。

参考文献

[1](美)施瑞奈尔.OpenGL编程指南.第七版.2012年,第5次:第5页.

[2]刘正林.周纯杰编著.最新c语言程序设计教程.武汉:华中科技大学出版社,2003

[3]谭浩强编著.c语言程序设计.北京:清华大学出版社,2002

文档

基于OpenGL的3D旋转魔方实现

华中科技大学电子科学与技术系课程设计报告(2010--2011年度第2学期)名称:软件课程设计题目:基于OpenGL的3D旋转魔方实现院系:班级:学号:学生姓名:指导教师:设计周数:成绩:日期:年月日1.1目的………………………………………………………………………………………………..……21.2内容………………………………………………………………………………………………..……21.3取得的成果……………………………………………………………………………………………22.1程序原理………………
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top