摘 要: 粒子系統(tǒng)是模擬噴泉的一種有效方法,。首先使用Visual C++的基本類庫(kù)MFC和Open GL圖形庫(kù)建立面向?qū)ο蟮娜S圖形應(yīng)用程序的開(kāi)發(fā)環(huán)境,然后再利用各種計(jì)算過(guò)程生成模型中的各個(gè)體素,,利用粒子系統(tǒng)建模的優(yōu)點(diǎn),,實(shí)現(xiàn)噴泉的模擬。
關(guān)鍵詞: 三維圖形編程,;OpenGL,;MFC類庫(kù);粒子系統(tǒng)
由于自然環(huán)境中大部分景物(如云彩,、火焰,、煙霧、瀑布,、雪花等特效)具有不規(guī)則性,、復(fù)雜性與隨機(jī)性,且隨著時(shí)間變化形狀會(huì)隨之變化,,對(duì)其進(jìn)行逼真的實(shí)時(shí)模擬十分困難,,需要大量的計(jì)算量和數(shù)據(jù)量。在虛擬環(huán)境中,,自然景物的視覺(jué)效果直接影響到觀察者對(duì)周圍環(huán)境的感知,,所以開(kāi)發(fā)一個(gè)既能滿足逼真度要求,又能實(shí)時(shí)顯示的粒子系統(tǒng)是非常必要的,。自從OpenGL公布以來(lái),,有關(guān)圖形學(xué)方面的書(shū)籍、論文等資料就層出不窮,,如何利用Open GL開(kāi)發(fā)出具有一定水平的計(jì)算機(jī)圖形程序就成為眾多學(xué)者的追求目標(biāo),。在Visual C++中,既可利用Win32編程,,也可利用MFC編程,,兩者各有特點(diǎn),本文就如何利用Open GL在MFC中開(kāi)發(fā)出一個(gè)簡(jiǎn)單的噴泉模擬程序作一個(gè)簡(jiǎn)單探討,。
1 OpenGL繪圖環(huán)境初始化
OpenGL是一個(gè)跨平臺(tái)的三維圖形庫(kù),,可在Windows、Unix和Mac等平臺(tái)上運(yùn)行。而Visual C++完善的基本類庫(kù)MFC和應(yīng)用向?qū)ppWizard使得開(kāi)發(fā)一個(gè)復(fù)雜的應(yīng)用程序變得輕松自如,。如果將兩者結(jié)合,,便可開(kāi)發(fā)出較高水平的Windows下三維圖形應(yīng)用程序[1]。
在3D游戲的渲染過(guò)程中,,傳統(tǒng)的建模方法一般只適用于外形比較規(guī)則的形體,,對(duì)于那些像雨、雪,、瀑布,、噴泉以及火焰等沒(méi)有固定形狀,甚至要隨著外部環(huán)境或者其他因素的改變而改變的物質(zhì)建模,,傳統(tǒng)的方法就顯得無(wú)能為力了[2],。1983年REEVES W T提出了一種新的建模方法,稱為模糊物體建模,,該方法就是粒子系統(tǒng),,它的出現(xiàn)正好解決了上述問(wèn)題[3]。
OpenGL函數(shù)庫(kù)和操作系統(tǒng)無(wú)關(guān),,它有自己的獨(dú)特設(shè)計(jì),,與Windows的圖像設(shè)備接口GDI模型以及多數(shù)MFC應(yīng)用程序的建立方法不太一致。在Windows系統(tǒng)中,,這樣的一組函數(shù)稱為wiggle函數(shù),,每個(gè)wiggle函數(shù)的前綴是“wgl”。
在Win32下,,首先必須重新設(shè)置畫(huà)圖窗口的像素格式,,使其符合OpenGL對(duì)像素格式的需要。為此,,聲明一個(gè)PIXELFORMATDESCRIPTOR結(jié)構(gòu)的變量,,并適當(dāng)設(shè)置其結(jié)構(gòu)成員的值,使其支持OpenGL及其顏色模式,。再以此變量為參數(shù)調(diào)用ChoosePixelFormat(),,分配一個(gè)像素格式號(hào),然后調(diào)用SetPixelFormat()將其設(shè)置為當(dāng)前像素格式,。
完成了像素格式的重新設(shè)置后,,需要為OpenGL建立繪制描述表(Render Context)。繪制描述表的作用類似于Windows中的設(shè)備描述表(Device Context),。只有建立了繪制描述表RC后,,OpenGL才能調(diào)用繪圖原語(yǔ)在窗口中做出圖形。Win32API提供了幾個(gè)操作繪制描述表的函數(shù),,包括建立,、復(fù)制,、使用、刪除和查詢等,,它們都以wgl為詞頭,。RC是以線程為單位的,每一個(gè)線程必須使用一個(gè)RC作為當(dāng)前RC才能執(zhí)行OpenGL繪圖原語(yǔ),。
wglCreateContext()是建立繪制描述表的函數(shù),,它以一個(gè)指向GDI設(shè)備描述表的句柄為參數(shù),返回一個(gè)與此設(shè)備描述表相關(guān)聯(lián)的繪制描述表句柄,。在以此2句柄為參數(shù)調(diào)用函數(shù)wglMakeCurrent(),,使RC成為線程當(dāng)前使用的RC,完成Windows下OpenGL繪圖環(huán)境的初始化過(guò)程[4],。
2 建立OpenGL單文檔應(yīng)用程序框架
使用Visual C++的AppWizard和Class Wizard可以很容易地生成一個(gè)使用MFC的OpenGL單文檔應(yīng)用程序框架,,名稱為MyFountain。
2.1 PreCreateWindow方法
BOOL CMySDOpenGLView:: PreCreateWindow(CREATESTRUCT& cs)
{
cs.style|=WS_CLIPCHILDREN|WS_CLIPSIBLINGS,;
return CView::PreCreateWindow(cs);
}
使視窗口具有WS_CLIPCHILDREN和WS_CLIPSIBLINGS風(fēng)格,,確保成功地設(shè)置像素格式,。
2.2 添加消息響應(yīng)函數(shù)
利用MFC ClassWizard為CMySDOpenGLView類添加消息WM_CREATE、WM_DESTROY,、WM_SIZE和WM_TIMER的響應(yīng)函數(shù),。
首先在OnCreate方法中初始化OpenGL,并設(shè)置定時(shí)器,。
然后在OnTimer響應(yīng)函數(shù)中添加定時(shí)器響應(yīng)函數(shù)和場(chǎng)景更新命令,,使得程序按照定時(shí)器設(shè)置的時(shí)間步長(zhǎng)進(jìn)行中斷,并調(diào)用OnDraw對(duì)場(chǎng)景進(jìn)行更新,、渲染,。
第三步,添加OnSize函數(shù)對(duì)用戶進(jìn)行窗口調(diào)整的消息進(jìn)行響應(yīng),,并即時(shí)調(diào)整窗口的大小[5],。
最后,當(dāng)關(guān)閉窗口時(shí),,將值NULL(或0)賦值給wglMakeCurrent()的參數(shù)hRC后,,調(diào)用wglDeleteContext()刪除繪制描述表,并刪除調(diào)色板和定時(shí)器,。
3 基于粒子系統(tǒng)的噴泉模擬
構(gòu)造可視化系統(tǒng)的建模技術(shù)大致可以分為兩類:幾何建模和行為建模,。幾何建模處理物體的幾何和形狀的表示,研究圖形數(shù)據(jù)結(jié)構(gòu)等基本問(wèn)題,;行為建模處理物體運(yùn)動(dòng)和行為的描述,。
一個(gè)粒子系統(tǒng)由大量稱為粒子的簡(jiǎn)單體素構(gòu)成,。每個(gè)粒子有一組屬性,如位置,、速度,、顏色和生命期。一個(gè)粒子究竟有什么樣的屬性,,主要取決于具體的應(yīng)用,。粒子的初值由隨機(jī)過(guò)程產(chǎn)生。粒子往往由位于空間的某個(gè)地方的粒子源產(chǎn)生,。
粒子系統(tǒng)也利用了隨機(jī)過(guò)程,,并常將物體的幾何和行為組合在一個(gè)有機(jī)模型中。
一個(gè)粒子系統(tǒng)是不斷進(jìn)化的,。在生命期的每一刻,,都要完成以下4步工作:
(1)粒子源產(chǎn)生新粒子,。產(chǎn)生任意數(shù)目的新粒子,,它們的初始屬性由隨機(jī)過(guò)程控制。每個(gè)粒子都有一個(gè)生命期,,如果某些粒子不應(yīng)刪除,,則可以賦予它無(wú)限長(zhǎng)的生命期。
?。?)更新現(xiàn)有粒子屬性,。例如,若粒子有位置和速度屬性,,在模擬重力場(chǎng)中的運(yùn)動(dòng)時(shí),,可以如下更新粒子的位置和速度屬性:
v=v+gts=s+vt
在該步中,粒子的生命期遞減一個(gè)時(shí)間步,。
?。?)刪除“死”粒子。檢查粒子的生命期,,若為0則將粒子從系統(tǒng)中刪除,。
(4)繪制粒子,。顯示粒子系統(tǒng)中所有現(xiàn)存的粒子,。
在一般情況下,粒子的幾何特征十分簡(jiǎn)單,,可以采用一個(gè)像素或小的多邊形來(lái)代表[6],。
3.1 粒子數(shù)據(jù)結(jié)構(gòu)的定義
粒子數(shù)據(jù)結(jié)構(gòu)的定義如下:
struct particle
{
float t; //粒子的生命期
float vel,; //粒子運(yùn)動(dòng)的速度
float dir,; //粒子運(yùn)動(dòng)的方向
float x,,y,z,; //粒子的位置坐標(biāo)
float xd,,zd; //粒子的X和Z方向增加值
char type,; //粒子類型(運(yùn)動(dòng)或淡化)
float a,; //淡化alpha值
struct particle*next,*prev,;
},;
3.2 繪制噴泉
3.2.1 先構(gòu)造一個(gè)場(chǎng)景
由于重點(diǎn)是噴泉,因此簡(jiǎn)單構(gòu)造一個(gè)模擬的地面能突出噴泉就可以了,。實(shí)現(xiàn)代碼如下:
glClear(GL_COLOR_BUFFER_BIT),;
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D,,texture[1]),;
a+=0.2;
gluLookAt(cam.x,,cam.y,,cam.z,0,,0,0,,upv.x,,upv.y, upv.z),;
3.2.2 噴泉的渲染處理
噴泉的渲染處理過(guò)程主要是利用了OpenGL的特征函數(shù)[7]和方法,,主要進(jìn)行了兩方面的處理:(1)將噴泉模型渲染成紋理文件[8];(2)采用透明紋理渲染技術(shù)[9],。
3.2.3 噴泉的實(shí)現(xiàn)
在構(gòu)造了簡(jiǎn)單的地面場(chǎng)景后,,取以原點(diǎn)為中心的圓周上的均勻點(diǎn)序列作為噴泉的噴射點(diǎn),按照上述提到的繪制方法[10]即完成了噴泉的動(dòng)態(tài)模擬,。噴泉系統(tǒng)模擬的主要關(guān)鍵代碼在于向內(nèi)存中添加渲染粒子,,即函數(shù)AddParticles(),之后粒子將按照預(yù)定的軌道運(yùn)行,,其主要實(shí)現(xiàn)代碼如下:
//添加新的粒子
void CMyFountainView::AddParticles()
{
struct particle*tempp,;
int i, j,;
for (j=0,;j<18,;j++)
for (i=0;i<2,;i++)
{
tempp=(struct particle*)malloc(sizeof(struct particle)),;
if (fn[j])fn[j]->prev=tempp;
tempp->next=fn[j],;
fn[j]=tempp,;
tempp->t=-9.9; //粒子的生命期
tempp->v=(float)(rand()%200000)/100000+1,;
// 粒子速度
tempp->d=(float)(rand()%400)/100-2,;
//粒子方向
tempp->x=20*cos((j*3.14159)/180); //開(kāi)始位置的坐標(biāo)
tempp->y=0,;
tempp->z=20*sin((j*3.14159)/180),;
tempp->xd=cos((tempp->d*3.14159)/180)*tempp->v/4;
tempp->zd=sin((tempp->d*3.14159)/180)*tempp->v,;
tempp->type=0,; //粒子狀態(tài)為運(yùn)動(dòng)
tempp->a=1; //粒子淡化
}
}
噴泉的效果顯示如圖1所示,。
通過(guò)改變程序中alpha(圓的內(nèi)接正多邊形圓心角)的值,,可以改變噴泉粒子流的股數(shù)。噴泉的粒子流粗細(xì)可通過(guò)改變矢量的乘積來(lái)實(shí)現(xiàn),,通過(guò)改變“vectl.x*=5,;vectl.y*=5;vectl.z*=5,;”等式右邊的數(shù)值可以控制,,圖1就是改為“5;3,;2,;”的結(jié)果。
通過(guò)上述的試驗(yàn)比較可知,,噴泉粒子流的股數(shù)和每股粒子流的粒子數(shù)目都會(huì)影響到噴泉模擬效果的真實(shí)感[11],。
越來(lái)越多的人注意到使用Visual C++和OpenGL開(kāi)發(fā)三維圖形動(dòng)畫(huà)軟件的有利之處,但是有關(guān)OpenGL的資料大多都是介紹基本的編程指南或者一些基礎(chǔ)的原理或方法,,卻很少有大型的與應(yīng)用有關(guān)的編程案例,,而且有也大多都是基于Win32的類來(lái)實(shí)現(xiàn)一些簡(jiǎn)單的圖形功能,介紹MFC與OpenGL連接的資料卻少之又少,,本文主要是在MFC下實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的噴泉模擬程序,,主要的創(chuàng)新點(diǎn)是分析了MFC下消息響應(yīng)的內(nèi)部機(jī)制,所以希望本次的探索能對(duì)以后利用MFC開(kāi)發(fā)出更高效的程序有所幫助,。
參考文獻(xiàn)
[1] 和平鴿工作室.OpenGl高級(jí)編程與可視化系統(tǒng)開(kāi)發(fā)(高級(jí)編程篇)[M].北京:中國(guó)水利水電出版社,,2007.
[2] 徐明亮,,盧紅星,王琬.OpenGl游戲編程[M].北京:機(jī)械工業(yè)出版社,,2008.
[3] REEVES W T. Particle systems-a technique for modeling a class of fuzzy objects[J]. ACM Transations on Graphics(TOG),, 1983,2(2):359-376.
[4] 周建龍,,肖春.計(jì)算機(jī)圖形學(xué)理論與OpenGl編程實(shí)踐[M].廣州:華南理工大學(xué)出版社,,2007.
[5] 孫鑫,余安萍.VC++深入詳解[M].北京:電子工業(yè)出版社,,2008.
[6] 雷曉,,胡倩.基于Direct3D的粒子系統(tǒng)設(shè)計(jì)[J].微計(jì)算機(jī)信息,2010(11-1).
[7] 張芹,,吳慧中,,謝雋毅.基于粒子系統(tǒng)的火焰模型及其生產(chǎn)方法研究[J].計(jì)算機(jī)輔助設(shè)計(jì)與圖形學(xué)報(bào),2001,,13(1):78-82.
[8] PHONG B T. Illunimation for computer generated pictures[J].Communications of the ACM,,1975,18(6):311-317.
[9] 侯陽(yáng),,迪克.三維圖形動(dòng)畫(huà)編程實(shí)例[M].海洋出版社,,1993.
[10] 楊春雨.基于粒子系統(tǒng)的噴泉?jiǎng)赢?huà)模擬[J].長(zhǎng)春:吉林大學(xué)出版社,2008.
[11] 凌云,,儲(chǔ)林波.用Visual C++中的MFC和OpenGl建立三維圖形應(yīng)用環(huán)境[J].微型機(jī)與應(yīng)用,,1998,17(4):8-10.