基于OpenGL的3D旋轉(zhuǎn)魔方的實(shí)現(xiàn)終期報(bào)告加源碼
《基于OpenGL的3D旋轉(zhuǎn)魔方的實(shí)現(xiàn)終期報(bào)告加源碼》由會(huì)員分享,可在線閱讀,更多相關(guān)《基于OpenGL的3D旋轉(zhuǎn)魔方的實(shí)現(xiàn)終期報(bào)告加源碼(61頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
1、華中科技大學(xué)電子科學(xué)與技術(shù)系 課程設(shè)計(jì)報(bào)告 ( 2011-- 2012年度第 2 學(xué)期) 名 稱: 軟件課程設(shè)計(jì) 題 目: 基于OpenGL的3D旋轉(zhuǎn)魔方實(shí)現(xiàn) 院 系: XXXXXX 班 級(jí): XXXXX 學(xué) 號(hào): U201014185 學(xué)生姓名: X X X 指導(dǎo)教師: X X X
2、設(shè)計(jì)周數(shù): XXXX 成 績(jī): 日期: 2012 年 5月 24日 1 目 錄 1.課程設(shè)計(jì)介紹……………………………………………………………… 1 1.1.內(nèi)容……………………………………………………………………… 1 1.2.目的 ………………………………………………………………………1 1.3.取得的成果 ……………………………………………………………… 1 2.程序分析 ……………………………
3、……………………… ……………2 2.1. 程序原理………………………………………………………………… 2 2.1. 程序流程………………………………………………………………… 3 2.3. 數(shù)據(jù)結(jié)構(gòu)………………………………………………………………… 8 2.4. 重要函數(shù)用法分析 ……………………………………………………… 8 3.結(jié)果演示與程序分析 …………………………………………………… 9 3.1. 成果演示………………………………………………………………… 9 3.2. 程序分析 ……………………………………………………………… 11 4.編程中遇到的問(wèn)題………
4、…………………………………………………12 5.課程設(shè)計(jì)小結(jié)………………………………………………………………13 參考文獻(xiàn)………………………………………………………………………14 基于OpenGL的3D旋轉(zhuǎn)魔方實(shí)現(xiàn) 1. 課程設(shè)計(jì)介紹 1.1 目的 當(dāng)今計(jì)算機(jī)技術(shù)流行,引領(lǐng)了各行各業(yè)。而程序是計(jì)算機(jī)的靈魂,因此編程能力對(duì)當(dāng)今的學(xué)生而言至關(guān)重要。雖然我們?cè)谇捌谝呀?jīng)學(xué)習(xí)了C語(yǔ)言,但是還只對(duì)程序有一些簡(jiǎn)單的認(rèn)識(shí),說(shuō)實(shí)話,是很淺顯的認(rèn)識(shí)。通過(guò)本軟件課程設(shè)計(jì)的學(xué)習(xí),可以從整體上對(duì)軟件工程和項(xiàng)目有全面的認(rèn)識(shí)。通過(guò)此次課程設(shè)計(jì),可以鍛煉編程能力,激發(fā)對(duì)編程的興趣,同時(shí)也能培養(yǎng)
5、良好的編程習(xí)慣。這對(duì)于個(gè)人今后的學(xué)習(xí),今后的工作乃至今后的生活都會(huì)產(chǎn)生重要的影響。對(duì)于國(guó)家而言,極大的推動(dòng)了計(jì)算機(jī)普及教育,提高了大學(xué)生的計(jì)算機(jī)使用水平,具有重大的意義。 1.2 內(nèi)容 (1) 通過(guò)此次項(xiàng)目掌握軟件開(kāi)發(fā)模式,模塊化結(jié)構(gòu)分析以及程序設(shè)計(jì)流程 (2) 學(xué)會(huì)使用VC++6.0進(jìn)行編程 (3) 掌握有關(guān)程序設(shè)計(jì)的思想,數(shù)據(jù)結(jié)構(gòu)的知識(shí),掌握C語(yǔ)言算法,掌握OpenGL編程知識(shí)如貼圖與鍵盤控制 (4) 掌握win32編程知識(shí),了解windows程序內(nèi)部運(yùn)行機(jī)制 (5) 初步培養(yǎng)需求分析、軟件測(cè)試、調(diào)試的能力 (6) 在2X2魔方的基礎(chǔ)上,嘗試編寫(xiě)3X3的魔方,并實(shí)現(xiàn)其旋轉(zhuǎn)
6、 1.3 取得的成果 在理解Magic2D例子程序的基礎(chǔ)上,借助了Win32平臺(tái)進(jìn)行了一系列調(diào)試和學(xué)習(xí)。在此次項(xiàng)目中,學(xué)習(xí)了Visual C++6.0軟件開(kāi)發(fā)環(huán)境,熟練掌握了Win32 Application開(kāi)發(fā)流程。同時(shí)也學(xué)習(xí)了OpenGL的基本知識(shí),掌握了一些OpenGL的重要技術(shù)與重要函數(shù)的使用,編寫(xiě)了一些簡(jiǎn)單的OpenGL程序。參考Magic2D例子流程,我對(duì)原程序進(jìn)行了比較大的修改,并換上了自己的圖片,實(shí)現(xiàn)了一個(gè)立方體貼六張不同的圖片,并編寫(xiě)出了自己的2X2魔方程序。根據(jù)相似度分析,成功的編寫(xiě)出了3X3旋轉(zhuǎn)魔方,并自己設(shè)計(jì)了算法,實(shí)現(xiàn)了各個(gè)層面的轉(zhuǎn)動(dòng),轉(zhuǎn)動(dòng)效果很完美。同時(shí),為了增加
7、程序的娛樂(lè)效果,我加入了歌曲最炫民族風(fēng),雖然很簡(jiǎn)單,不過(guò)感覺(jué)非常實(shí)用且有趣。 2. 程序分析 2.1 程序原理 (1)OpenGL OpenGL是一個(gè)開(kāi)放的三維圖形軟件包,它獨(dú)立于窗口系統(tǒng)和操作系統(tǒng),以它為基礎(chǔ)開(kāi)發(fā)的應(yīng)用程序可以十分方便地在各種平臺(tái)間移植;OpenGL可以與Visual C++緊密接口,便于實(shí)現(xiàn)機(jī)械手的有關(guān)計(jì)算和圖形算法,可保證算法的正確性和可靠性;OpenGL使用簡(jiǎn)便,效率高。 本設(shè)計(jì)是在Visual C++6.0開(kāi)發(fā)環(huán)境下,使用OpenGL(Open Graphics Library)函數(shù)庫(kù),繪制魔方并實(shí)現(xiàn)魔方的繪制、隨機(jī)旋轉(zhuǎn)、貼圖以及鍵盤控制
8、等功能。采用基本圖形的繪圖函數(shù)及定位函數(shù),添加相應(yīng)紋理來(lái)實(shí)現(xiàn)魔方模型的繪制。通過(guò)讀取載入BMP文件,應(yīng)用紋理貼圖技術(shù)來(lái)完成對(duì)魔方旋轉(zhuǎn)面的處理。 (2)模型的旋轉(zhuǎn) 首先對(duì)立方體進(jìn)行建模。一個(gè)立方體由8個(gè)點(diǎn)組成,8個(gè)點(diǎn)組成6個(gè)面片,對(duì)立方體的幾何操作本質(zhì)上就是對(duì)這6個(gè)平面的操作(繪制、紋理、旋轉(zhuǎn)和平移等)。點(diǎn)的索引號(hào)確定后,每個(gè)面片也就確定了,如{0,1,2,3}四個(gè)點(diǎn)構(gòu)成Z向正投影面。 立方體在空間的旋轉(zhuǎn),歸根到底是其頂點(diǎn)的旋轉(zhuǎn),如空間點(diǎn)(x, y, z)繞Z軸旋轉(zhuǎn)a對(duì)應(yīng)的旋轉(zhuǎn)矩陣: cosa sina -sina cosa 一個(gè)立方體pCube繞Z軸旋轉(zhuǎn)a后對(duì)應(yīng)的坐標(biāo)變化
9、為: for( int i=0;i<8;i++) { float x,y; x= pCube->CubePoint[i].p[0]; y= pCube->CubePoint[i].p[1]; pCube->CubePoint[i].p[0] = x*cosa - y*sina; pCube->CubePoint[i].p[1] = x*sina + y*cosa; } 其它軸的旋轉(zhuǎn)類似。由于魔方體層面的旋轉(zhuǎn)是90,在某個(gè)層面內(nèi)一個(gè)子立方體Ci會(huì)被另外一個(gè)Cj完全替換,因此旋轉(zhuǎn)后必須同步更新魔
10、方體Cube各層面內(nèi)包含的子立方的索引號(hào)。為了簡(jiǎn)化算法,只需查找旋轉(zhuǎn)后Cube[i]在Static_Cube中對(duì)應(yīng)的小立方編號(hào)j與i的位置匹配。 2.2 程序的流程 通過(guò)分析,整個(gè)程序大致可以分為6個(gè)子功能模塊 (1) Win32應(yīng)用程序框架 WinMain主函數(shù)是所有Win32程序的入口點(diǎn)。在WinMain函數(shù)里實(shí)現(xiàn)Window是窗體的建立和消息循環(huán),在消息循環(huán)中實(shí)現(xiàn)鍵盤、鼠標(biāo)輸入事件處理響應(yīng),具體內(nèi)容可參考VC程序參考手冊(cè)。在本課程程序中,不僅要?jiǎng)?chuàng)建Window窗體,而且構(gòu)建OpenGL設(shè)備繪圖環(huán)境。 Window窗體創(chuàng)建步驟: l 窗體類注冊(cè):RegisterCla
11、ss l 設(shè)置顯示分辨率:ChangeDisplaySettings l 設(shè)置窗體大?。篈djustWindowRectEx l 創(chuàng)建窗體:CreateWindowEx OpenGL繪圖環(huán)境搭建: l 獲取設(shè)備繪圖環(huán)境(DC,DeviceContext):hDC=GetDC(hWnd) l 選擇繪圖環(huán)境像素格式:ChoosePixelFormat(hDC,&pfd),其中pfd為像素格式描述符,如果設(shè)置不對(duì),OpenGL繪圖失敗,看不到正確的顯示結(jié)果。 l 設(shè)置繪圖環(huán)境像素格式:SetPixelFormat(hDC,PixelFormat,&pfd) l 獲取Ope
12、nGL繪圖環(huán)境:hRC =wglCreateContext(hDC) l 設(shè)置OpenGL繪圖環(huán)境:wglMakeCurrent(hDC,hRC) (2)空間建模得到3階魔方 顯然,要建立3X3的魔方必須首先建立單個(gè)魔方的模型,然后通過(guò)對(duì)單個(gè)立方體進(jìn)行平移從而得到3X3的魔方。 平移單個(gè)立方體通過(guò)reset_model( )函數(shù)中的語(yǔ)句實(shí)現(xiàn) for(i=0;i<8;i++) { Cube[0].CubePoint[i].p[0] = CubePoint[i].p[0]-2.0f ; Cube[0].CubePoint[i].p[1]
13、= CubePoint[i].p[1]-2.0f ; Cube[0].CubePoint[i].p[2] = CubePoint[i].p[2]+2.0f; } 上述代碼只得到了編號(hào)為0的立方體,其他編號(hào)的立方體同理可以得到 構(gòu)成2X2的魔方需要8個(gè)立方體,構(gòu)建3X3的魔方則需要27個(gè)立方體。根據(jù)2階魔方的一些方法,類比到3階魔方。則首先對(duì)魔方的立方體進(jìn)行編號(hào),然后通過(guò)編號(hào)得到魔方各層所包含立方體的編號(hào)。其中編號(hào)為 BYTE ZP[9] = {0,1,2,3,4,5,6,7,8}; //z軸方向正向一層 BYTE ZZ[9] = {9,10,11,12
14、,13,14,15,16,17}; //z軸方向中間一層 BYTE ZM[9] = {18,19,20,21,22,23,24,25,26}; //z軸方向負(fù)向一層 BYTE YM[9] = {0,1,2,11,10,9,18,19,20}; //y軸方向負(fù)向一層 BYTE YZ[9] = {3,4,5,14,13,12,21,22,23}; //y軸方向中間一層 BYTE YP[9] = {6,7,8,17,16,15,24,25,26}; //y軸方向正向一層 BYTE XM[9] = {2,3,8,17,12,11,20,21,
15、26}; //x軸方向正向一層 BYTE XZ[9] = {1,4,7,16,13,10,19,22,25}; /x軸方向中間一層 BYTE XP[9] = {0,5,6,15,14,9,18,23,24}; //x軸方向負(fù)向一層 (3)OpenGL紋理貼圖 以下是紋理貼圖的流程,其中實(shí)現(xiàn)了一個(gè)立方體貼六張圖片 GLuint texture[6] 創(chuàng)建紋理存儲(chǔ) AUX_RGBImageRec* TextureImage[6]; 創(chuàng)建紋理的存儲(chǔ)空間
16、TextuteImage[i]=auxDIBImageLoad(“picture/y1.bmp) 調(diào)用此函數(shù)六次載入六張不同的圖片 glGenTexTures(1,&texture[i]) 用載入的圖像生成六個(gè)紋理 glBindTextures(GL_TEXTURE_2D,texture[i] 選擇生成的紋理 glBegin(GL_QUADS); glTexCoord(0.0f,0.0f); glVertex3fv(CubePoint[0].p); …… glEnd(); 每次選擇不同的紋理,然后利用OpenGL是狀態(tài)機(jī)的性質(zhì),可以給每個(gè)面貼上不同的圖片
17、 (4)同步更新索引 在整個(gè)程序中,同步更新索引所涉及到的算法可以算是最核心的了。當(dāng)然,你也可以讓每層每個(gè)周期轉(zhuǎn)動(dòng)360度,這樣就不需要?jiǎng)討B(tài)更新索引了,因?yàn)槊看无D(zhuǎn)動(dòng)前后,立方體的相對(duì)坐標(biāo)位置并沒(méi)有改變。但是這樣得到的旋轉(zhuǎn)效果并不好,因?yàn)檫@并沒(méi)有考慮到魔方旋轉(zhuǎn)的所有情況,每次旋轉(zhuǎn)后魔方都沒(méi)有被打亂。 由于涉及到動(dòng)態(tài)刷新索引,于是按照常理定義一個(gè)靜態(tài)的魔方與動(dòng)態(tài)的魔方進(jìn)行比較。類似動(dòng)態(tài)魔方的編號(hào)可以得到靜態(tài)魔方的編號(hào)。 const BYTE SZP[9] = {0,1,2,3,4,5,6,7,8}; //z軸
18、方向正向一層 const BYTE SZZ[9] = {9,10,11,12,13,14,15,16,17}; //z軸方向中間一層 const BYTE SZM[9] = {18,19,20,21,22,23,24,25,26}; //z軸方向負(fù)向一層 const BYTE SYM[9] = {0,1,2,11,10,9,18,19,20}; //y軸方向負(fù)向一層 const BYTE SYZ[9] = {3,4,5,14,13,12,21,22,23}; //y軸方向中間一層 const BYTE SYP[9] = {6,
19、7,8,17,16,15,24,25,26}; //y軸方向正向一層 const BYTE SXM[9] = {2,3,8,17,12,11,20,21,26}; //x軸方向正向一層 const BYTE SXZ[9] = {1,4,7,16,13,10,19,22,25}; //x軸方向中間一層 const BYTE SXP[9] = {0,5,6,15,14,9,18,23,24}; //x軸方向負(fù)向一層 然后編寫(xiě)一個(gè)函數(shù)int is_equal(stCube *pc1,stCube *pc2)判斷兩個(gè)立方體是否重合,這
20、個(gè)函數(shù)的算法就是比較立方體所有頂點(diǎn)的坐標(biāo)是否相同。 最后一步編寫(xiě)函數(shù)void Update_Cube_index(),由于魔方轉(zhuǎn)動(dòng)情況總體上有九種情況,則該函數(shù)必須編寫(xiě)九塊功能類似的代碼,現(xiàn)在只列出X軸負(fù)向一層刷新索引的算法。 int i,j,k=0; k =0 ; for( i=0;i<9;i++) { for( j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SZM[i] ] ) ) { ZM[k++] = j; } } (5)魔方的旋轉(zhuǎn)以及
21、鍵盤控制對(duì)魔方的平移 魔方層面的旋轉(zhuǎn)已經(jīng)在前面介紹,此處除了層面旋轉(zhuǎn)還有魔方的整體旋轉(zhuǎn)。只需調(diào)用庫(kù)函數(shù)即可即可。 glRotatef(xrot,1.0,0.0,0.0); //使魔方繞x軸轉(zhuǎn)動(dòng)xrot度 glRotatef(yrot,0.0,1.0,0.0); //使魔方繞y軸轉(zhuǎn)動(dòng)yrot度 glRotatef(zrot,0.0,0.0,1.0); //使魔方繞z軸轉(zhuǎn)動(dòng)zrot度 (6)定時(shí)器對(duì)魔方層面旋轉(zhuǎn)的控制 為了控制魔方的轉(zhuǎn)
22、動(dòng),首先定義了函數(shù)void enable_X_roatate(int direction),void enable_Y_roatate(int direction),void enable_Z_roatate(int direction)以確定旋轉(zhuǎn)軸和旋轉(zhuǎn)方向,同時(shí)定義了void Rotate_X(int ii),void Rotate_Y(int ii),void Rotate_Z(int ii)來(lái)指定是哪一層的旋轉(zhuǎn)。 然后定義兩個(gè)計(jì)時(shí)器Time1和Time2,其中Timer1的消息由WM_TIMER接收并處理,以實(shí)現(xiàn)立方體的旋轉(zhuǎn)。Timer2的消息由TimerProc函數(shù)處理,用于生
23、成控制量以控制旋轉(zhuǎn)軸和旋轉(zhuǎn)方向。
流程如圖:
魔方的層面旋轉(zhuǎn)
r除6得到控制參數(shù)
r=rand()
得到隨機(jī)數(shù)r
Timer2
cs除3的余數(shù)得到控制參數(shù)
Timer1實(shí)現(xiàn)旋轉(zhuǎn)
cs=rand()
得到隨機(jī)數(shù)cs
(7)背景音樂(lè)的添加
為了程序有更豐富的效果,我添加了歌曲最炫民族風(fēng),方法也很簡(jiǎn)單。
#include
24、b庫(kù),實(shí)現(xiàn)對(duì)多媒體編程的支持 編寫(xiě)函數(shù)loadsound(),其調(diào)用函數(shù)PlaySound("sound\\最炫民族風(fēng).wav",NULL,SND_LOOP|SND_ASYNC|SND_FILENAME)加載最炫民族風(fēng)味背景音樂(lè)。 (8)窗口文字的添加 為了添加自己的信息,我在程序窗口中加了文字 void drawString(const char* str),實(shí)現(xiàn)添加英文字符。 void drawCNString(const char* str)實(shí)現(xiàn)添加中文字符 void selectFont(int size, int cha
25、rset, const char* face),實(shí)現(xiàn)變換字體 2.3 數(shù)據(jù)結(jié)構(gòu) 本程序定義了記錄魔方體每個(gè)小塊編號(hào)的數(shù)組Cube[i]及相應(yīng)的定態(tài)數(shù)組Static_Cube,用來(lái)對(duì)魔方體變化過(guò)程中的相對(duì)位置進(jìn)行索引及重新定位。定義了立方體記錄頂點(diǎn)位置的數(shù)組CubePoint[i]及相應(yīng)靜態(tài)數(shù)組stPoint CubePoint[i],用來(lái)確定魔方體的旋轉(zhuǎn),因?yàn)樾D(zhuǎn)歸根結(jié)底是其頂點(diǎn)位置的旋轉(zhuǎn)。定義了用來(lái)記錄魔方體各個(gè)面上子塊編號(hào)的數(shù)組ZP/ZZ/ZM,YP/YZ/YM,XP/XZ/XM,及其對(duì)應(yīng)靜態(tài)數(shù)組。定義了數(shù)組TextureImage[i]來(lái)接收紋理。 2.4 重要函數(shù)用法分
26、析 (1)窗口創(chuàng)建 GLvoid resizeScene(GLsizei width,GLsizei height ) 這個(gè)函數(shù)的目的是重置OpenGL窗口的大小,具體又包含以下五個(gè)函數(shù) glViewport(0,0,width,height); glViewport是OpenGL中視口變化函數(shù),根據(jù)窗口的實(shí)時(shí)變化重繪窗口,它負(fù)責(zé)把視景體截取的圖像按照怎樣的高和寬顯示到屏幕上。 glMatrixMode(GL_PROJECTION)、glMatrixMode(GL_MODELVIEW) 這兩個(gè)函數(shù)原型都是glMatrixMode函數(shù)。glMatrixMo
27、de這個(gè)函數(shù)其實(shí)就是要指定操作的是哪種矩陣。如果參數(shù)是GL_PROJECTION,這個(gè)是投影的意思,如果參數(shù)是GL_MODELVIEW,這個(gè)是對(duì)模型視景的操作,用于對(duì)三維場(chǎng)景中坐標(biāo)系的變換操作。 glLoadIdentity() glLoadIdentity該函數(shù)的功能是將當(dāng)前的用戶坐標(biāo)系的原點(diǎn)移到了屏幕中心,就像一個(gè)復(fù)位操作 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f) gluPerspective的作用是設(shè)置透視投影矩陣,意味著越遠(yuǎn)的東西看起來(lái)越小。45.0f表示將視角設(shè)置為45度,(GLfloat
28、)width/(GLfloat)height表示窗口的縱橫比,0.1f表示沿z軸方向的兩裁面之間的距離的近處為0.1,100f表示沿z軸方向的兩裁面之間的距離的遠(yuǎn)處為100 (2)初始化操作 glShadeModel(GL_SMOOTH),作用是啟用陰影平滑。 glClearColor(0.0f, 0.0f, 0.0f, 0.5f),作用是將背景設(shè)置為黑色。 glClearDepth(1.0f),作用是設(shè)置深度緩存。 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST),作用是做精細(xì)的透
29、視修正。 loadsound(),作用是導(dǎo)入歌曲最炫民族風(fēng)。 (3)OpenGL貼圖 glGenTextures(1, &texture[i]),作用是利用載入的圖像生成紋理。 glBindTexture(GL_TEXTURE_2D, texture[i]),作用是選擇生成的紋理。 glTexCoord2f(0.0f,0.0f),作用是設(shè)置紋理坐標(biāo)。 glEnable(GL_TEXTURE_2D),作用是啟用紋理映射,此點(diǎn)很關(guān)鍵。 (4)平移與旋轉(zhuǎn) glTranslatef(x, y, z)
30、 平移函數(shù)。表示相對(duì)于當(dāng)前所在的屏幕位置沿著 X, Y 和 Z 軸移動(dòng)x,y和z個(gè)單位。 glRotatef(angle, x, y, z) 旋轉(zhuǎn)函數(shù)。與glTranslatef(x, y, z)類似,glRotatef(angle, x, y, z)也是對(duì)坐標(biāo)系進(jìn)行操作。旋轉(zhuǎn)軸經(jīng)過(guò)原點(diǎn),方向?yàn)?x,y,z),旋轉(zhuǎn)角度為angle,方向滿足右手定則。 (5)添加窗口文字 void drawString(const char* str),實(shí)現(xiàn)添加英文字符。 void drawCNString(const char* str)實(shí)現(xiàn)添加中文字符 void selectFont(
31、int size, int charset, const char* face),實(shí)現(xiàn)變換字體 3. 結(jié)果演示與程序分析 3.1成果展示 魔方體旋轉(zhuǎn) 對(duì)魔方定位 對(duì)魔方進(jìn)行編號(hào) 3.2程序分析 紋理綁定 循環(huán)調(diào)用 生成紋理 3X3魔方有27個(gè)小塊,對(duì)每個(gè)小塊分別進(jìn)行編號(hào)。先畫(huà)出一個(gè)子塊,經(jīng)過(guò)向相應(yīng)方向的平移,獲得完整的魔方體。 魔方由函數(shù)glTranslatef(float x,float y,float z)定位,再由函數(shù)glRotate(float angle,float x,float y,float z)進(jìn)行旋轉(zhuǎn),然
32、后由函數(shù)glBindTexture(GLenum target,GLunit textureName)進(jìn)行紋理與相應(yīng)面的綁定(紋理已由glGenTextures()函數(shù)來(lái)產(chǎn)生),最后再用函數(shù)glBegin(GL_QUADS)畫(huà)出正方面,從而描繪出了魔方的一個(gè)小面。循環(huán)調(diào)用就可以繪制出的魔方。 循環(huán)調(diào)用程序的紋理綁定和旋轉(zhuǎn)過(guò)程就實(shí)現(xiàn)了魔方體的旋轉(zhuǎn)變化。 4.編程中遇到的問(wèn)題 在對(duì)2X2魔方理解的基礎(chǔ)上,我經(jīng)過(guò)自己的摸索終于在末期做出了自己的3階魔方。其中,遇到了很多問(wèn)題,不過(guò)都被我解決了。以下是我認(rèn)為的比較重要的問(wèn)題 (1)在編寫(xiě)判斷兩個(gè)立方體是否重合的函數(shù)時(shí),開(kāi)始我沒(méi)
33、有消除累計(jì)誤差。說(shuō)實(shí)話,當(dāng)時(shí)我對(duì)這個(gè)程序并不是很了解。沒(méi)有加入這個(gè)功能,程序運(yùn)行結(jié)果如下: 剛開(kāi)始時(shí)還比較正常,運(yùn)行一段時(shí)間后,魔方錯(cuò)位了。想了很久,看了指導(dǎo)書(shū)才知道原來(lái)還差消除累計(jì)誤差這個(gè)功能。其實(shí),這也很好解釋。因?yàn)槲覀兙帉?xiě)的旋轉(zhuǎn)函數(shù)涉及到計(jì)算cosa以及sina的值,而計(jì)算機(jī)計(jì)算這些值是不是很準(zhǔn)確的。在一個(gè)旋轉(zhuǎn)周期中,要計(jì)算180次cosa和sina的值,因此誤差會(huì)被放大,則消除累計(jì)誤差成了必須。只需判斷兩個(gè)數(shù)在一定誤差范圍內(nèi)相等即可。 (2)魔方循環(huán)控制算法的設(shè)計(jì)中,我遇到了前所未有的問(wèn)題。單獨(dú)編寫(xiě)控制最外面一層或是中間一層旋轉(zhuǎn)的函數(shù)確實(shí)比較簡(jiǎn)單,但是如何實(shí)現(xiàn)一個(gè)實(shí)現(xiàn)外層和中
34、間一層同時(shí)都可旋轉(zhuǎn)的魔方還是很有難度的,這涉及到如何合理調(diào)度的問(wèn)題。在多方調(diào)試后,我想到了一個(gè)很好的算法,就是再引入一個(gè)控制變量cs,可是變量應(yīng)該選擇在哪里賦值呢?剛開(kāi)始我毫不猶豫的就選擇在TimerProc函數(shù)里面賦值,可是一下子就出錯(cuò)了。后來(lái)我將Timer2的定時(shí)時(shí)間設(shè)置為1800ms,目的是等于Timer1的180倍,以實(shí)現(xiàn)轉(zhuǎn)一個(gè)周期cs重新賦值一次,可結(jié)果表明我再次錯(cuò)了。因?yàn)檗D(zhuǎn)動(dòng)的延遲,所以轉(zhuǎn)動(dòng)一個(gè)周期所需時(shí)間是不定的,但肯定不等于1800ms。在重新閱讀一遍程序后,我發(fā)現(xiàn)在void Rotate_ZM()函數(shù)中有轉(zhuǎn)動(dòng)一個(gè)周期后的初始化操作,受到啟發(fā)后,我于是將cs的賦值移到了這個(gè)函數(shù)
35、中,運(yùn)行了觀察很久后都沒(méi)有出錯(cuò),果然成功了。 (3)編程過(guò)程中還有一些小問(wèn)題,不過(guò)只要是因?yàn)镃語(yǔ)言編程的一些知識(shí)都忘記了,于是我又重新復(fù)習(xí)了一下C語(yǔ)言的有關(guān)知識(shí),果然編起來(lái)得心應(yīng)手多了。 5.課程設(shè)計(jì)小結(jié) 編程是一件急需細(xì)心和耐心的事,剛開(kāi)始調(diào)試過(guò)程中遇到了很多弄不清楚原因的報(bào)錯(cuò)現(xiàn)象,但是經(jīng)過(guò)不斷地修改,那些問(wèn)題也都沒(méi)有了。一開(kāi)始寫(xiě)3X3程序的時(shí)候,為了避免犯錯(cuò)誤,我是沒(méi)有加旋轉(zhuǎn)的,只是建了一個(gè)魔方的模型并將其繪制出。 加了旋轉(zhuǎn)函數(shù)后果然遇到了一些問(wèn)題,旋轉(zhuǎn)過(guò)程中有時(shí)候會(huì)出現(xiàn)折疊和重疊現(xiàn)象,經(jīng)過(guò)仔細(xì)的檢查修改,發(fā)現(xiàn)原因是在調(diào)用旋轉(zhuǎn)函數(shù)時(shí),有部分子塊的運(yùn)動(dòng)沒(méi)有寫(xiě)入函數(shù),于是問(wèn)
36、題得到了部分解決。但是隨后編寫(xiě)循環(huán)控制算法遇到了很大問(wèn)題,剛開(kāi)始都弄煩了,但是休息一段時(shí)間后,沉下心來(lái)仔細(xì)思考,我想到了非常好的控制算法,終于問(wèn)題全部解決了。 這次課程設(shè)計(jì),我確實(shí)學(xué)到了很多。不僅有提升編程能力,而且也學(xué)習(xí)到了很多做人的道理。剛開(kāi)始入手這個(gè)項(xiàng)目,感覺(jué)壓力非常大,因?yàn)槲抑霸?D設(shè)計(jì)方面還是零基礎(chǔ),OpenGL讓我感覺(jué)是那么的復(fù)雜。隨后,我掌握了OpenGL貼圖技術(shù),并充分利用OpenGL的特性實(shí)現(xiàn)了一個(gè)立方體貼六張不同的圖片。在我以為實(shí)現(xiàn)了一個(gè)旋轉(zhuǎn)立方體后,實(shí)現(xiàn)2階魔方就難度不大時(shí),我再次因?yàn)槲易约旱臒o(wú)知而停下了腳步。閱讀完老師的代碼,總感覺(jué)思維很混亂。于是此后很久都
37、沒(méi)有進(jìn)展。一段時(shí)間過(guò)后,當(dāng)我再次仔細(xì)閱讀這些算法時(shí),我終于將它們完美的串接了起來(lái),實(shí)現(xiàn)了2階魔方。由2階魔方到3階魔方是類似的,但是循環(huán)控制算法要難一些。好在我再次編寫(xiě)出來(lái)了很好的控制算法,感覺(jué)效果很好 總的來(lái)說(shuō)總的來(lái)說(shuō),本次軟件課程設(shè)計(jì),對(duì)我來(lái)說(shuō)收獲不小。不僅復(fù)習(xí)了C語(yǔ)言知識(shí),也對(duì)編程及3D設(shè)計(jì)產(chǎn)生了一定的興趣,分析問(wèn)題和解決問(wèn)題的能力也得到了不小的提高。而且,我也學(xué)到了很多人生的道理。在做一件看似很難的事時(shí),我們要有一個(gè)總體的框架,不要有畏難心理。靜下心來(lái),沉著的分析問(wèn)題,問(wèn)題總會(huì)迎刃而解的。因此,成功的關(guān)鍵在于你是否擁有這樣的心理。 參考文獻(xiàn) [1]孫鑫 VC++深入詳解
38、第三版 北京 電子工業(yè)出版社 2007年 1-26 [2]楊柏林,陳根浪,徐靜 OpenGL編程精粹 第三版 北京 機(jī)械工業(yè)出版社 2010年 1-121 [3]周純杰,劉正林,何頂新,周凱波 標(biāo)準(zhǔn)C語(yǔ)言程序設(shè)計(jì)及應(yīng)用 第二版 武漢 華中科技大學(xué)出版社 2008年 1-263 [4]Dave Shreiner,The Khronons OpenGLARB Working Group OpenGL編程指南 第七版 北京 機(jī)械工業(yè)出版社 2010年 21-328 附上源碼 第一個(gè)文件---頭文件
39、
MoFang.h
#ifndef _MO_FANG_H_
#define _MO_FANG_H_
#include
40、 #define CYCLE_COUNT 90 #define MAX_CHAR 128 //用于在窗口顯示文字而定義的常數(shù) #define FRONT 0 #define BACK 1 #define LEFT 2 #define RIGHT 3 #define TOP 4 #define BOTTOM 5 typedef struct { GLfloat vx,vy,vz; }CubeVertex; typedef struct { GLfloat p[3]; }stPoi
41、nt; typedef struct { stPoint CubePoint[8]; }stCube; void reset_model(); void Rotate_ZM(); void Rotate_ZZ(); void Rotate_ZP(); void Rotate_XM(); void Rotate_XZ(); void Rotate_XP(); void Rotate_YM(); void Rotate_YZ(); void Rotate_YP(); void Rotate_Z(int ii); void R
42、otate_Y(int ii); void Rotate_X(int ii); void enable_X_roatate(int direction); void enable_Y_roatate(int direction); void enable_Z_roatate(int direction); void selectFont(int size, int charset, const char* face); void drawCNString(const char* str); void drawString(const char* str); exte
43、rn stCube Cube[27]; extern int rotAngle; extern int rotCount; extern int rotX,rotY,rotZ; extern GLfloat Vx,Vy; #endif 第二個(gè)文件 MoFang.cpp /* * 這個(gè)cpp文件包含三階魔方變換的常規(guī)函數(shù) * 作者為張世清 學(xué)號(hào)U201014185 * 華中科技大學(xué)電子系集成1001班 2012.5.19 * 當(dāng)然成果還離不開(kāi)組員徐兮、雷韋拉以及何兆華的支持 */ //加入自己編寫(xiě)的魔方頭文件,其
44、中包含一些變量定義與函數(shù)聲明 #include "MoFang.h" //對(duì)立方體各頂點(diǎn)編號(hào) static stPoint CubePoint[8]= { { -1.0f, -1.0f, 1.0f}, //0 { 1.0f, -1.0f, 1.0f }, //1 {1.0f, 1.0f, 1.0f }, //2 {-1.0f, 1.0f, 1.0f}, //3 {-1.0f, -1.0f, -1.0f}, //4 {-1.0f, 1.0f, -1.0f}, //5 {1.0f, 1.
45、0f, -1.0f}, //6 {1.0f, -1.0f, -1.0f}, //7 }; extern int cs; stCube Cube[27]; //定義一個(gè)3階魔方 stCube Static_Cube[27]; //定義一個(gè)靜態(tài)的3階魔方 //旋轉(zhuǎn)控制 int rotAngle = 1; //旋轉(zhuǎn)角度 int rotCount; //一個(gè)旋轉(zhuǎn)周期內(nèi)旋轉(zhuǎn)次數(shù) CYCLE_COUNT = 90/rotAngle; int rotX,rotY
46、,rotZ; //指定那個(gè)軸旋轉(zhuǎn) int rotDirect=1; //正反向旋轉(zhuǎn) //對(duì)當(dāng)前魔方各個(gè)立方體進(jìn)行編號(hào) BYTE ZP[9] = {0,1,2,3,4,5,6,7,8}; //z軸方向正向一層 BYTE ZZ[9] = {9,10,11,12,13,14,15,16,17}; //z軸方向中間一層 BYTE ZM[9] = {18,19,20,21,22,23,24,25,26}; //z軸方向負(fù)向一層 BYTE YM[9] = {0,1,2,11,10,9,18,19,20};
47、 //y軸方向負(fù)向一層 BYTE YZ[9] = {3,4,5,14,13,12,21,22,23}; //y軸方向中間一層 BYTE YP[9] = {6,7,8,17,16,15,24,25,26}; //y軸方向正向一層 BYTE XM[9] = {2,3,8,17,12,11,20,21,26}; //x軸方向正向一層 BYTE XZ[9] = {1,4,7,16,13,10,19,22,25}; //x軸方向中間一層 BYTE XP[9] = {0,5,6,15,14,9,18,23,2
48、4}; //x軸方向負(fù)向一層 //對(duì)靜態(tài)魔方各個(gè)立方體進(jìn)行編號(hào) const BYTE SZP[9] = {0,1,2,3,4,5,6,7,8}; //z軸方向正向一層 const BYTE SZZ[9] = {9,10,11,12,13,14,15,16,17}; //z軸方向中間一層 const BYTE SZM[9] = {18,19,20,21,22,23,24,25,26}; //z軸方向負(fù)向一層 const BYTE SYM[9] = {0,1,2,11,10,9,18,19,20};
49、 //y軸方向負(fù)向一層 const BYTE SYZ[9] = {3,4,5,14,13,12,21,22,23}; //y軸方向中間一層 const BYTE SYP[9] = {6,7,8,17,16,15,24,25,26}; //y軸方向正向一層 const BYTE SXM[9] = {2,3,8,17,12,11,20,21,26}; //x軸方向正向一層 const BYTE SXZ[9] = {1,4,7,16,13,10,19,22,25}; //x軸方向中間一層 const BYTE SXP[9
50、] = {0,5,6,15,14,9,18,23,24}; //x軸方向負(fù)向一層 void Rotate(stCube *pCube,float angle,float x0,float y0,float z0); //聲明旋轉(zhuǎn)函數(shù) //判斷兩個(gè)立方體是否重合,即判斷兩個(gè)立方體所包含的所有頂點(diǎn)坐標(biāo)是否相同 int is_equal(stCube *pc1,stCube *pc2){ float x1,x2,y1,y2,z1,z2; int isFind = 0; for( int i=0;i<8;i++) { x1 = pc1
51、->CubePoint[i].p[0]; y1 = pc1->CubePoint[i].p[1]; z1 = pc1->CubePoint[i].p[2]; isFind = 0; for(int j=0;j<8;j++) { x2 = pc2->CubePoint[j].p[0]; y2 = pc2->CubePoint[j].p[1]; z2 = pc2->CubePoint[j].p[2]; if( fabs(x1 - x2)<1e-1 && fabs(y1-y2)<1e-1 &&
52、 fabs(z1-z2)<1e-1) { pc1->CubePoint[i].p[0] = pc2->CubePoint[j].p[0]; //消除累計(jì)誤差 pc1->CubePoint[i].p[1] = pc2->CubePoint[j].p[1]; pc1->CubePoint[i].p[2] = pc2->CubePoint[j].p[2]; isFind = 1; break; } } if( isFind == 0) return 0; } r
53、eturn 1; } //旋轉(zhuǎn)之后,查找當(dāng)前旋轉(zhuǎn)面里面包含新的角點(diǎn) void Update_Cube_index() { int i,j,k=0; //根據(jù)逐一判斷立方體是否重合來(lái)更新每一層所包含的立方體的索引,總共三個(gè)方向有九層 k =0 ; for( i=0;i<9;i++) { for( j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SZM[i] ] ) ) { ZM[k++] = j; } } k=0; for(i=
54、0;i<9;i++) { for(j=0;j<27;j++) if(is_equal( &Cube[j], &Static_Cube[ SZZ[i] ] )) { ZZ[k++]=j; } } k = 0; for( i=0;i<9;i++) { for( j=0;j<27;j++) if( is_equal( &Cube[j] , &Static_Cube[ SZP[i] ] ) ) { ZP[k++] = j; } } k =0 ; for( i=0;
55、i<9;i++) { for( j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SXM[i] ] ) ) { XM[k++] = j; } } k =0 ; for( i=0;i<9;i++) { for( j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SXZ[i] ] ) ) { XZ[k++] = j; } }
56、 k = 0; for( i=0;i<9;i++) { for(j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SXP[i] ] ) ) { XP[k++] = j; } } k =0 ; for( i=0;i<9;i++) { for(j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SYM[i] ] ) ) {
57、 YM[k++] = j; } } k =0 ; for( i=0;i<9;i++) { for(j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SYZ[i] ] ) ) { YZ[k++] = j; } } k = 0; for( i=0;i<9;i++) { for( j=0;j<27;j++) if( is_equal( &Cube[j], &Static_Cube[ SYP[i]
58、] ) ) { YP[k++] = j; } } } //z軸負(fù)向一層繞著z軸轉(zhuǎn) void Rotate_ZM() { for(int i=0;i<9;i++) { Rotate(&Cube[ ZM[i] ],rotAngle*rotDirect, 0.0,0.0, 1.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=rand()%3; //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值
59、 Update_Cube_index(); rotAngle = 0; rotZ = 0; } } //z軸中間一層繞著z軸轉(zhuǎn) void Rotate_ZZ() { for(int i=0;i<9;i++) { Rotate(&Cube[ ZZ[i] ],rotAngle*rotDirect, 0.0,0.0, 1.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=rand()%3; //每轉(zhuǎn)一個(gè)周
60、期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotZ = 0; } } //z軸正向一層繞著z軸轉(zhuǎn) void Rotate_ZP() { for(int i=0;i<9;i++) { Rotate(&Cube[ ZP[i] ],rotAngle*rotDirect, 0.0,0.0, 1.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=rand()%3;
61、 //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotZ = 0; } } //x軸負(fù)向一層繞著x軸轉(zhuǎn) void Rotate_XM() { for(int i=0;i<9;i++) { Rotate(&Cube[ XM[i] ],rotAngle*rotDirect, 1.0,0.0, 0.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=rand()%3;
62、 //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotX = 0; } } //x軸中間一層繞著x軸轉(zhuǎn) void Rotate_XZ() { for(int i=0;i<9;i++) { Rotate(&Cube[ XZ[i] ],rotAngle*rotDirect, 1.0,0.0, 0.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=rand()%3
63、; //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotX = 0; } } //x軸正向一層繞著x軸轉(zhuǎn) void Rotate_XP() { for(int i=0;i<9;i++) { Rotate(&Cube[ XP[i] ],rotAngle*rotDirect, 1.0,0.0, 0.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=ran
64、d()%3; //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotX = 0; } } //y軸負(fù)向一層繞著y軸轉(zhuǎn) void Rotate_YM() { for(int i=0;i<9;i++) { Rotate(&Cube[ YM[i] ],rotAngle*rotDirect, 0.0,1.0, 0.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs
65、=rand()%3; //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotY = 0; } } //y軸中間一層繞著y軸轉(zhuǎn) void Rotate_YZ() { for(int i=0;i<9;i++) { Rotate(&Cube[ YZ[i] ],rotAngle*rotDirect, 0.0,1.0, 0.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) {
66、 cs=rand()%3; //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotY = 0; } } //y軸正向一層繞著y軸轉(zhuǎn) void Rotate_YP() { for(int i=0;i<9;i++) { Rotate(&Cube[ YP[i] ],rotAngle*rotDirect, 0.0,1.0, 0.0); } //轉(zhuǎn)180度后重新更新立方體索引 if( rotCount++==CYCLE_COUNT) { cs=rand()%3; //每轉(zhuǎn)一個(gè)周期后重新對(duì)cs賦值 Update_Cube_index(); rotAngle = 0; rotY = 0; } } //通過(guò)控制量ii來(lái)確定是那一層面繞Z軸轉(zhuǎn)動(dòng) void Rotate_Z(int ii) { switch(ii) { case 0: Rotate_ZP();
- 溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 產(chǎn)后保健知識(shí)講座
- 《音樂(lè)小屋》課件2
- 2019屆高考物理二輪復(fù)習(xí)專題二能量與動(dòng)量第7講動(dòng)能定理的應(yīng)用課件
- 灝忓涓€騫寸駭鍥介槻鏁欒偛璇句歡
- 高中地理一輪二輪三輪復(fù)習(xí)氣象災(zāi)害集備1
- 人教英語(yǔ)必修二同課異構(gòu)課件:Unit2TheOlympicGamesSectionAWarmingUpandReading2
- 人教版小學(xué)語(yǔ)文二年級(jí)上冊(cè)《黃山奇石》PPT課件
- 6分?jǐn)?shù)混合運(yùn)算(二)第1-課時(shí)課件
- 黃河的主人(教育精品)
- 術(shù)前肺功能測(cè)定及其臨床意義
- 變態(tài)心理學(xué)和健康心理學(xué)知識(shí)專題知識(shí)宣講
- 肝纖維化無(wú)創(chuàng)性診斷--課件
- 512垂線(1)(教育精品)
- 熒光幻彩金蔥粉耐溶劑金蔥粉
- 第4章音頻媒體2