真實感場景繪制(附源碼)


首先給出繪制效果圖:

 

說明:

本系統繪制了一個真實感的三維場景,並實現場景漫游。使用按鍵↑、↓、←、→或W、S、A、D控制運動方向,PgDn和PgUp可以改變觀察者的高度,鼠標控制轉向,按鍵‘F’可以打開和關閉“霧氣”,Esc退出程序。

本場景中繪制了牆壁與地面、天空、石柱、箱子、玻璃球、雪人、霧等對象,下面將依次分析它們的設計思路,這里將使用相同繪制技術的對象放到一起說明。

1、 牆壁、地面、箱子

它們的基本操作對四邊形的紋理映射,將一幅紋理圖的四個頂點坐標分別映射到四邊形的四個頂點上即可。OpenGL就自動通過插值填充多邊形內部的紋理。由於在OpenGL中紋理坐標是一個點的屬性,故需要在繪制點之前指定該點的紋理坐標。另外在繪制四邊形時要保證繪制順序的一致,這里統一采用逆時針順序繪制。紋理坐標范圍在[0,1]之間,坐標超過1則采用重復的方式(OpenGL默認處理方式)。這樣可以在映射時按四邊形的比例設置紋理坐標,從而防止紋理圖過度拉伸造成的變形。一個四邊形的紋理映射步驟為:

glBindTexture(GL_TEXTURE_2D,texture[0]); 

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();

實驗效果如下:

 

圖1.牆壁、地面、箱子

2、 石柱、雪人

石柱和雪人都屬於二次幾何體的繪制和紋理映射,其中雪人由圓柱、球體、圓盤、圓錐構成。OpenGL提供了這些基本幾何體的繪制函數,而且在紋理映射時我們采用自動生成紋理坐標的方法,所以這一部分工作量其實很少。另外,為了給雪人的身體、鼻子等部位設置顏色時,我們需要關閉紋理映射、並更改材質的屬性(物體的顏色是由光源和材質共同作用的結果)。對於石柱,我們加上了繞自身局部坐標Y軸的勻速旋轉。實驗效果如下:  

 
                                                  

圖2.雪人                                                圖3.石柱

我們使用Glut庫提供的如下函數繪制二次幾何體:

gluCylinder:繪制圓柱和圓柱

gluSphere:繪制球體

gluDisk:繪制圓盤

使用gluQuadricTexture設置自動計算紋理坐標。

3、 玻璃球

在繪制玻璃球時,為了在球面上反射出周圍的場景,我們使用了環境映射。由於我們能夠在三維場景中漫游,這就需要球面上反射出的場景是隨着視點移動而變化的,這一需求可以利用“渲染到紋理”(RTT)技術實現。其基本思想是:首先繪制出環境中的所有物體(除了該玻璃球),接着將繪制得到的場景圖制作成紋理,在繪制該玻璃球時將此紋理圖貼在球面上即可。

我們使用的核心函數是glCopyTexImage2D,該函數可以將幀緩存中的顏色值復制到紋理緩存中。實驗發現該函數性能較低,會拖慢整個程序的速度,為了平衡繪制質量和速度,可以只拷貝一部分像素值。實驗效果如下:

圖4.玻璃球

 

4、 霧氣

OpenGL中提供了完整的霧化接口,我們只需要選擇合適的霧氣的混合因子、密度、顏色、起始位置等。我們的霧氣設置如下:

GLfloat fogColor[4]={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_FOG_HINT,GL_NICEST);//霧化效果

實驗效果如下:

 

圖5.霧氣

 

5、 天空

天空包含雲、星星、閃電三個對象。我們要實現的目標是:雲在空中飄動、且能夠遮蓋住空中的星星,每間隔一段時間都會有閃電和雷聲。

天空的繪制主要使用了顏色混合技術。首先將星星的紋理圖映射到天空,為了實現雲朵覆蓋住星星,我們使用了如下技巧:制作一個關於雲圖(圖6)的二值圖像(圖7),其中有雲的部分為黑色、無雲的部分為白色。將該二值圖像作為“掩模”與星星圖進行混合,並設置混合因子glBlendFunc (GL_DST_COLOR,GL_ZERO),該設置可以將星星圖中對應“掩模”黑色的部分置為黑色、對應“掩模”白色的部分保留原色。接着再將雲圖映射至天空,並更改混合因子glBlendFunc(GL_ONE, GL_ONE),該設置實現源色與目的色相加。至此已經實現雲對星星的遮蓋,另外,在進行顏色混合時需要打開OpenGL的顏色混合功能,且要關閉深度測試功能。

圖6.雲圖                         圖7.二值圖

為了實現雲的飄動,我們在設置雲圖紋理坐標時添加一個變量,該變量從0遞增至1,超過1時做減1操作,這樣就可以模擬雲的移動。如下的roll即為該變量:

glBegin(GL_QUADS); 

glTexCoord2f(0.0f, 3.0f-roll);glVertex3f(-50.0f, 100.0f, -300.0f);

glTexCoord2f(1.0f, 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();

每繪制一定幀數后,我們將一幅閃電紋理圖映射到天空,使用簡單的相加混合,且在首次繪制閃電時調用音頻播放函數,播放一段雷聲,音頻調用函數為PlaySound。實驗效果如下:

圖8.天空

源碼下載

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM