計算機圖形學(xué)課程教學(xué)設(shè)計_第1頁
計算機圖形學(xué)課程教學(xué)設(shè)計_第2頁
計算機圖形學(xué)課程教學(xué)設(shè)計_第3頁
計算機圖形學(xué)課程教學(xué)設(shè)計_第4頁
計算機圖形學(xué)課程教學(xué)設(shè)計_第5頁
已閱讀5頁,還剩34頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、計算機圖形學(xué)課程設(shè)計(2015-2016學(xué)年第二學(xué)期)學(xué)院專業(yè)班級學(xué)號學(xué)生姓名老師編寫日期:2016年xx月xx日真實感游戲場景繪制3.1 實驗?zāi)康?.2 實驗內(nèi)容3.3 實驗分工4.4 理論基礎(chǔ)4.1 霧化模型4.2 顏色模型5.3 光照模型6.4 紋理模型6.5 系統(tǒng)描述1.31 墻壁、地面、箱子1.32 石柱、雪人143 玻璃球1.54 天空1.76 心得體會1.97 附錄:程序源代碼 19真實感游戲場景繪制【摘要】本次課程設(shè)計繪制了一個真實感的三維場景, 并實現(xiàn)場景漫游。主 要繪制了墻壁與地面、天空、石柱、箱子、玻璃球、雪人、霧等對象。以 Visual Studio2012為平臺用Op

2、enGL基礎(chǔ)知識實現(xiàn)此真實感場景的繪制。一 實驗?zāi)康? .熟悉OpenGL基礎(chǔ)函數(shù),并了解其用法。2 .通過程序模擬真實感游戲場景,掌握圖形綜合展示效果,基于專業(yè)背景, 結(jié)合實驗課內(nèi)容與課程設(shè)計要求,使用OpenGL繪制簡單的3D真實感游戲場景, 包括光柵化算法、多邊形裁剪計算以及消隱算法在場景繪制中的應(yīng)用。實驗內(nèi)容和效果光柵化算法、多邊形裁剪計算以及消隱算法在場景繪制中的應(yīng)用,其中真實感場景繪制包括顏色模型、紋理模型、霧化模型、運動模型以及環(huán)境光、漫反射、 鏡面反射等光照模型設(shè)置。圖1游戲場景整體效果三實驗分工本次課程設(shè)計實驗,小組成員齊心協(xié)力。首先從自己嘗試編寫沒有成功到 后來的各種搜集資

3、料,尋找3D游戲場景的繪制代碼,到最后小組成員分工解析 代碼并注釋,做PPT,演講PPT等,大家合作都很用心。這次的實驗中我們小 組每個成員在每一個環(huán)節(jié)都參與任務(wù),因代碼過多,也都參與到代碼解析中。具體安排如下:姓名任務(wù)xxx搜集資料,代碼解析注釋,做 PPT, PPT演講xxx搜集資料,代碼解析并注釋,做 PPT, PPT演講xxx搜集資料,代碼解析注釋,做 PPT, PPT演講xxx搜集資料,代碼解析注釋,做 PPT, PPT演講四理論基礎(chǔ)1霧化模型OpenGL中提供了完整的霧化接口 ,我們只需要選擇合適的霧氣的混合因子、 密度、顏色、起始位置等。在OpenGL中,霧的工作模式有兩種:線性

4、模式和指 數(shù)模式。這兩種模式是根據(jù)霧的濃度變化來區(qū)分的。在線性模式下,只需要提供一個距離視點的開始位置和結(jié)束位置。從開始位置到結(jié)束位置之間,霧的濃度越來越高,濃度的變化和距離成正比。在指數(shù)模式下,霧的濃度隨著距離的增加呈指數(shù)增長。這種模式通常用來用 于煙霧、煙幕等效果。glFogf(GL_FOG_START, 1.0f)確定了霧的開始初離屏幕有多近。glFogf(GL_FOG_END, 5.0),它告訴OpenGL霧能離開屏幕有多遠glHint(GL_FOG_HINT, GL_DONT_CARE)確定了霧的渲染方式,使用 GL_DONT_CARE是因為并不關(guān)心建議值。這個項的不同值之間的區(qū)別:

5、GK_DONT_CARE :讓OPENGL自己來確定霧的渲染方式,每頂點或是每 像素。GL_NICEST:對每一像素進行霧的渲染,它看起來是極棒的。GL_FASTEST:對每一頂點進行霧的渲染,它速度較快,但是不夠美麗我們的霧氣設(shè)置如下: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)小霧化效果修改函數(shù)里面的參數(shù)改變霧的顏色和濃度:圖2改變顏色(藍色)和濃度的霧氣2顏色模型OpenGL支持兩種顏色模式:一種是 RGBA , 一種是顏色索引模式。不同的 是,RGBA模式中,數(shù)據(jù)直接就代表了顏色;而顏色索引模式中,數(shù)據(jù)代表的是 一個索引,要得到真正的顏色,還必須去查索引表。RGBA顏色RGBA模式中,每一個像素會保存以下數(shù)據(jù):R值(紅色分量)、G值(綠 色分量)、B值(藍色分量)和 A值(alpha分量)。其中紅、綠、藍三種顏色 相組合,就可以得到我們所需要的各種顏

7、色,而alpha不直接影響顏色。3光照模型光照模型包括許多因素,如物體的類型,物體相對光源與其他物體的位置以 及場景中所設(shè)置的光源屬性,物體的透明度,物體的表面光亮程度,甚至物體的 各種表面紋理等。光照到物體表面時,物體對光會發(fā)生反射、透射、吸收、衍射、 折射和干涉。通常觀察不透明、不發(fā)光的物體,人眼所觀察到的是從物體表面的 得到的反射光,它是由場景中的光源和其他物體表面的反射光共同作用產(chǎn)生的。簡單光照明模型模擬物體表面對直接光照的反射作用,包括鏡面反射和漫反射,而物體間的光反射作用沒有被充分考慮到,僅僅用一個與物體周圍和視點、 光源位置都無關(guān)的環(huán)境光常量來近似表示??梢杂萌缦卤磉_式表示:入射

8、光=環(huán)境光+漫反射+鏡面反射光77光源屬性glLiehtfvCGL_LT(;HTO, GL.AMBIEMT, Lightkmbient) 光源中的環(huán)境光播度 £lLielrtfv(GL_LIGHTO, GlZdIFFUSE, Light Diffused ;“丸源中的散射光強度 jlLithtfvCGL_LL&HTO, GL_F05IT工0他 HghtFgitioii)指定光漉廟位置 /材質(zhì)屬性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) ; /材質(zhì)屬性的箱面反射指數(shù) ?lEnable(&L_LIGHrO):/glEnable(GL_LIGHTING):4紋理模型(因為我們的場景大量使用了紋理模型,且我主要也負責(zé)紋理模型,因此處會詳細解釋。)我們都知道物體表面通常并不是具有簡單顏色的平滑面,而是有著花紋 圖案等豐富細節(jié)的。計算機三維圖形通過給面貼紋理來表現(xiàn)表面細節(jié)。OpenGL默認設(shè)置是關(guān)閉貼紋理的,所以必須先用命令打開紋理計算

10、 glEnable(GL_TEXTURE_2D); / 啟用二維紋理 glDisable(GL_TEXTURE_2D); 禁用二維紋理 1、啟用紋理和載入紋理如同我們曾經(jīng)學(xué)習(xí)過的OpenGL光照、混合等功能一樣。在使用紋理前,必 須啟用它。OpenGL支持一維紋理、二維紋理、三維紋理和四維紋理。一般情況下使用二維紋理即可。使用紋理前,必須載入紋理。利用 glTexImage2D函數(shù)可以載入一個二維的 紋理,該函數(shù)有多達九個參數(shù),glTexImage2D( GL_TEXTURE_2D , Glint level, Glint components, Glsizei width, Glsizei

11、Height, Glint order, Glenum ype, const Glvoid *pixels )詳細說明如下:第一個參數(shù)為指定的目標,在我們的入門教材中,這個參數(shù) 將始終使用 GL_TEXTURE_2D。第二個參數(shù)為“多重細節(jié)層次”,現(xiàn)在我們并不考慮多重紋理細節(jié),因此這 個參數(shù)設(shè)置為零。第三個參數(shù)有兩種用法。在OpenGL最初的版本中,使用整數(shù)來表示顏色分 量數(shù)目,例如:像素數(shù)據(jù)用 RGB顏色表示,總共有紅、綠、藍三個值,因此參 數(shù)設(shè)置為3,而如果像素數(shù)據(jù)是用 RGBA顏色表示,總共有紅、綠、藍、alpha 四個值,因此參數(shù)設(shè)置為4。而在后來的版本中,可以直接使用 GL_RGB或

12、 GL_RGBA來表示以上情況,顯得更直觀。注意:雖然我們使用 Windows的BMP 文件作為紋理時,一般是藍色的像素在最前,其真實的格式為GL_BGR而不是GL_RGB,在數(shù)據(jù)的順序上有所不同,但因為同樣是紅、綠、藍三種顏色,因此 這里仍然使用GL_RGB o如果使用GL_BGR, OpenGL將無法識別這個參數(shù),造 成錯誤。第四、五個參數(shù)是二維紋理像素的寬度和高度。在使用紋理時要特別注意其 大小,必須使用大小為2的整數(shù)次方的紋理。在很長一段時間內(nèi),很多圖形程序 都喜歡使用256*256大小的紋理,不僅因為256是2的整數(shù)次方,也因為某些硬 件可以使用8位的整數(shù)來表示紋理坐標,2的8次方正

13、好是256,這一巧妙的組 合為處理紋理坐標時的硬件優(yōu)化創(chuàng)造了一些不錯的條件。第六個參數(shù)是紋理邊框的大小最后三個參數(shù)分別是紋理的圖像數(shù)據(jù)格式,數(shù)據(jù)類型和紋理圖像的像素數(shù)據(jù) 的存儲地址。舉個例子,如果有一幅大小為 width*height,格式為Windows系統(tǒng)中使用最 普遍的24位BGR,保存在pixels中的像素圖像。則把這樣一幅圖像載入為紋理 可使用以下代碼:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);下面一段為我們的游戲場景中的載入紋理的代碼:

14、/對于指定的多個紋理,要根據(jù)自己的需要映射到不同的面上,需要對位圖 創(chuàng)建一個數(shù)組,/用來存儲位圖的名稱,然后在初始化OpenGL的時候,可以讀取這些位圖, 然后生成多個紋理存儲到一個紋理數(shù)組中,接著就可以指定繪制的某個面,對該指定的面進行紋理映射/加載位圖AUX_RGBImageRec *LoadBMP(char "Filename)/ 根據(jù)位圖文件的名稱進行 加載。 AUX_RGBImageRec定義紋理數(shù)據(jù)的格式FILE *File=NULL; / 文件指針if (Filename)/確保文件名已提供return NULL; 如果沒有提供,返回 nullFile=fopen(Fi

15、lename,"r"); /根據(jù)指定的位圖文件名稱,打開該位圖文件 if (File) /如果位圖文件存在 fclose(File);/關(guān)閉句柄。因為只是需要判斷問題是否存在,而不需要對位圖文件進行寫操作,所以關(guān)閉位圖文件return auxDIBImageLoad(Filename); 載入位圖并返回指針(其實,只 需要一個真正存在的位圖文件的名稱,實現(xiàn)加載位圖文件,并返回) return NULL;首先,AUX_RGBImageRec類型是一個RGB圖像結(jié)構(gòu)類型。該結(jié)構(gòu)定義 了三個成員:sizeX 圖像的寬度;sizeY 圖像的高度;data;圖形所包含的數(shù)據(jù),其實也就

16、是該圖形在內(nèi)存中的像素數(shù)據(jù)的 一個指針。AUX_RGBImageRec類型的變量描述了一幅圖像的特征。上述函數(shù)中,調(diào)用了 glaux.h庫文件中的auxDIBImageLoad 函數(shù),其實它 是一個宏,函數(shù)原型為 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實現(xiàn)的功能就是:根據(jù)指定的位圖名稱,將該位圖的 信息加載到內(nèi)存中,以便用來創(chuàng)建成為紋理。/加載紋理int LoadGLTextures()用于創(chuàng)建并加載紋理的函數(shù)為 LoadGLTexturesint Status=FALSE;/很多函數(shù)的返回類型都是 Status這里Status是用 typedef 定義的 intl 類型 即:typedef int Status;AUX_RGBImageRec *TextureImage10; /創(chuàng)建一個紋理

19、圖像數(shù)組,這里 指定數(shù)組大小為10memset(TextureImage,0,sizeof(void *)*10); / 創(chuàng)建一個紋理圖像數(shù)組, 這里指定數(shù)組大小為10/創(chuàng)建的位圖名稱數(shù)組,對應(yīng)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;/加載位圖成功,修改狀態(tài)標志變量Status為TRUEglGenTextures(10, &texture0);/紋理標識 for(int loop=0;loop<10;loop+) /遍歷位圖名稱數(shù)組,根據(jù)位圖名稱分別生成glBindTexture(GL_TEXTURE_2D,textureloop); 進行綁定紋理。glTexParameteri(GL_TEXT

22、URE_2D,GL_TEXTURE_MAG_FILTER,GL_LINE AR);/設(shè)置濾波模式,功能就是實現(xiàn)線形濾波的功能,當(dāng)紋理映射到圖形表面以 后,glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINE AR);/如果因為其它條件的設(shè)置導(dǎo)致紋理不能更好地顯示的時候,進行過濾,按 照指定的方式進行顯示,可能會過濾掉顯示不正常的紋理像素。/紋理的定義,此處用到的是二維紋理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+) /釋放位圖數(shù)組占用的內(nèi)存空間 if (TextureImageloop!=NULL)if (TextureImageloop->data!=NULL)free(TextureImageloop->data);free(TextureImageloop);return Status;/創(chuàng)建紋理并加載,返回成功或者失敗的標志Status2、紋理控制OpenGL的紋理控制實質(zhì)上

24、就是定義紋理如何包裹物體的表面的,因為紋理的外形并不總是與物體一致,比如紋理通常是矩形的,但會被映射到一個多邊形或 曲面上,在被變換到屏幕坐標后,紋理的單個紋素很難與屏幕上的像素對應(yīng)。根據(jù)所使用的變換和所用的紋理的映射方式,屏幕上的單個像素可能對應(yīng)紋理單元中單個紋素的一部分,即放大濾波或?qū)?yīng)于多個紋素的,即縮小濾波。而控制縮 小和放大濾波的是采用glTexParameter函數(shù)來實現(xiàn)的?!霸O(shè)置超裝槿式,功能就是實現(xiàn)線電通裝的功能,當(dāng)紋理映射到圖形表面以后, 如果因為其它條件的謾置m致紋理不能更好地顯示的時候,迸行過速按照 指關(guān)的方式進行顯示,可能會過速掉顯示不正常的紋理像素。(GL_TEXTO

25、RE_2口,L_ TEXTURE. W.FILTER, GL.LINEAR);glTexParaneteri (GL_TEKTW_2D. GLTEXTURE.MIN.FILTER, GL.LTUEW : tl MM tl 3、紋理坐標紋理的使用只要指定每一個頂點在紋理圖像中所對應(yīng)的像素位置,OpenGL就會自動計算頂點以外的其它點在紋理圖像中所對應(yīng)的像素位置。例如:在繪制一條線段時,我們設(shè)置其中一個端點為紅色,另一個端點為綠色,則OpenGL會 自動計算線段中其它各像素的顏色,如果是使用glShadeMode(GL_SMOOTH);,則最終會形成一種漸變的效果(例如線段中點,就是紅色和綠色的中

26、間色)。類 似的,在繪制一條線段時,我們設(shè)置其中一個端點使用“紋理圖像中最左下角的 顏色”作為它的顏色,另一個端點使用“紋理圖像中最右上角的顏色”作為它的 顏色,則OpenGL會自動在紋理圖像中選擇合適位置的顏色,填充到線段的各個像素(例如線段中點,可能就是選擇紋理圖像中央的那個像素的顏色)。使用glTexCoord*系列函數(shù)來指定紋理坐標。這些函數(shù)的用法與使用 glVertex*系列函數(shù)來指定頂點坐標十分相似。例如: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ǒng)描述本實驗繪制的游戲場景可以使用按鍵T、J、一、一或 W、S、A、D控制 運動方向,PgDn和PgUp可以改變觀察者的高度,鼠標控制轉(zhuǎn)向,按鍵F'可 以打開和關(guān)閉“霧氣”,Esc退出程序。主要繪制了墻壁與地面、天空、石柱、箱子、玻璃球、雪人、霧等對

30、象下面 將依次分析它們的設(shè)計思路,這里將使用相同繪制技術(shù)的對象放到一起說明。1墻壁、地面、箱子它們的基本操作對四邊形的紋理映射,將一幅紋理圖的四個頂點坐標分別映 射到四邊形的四個頂點上即可。OpenGL就自動通過插值填充多邊形內(nèi)部的紋理。 由于在OpenGL中紋理坐標是一個點的屬性,故需要在繪制點之前指定該點的紋 理坐標。另外在繪制四邊形時要保證繪制順序的一致,這里統(tǒng)一采用逆時針順序 繪制。紋理坐標范圍在0, 1之間,坐標超過1則采用重復(fù)的方式(OpenGL默 認處理方式)。這樣可以在映射時按四邊形的比例設(shè)置紋理坐標,從而防止紋理圖過度拉伸造成的變形。一個四邊形的紋理映射步驟為: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石柱、雪人石柱和雪人都屬于二次幾何體的繪制和紋理映射,其中雪人由圓柱、球體、 圓盤、圓錐構(gòu)成。OpenGL提供了這些基本幾何體的繪制函數(shù),而且在紋理映射 時我們采用自動生成紋理坐標的方法, 所以這一部分工作量其實很少。另外,為 了給雪人的身體、鼻子等部位設(shè)置顏色時,我們需要關(guān)閉紋理映射、并更改材質(zhì) 的屬性(物體的顏色是由光源和材質(zhì)共同作用的結(jié)果)。對于石柱,我們加上了 繞自身局部坐標Y軸的勻速旋轉(zhuǎn)。我們使用 Glut庫提供的如下函數(shù)繪制二次幾 何體:gluCylinder:繪制圓柱和圓柱gluSphere繪制球體gluDisk:繪制圓盤使用gluQuadricTexture設(shè)置自動

33、計算紋理坐標實驗效果如下:圖4雪人和石柱3玻璃球在繪制玻璃球時,為了在球面上反射出周圍的場景,我們使用了環(huán)境映射。 由于我們能夠在三維場景中漫游,這就需要球面上反射出的場景是隨著視點移動 而變化的,這一需求可以利用“渲染到紋理" (RTT)技術(shù)實現(xiàn)。其基本思想是: 首先繪制出環(huán)境中的所有物體(除了該玻璃球),接著將繪制得到的場景圖制作 成紋理,在繪制該玻璃球時將此紋理圖貼在球面上即可。該場景使用的核心函數(shù)是glCopyTexImage2D,該函數(shù)可以將幀緩存中的顏 色值復(fù)制到紋理緩存中。實驗發(fā)現(xiàn)該函數(shù)性能較低,會拖慢整個程序的速度,為 了平衡繪制質(zhì)量和速度,可以只拷貝一部分像素值。實

34、驗效果如下:理 3m圖5玻璃球4、霧氣OpenGL中提供了完整的霧化接口,我們只需要選擇合適的霧氣的混合因 子、密度、顏色、起始位置等。該場景的霧氣設(shè)置如下: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);/ 結(jié)束距離 glHint(GL_FO

35、G_HINT,GL_NICEST); 霧化效果實驗效果如下:圖6霧氣4天空天空包含云、星星、閃電三個對象。我們要實現(xiàn)的目標是:云在空中飄動、 且能夠遮蓋住空中的星星,每間隔一段時間都會有閃電和雷聲。天空的繪制主要使用了顏色混合技術(shù)。首先將星星的紋理圖映射到天空,為了實現(xiàn)云朵覆蓋住星星,我們使用了如下技巧:制作一個關(guān)于云圖(圖6)的二值圖像(圖7),其中有云的部分為黑色、無云的部分為白色。將該二值圖像作 為“掩?!迸c星星圖進行混合,并設(shè)置混合因子glBlendFunc(GL_DST_COLOR,GL_ZERO),該設(shè)置可以將星星圖中對應(yīng)“掩?!焙谏牟糠?置為黑色、對應(yīng)“掩?!卑咨牟糠直A粼?/p>

36、。接著再將云圖映射至天空,并更 改混合因子glBlendFunc(GL_ONE, GL_ONE),該設(shè)置實現(xiàn)源色與目的色相力口。 至此已經(jīng)實現(xiàn)云對星星的遮蓋,另外,在進行顏色混合時需要打開OpenGL的顏 色混合功能,且要關(guān)閉深度測試功能。為了實現(xiàn)云的飄動,我們在設(shè)置云圖紋理坐標時添加一個變量,該變量從 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天空六心得體會這次的課程設(shè)計不僅考察了書上所學(xué)知識點,將所學(xué)融合在一起。過程中雖 然剛開始感覺有些難,也遇到很多困難,比如電腦配置問題等等,但遇到困難不 可怕,重要的是解決困難的過程,我們的游戲場景的繪制,因工

38、程量很大,且代 碼很多,在實驗過程中,我不斷查資料,看書去理解各種模型代碼,從來不敢相 信自己能將看完并理解這么多代碼。 但是這次我做到了,雖然我重點講的是紋理 模型,其他模型也都去認真學(xué)習(xí)了一遍。 在這個過程中真的學(xué)到很多,而大學(xué)鍛 煉的也就是這種自學(xué)能力。七附錄:程序源代碼#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; /左右旋轉(zhuǎn)角度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;/石柱旋轉(zhuǎn)角度GLfloat roll=0;/ 云層移動量GLfloat lightning=0;bool thunder=true;/促否打雷GLboolean fog=false;/是否開啟霧化bool fp;/F鍵是否按下GLuint EnvTexture;/環(huán)境紋理*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;/下面函數(shù)是定義視圖窗口在畫布上的大小和位置glViewport(0,0

45、,width,height);/設(shè)置為投影矩陣glMatrixMode(GL_PROJECTION);/當(dāng)前矩陣設(shè)置為單位矩陣glLoadIdentity();/角度視,景體的寬高比,沿z軸方向的兩裁面之間的距離的近處,沿z軸 方向的兩裁面之間的距離的遠處gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,1000.0f);/模型視圖應(yīng)用這個參數(shù)后,表示接下來的矩陣操作都是針對模型視景矩 陣堆棧,/直到下一次調(diào)用這個函數(shù)并更改參數(shù)為止。glMatrixMode(GL_MODELVIEW);/當(dāng)前矩陣設(shè)置為單位矩陣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);利用鼠標控制轉(zhuǎn)向void SetViewByMouse()POINT mousePos;/鼠標位置POINT middlePos;屏幕中心位置middlePos.x =SCREEN_WIDTH/2;middlePos.y =SCREEN_HEIGHT/2;GetCursorPos(&mousePos);/得到鼠標當(dāng)前位if(mousePos.x=middl

50、ePos.x&&mousePos.y=middlePos.y) /加果鼠標沒有動,返回。return ;/如果鼠標動了,/旋轉(zhuǎn)改變量/上下改變量SetCursorPos(middlePos.x, middlePos.y);則恢復(fù)到屏幕中心/通過鼠標在x軸上的移動分量,計算旋轉(zhuǎn)改變量theta += GLfloat(-middlePos.x +mousePos.x)/500;/通過鼠標在Y軸上的移動分量,計算旋轉(zhuǎn)改變量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)/ 根據(jù)位圖文件的名稱進 行加載。AUX_RGBImageRec定義紋理數(shù)據(jù)的格式FILE *File=NULL; / 文件指針if (Filename)確保文件名已提供 return NULL;如果沒有提供,返回 nullFile=fopen(Filename,"r"); /根據(jù)指定的位圖文件名稱,打開該位圖文件if (File)/ 如果位圖文件存在fclose(File);/關(guān)閉句柄。因為只是需要判斷問題是否存在,而不需要對位圖文件進行寫操作,所以關(guān)閉位圖文件return aux

57、DIBImageLoad(Filename); /雷入位圖并返回指針(其實,只 需要一個真正存在的位圖文件的名稱,實現(xiàn)加載位圖文件,并返回)return NULL;/加載紋理int LoadGLTextures()/用于創(chuàng)建并加載紋理的函數(shù)為 LoadGLTexturesint Status=FALSE;/很多函數(shù)的返回類型都是 Status這里Status是用 typedef 定義的 intl 類型 即:typedef int Status;AUX_RGBImageRec *TextureImage10; /創(chuàng)建一個紋理圖像數(shù)組,這里 指定數(shù)組大小為10memset(TextureImage,0,sizeof(void *)*10); / 創(chuàng)建一個紋理圖像數(shù)組, 這里指定數(shù)組大小為6/創(chuàng)建的位圖名稱數(shù)組,對應(yīng)6幅位圖 if(Tex

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論