VC++編程實(shí)現(xiàn)對(duì)火焰的計(jì)算機(jī)動(dòng)態(tài)仿真
更新時(shí)間: 2007-05-10 13:47:15來源: 粵嵌教育瀏覽量:893
摘要:本文通過對(duì)真實(shí)火焰物理特性的分析,建立了火焰動(dòng)態(tài)燃燒的數(shù)學(xué)模型,并在此數(shù)學(xué)模型基礎(chǔ)之上借助于DirectDraw技術(shù)對(duì)圖形顯示的加速,在VC++ 6.0下對(duì)火焰作了效果非常逼真的計(jì)算機(jī)動(dòng)態(tài)仿真。
關(guān)鍵詞:火焰;DirectDraw;計(jì)算機(jī)仿真
引言
計(jì)算機(jī)仿真技術(shù)的基本原理都是一樣的,神秘復(fù)雜的核爆同水波、火焰、煙霧等非常平常的自然現(xiàn)象在仿真處理過程中并沒有什么太大的區(qū)別。都是經(jīng)歷了從實(shí)體對(duì)象到物理特性的總結(jié),再由此建立數(shù)學(xué)模型并在數(shù)學(xué)模型基礎(chǔ)之上提出仿真算法,通過計(jì)算機(jī)將其動(dòng)態(tài)仿真出來等一系列步驟。本文以火焰作為仿真對(duì)象,通過對(duì)熱源、熱擴(kuò)散以及對(duì)流等特性的分析對(duì)其建立了數(shù)學(xué)模型及仿真算法,為了能充分發(fā)揮計(jì)算機(jī)對(duì)圖形的硬件加速,使用DirectDraw技術(shù)對(duì)仿真結(jié)果顯示進(jìn)行了加速,使之能逼真、流暢地對(duì)火焰的燃燒過程實(shí)行動(dòng)態(tài)模擬。
簡單近似模型設(shè)計(jì)
雖然火焰在自然界是一種極普通的自然現(xiàn)象,但根據(jù)流體力學(xué)的相關(guān)知識(shí),火焰可以表達(dá)為一個(gè)相當(dāng)復(fù)雜的三維動(dòng)態(tài)流體系統(tǒng)。如要在計(jì)算機(jī)中對(duì)這樣一個(gè)復(fù)雜的流體系統(tǒng)做出精確的仿真將需要有相當(dāng)龐大復(fù)雜的數(shù)學(xué)模型為基礎(chǔ),而且運(yùn)算量將非常巨大,在現(xiàn)有的微型計(jì)算機(jī)中幾乎很難保證其動(dòng)態(tài)實(shí)時(shí)性,這也就失去了仿真的意義。因此,在仿真時(shí)應(yīng)用盡可能簡單的模型來實(shí)現(xiàn)盡可能逼真的效果。
從物理角度分析,要產(chǎn)生火焰,首先要有火源,其次為了產(chǎn)生"焰"的效果,需要以火源為中心向上、向四周擴(kuò)散,而且由于在擴(kuò)散過程中逐漸遠(yuǎn)離火源,溫度會(huì)逐漸下降,表現(xiàn)在視覺上就是火焰的冷卻變暗。另外,由于火焰的高溫使周圍空氣受熱膨脹比重下降,因此會(huì)有空氣的對(duì)流出現(xiàn),這將把火焰向上"吹"起,使火焰向四周擴(kuò)散的距離要遠(yuǎn)小于向上擴(kuò)散的距離。基于以上幾點(diǎn)認(rèn)識(shí),可以采取對(duì)應(yīng)的仿真措施:對(duì)火源的設(shè)置可以用一幅二值位圖來標(biāo)識(shí),非火源以低亮度像素填充、火源點(diǎn)則設(shè)以高亮度像素,通過對(duì)位圖像素值的判別可以斷定當(dāng)前點(diǎn)是否為火源。
對(duì)于火源的溫度高低可用其所在點(diǎn)的亮度來描述;對(duì)于火焰擴(kuò)散的模擬,為盡量減少運(yùn)算量,在此簡單地用某火源點(diǎn)(x,y)及其前后左右鄰近四點(diǎn)的均值來近似,即Pixel(x,y)=(Pixel(x,y)+Pixel(x,y-1)+Pixel(x,y+1)+Pixel(x-1,y)+Pixel(x+1,y))/5,雖然該近似算法沒有采取正余弦的方法精確,但運(yùn)算速度極快,而且在后續(xù)的實(shí)驗(yàn)效果上同采用正余弦的方法幾乎沒有任何差別;由于在仿真過程中對(duì)火焰的溫度是通過改變其亮度值來實(shí)現(xiàn)的,因此對(duì)于擴(kuò)散過程的冷卻可對(duì)像素點(diǎn)降低一個(gè)固定的亮度值來實(shí)現(xiàn)。衰減值的大小需要視所希望火焰冷卻速度的快慢而定;對(duì)流對(duì)火焰產(chǎn)生的直接影響就是使火焰始終保持向上燃燒,因此可通過將當(dāng)前火焰上滾一至兩個(gè)像素來加以實(shí)現(xiàn)。根據(jù)前面描述的仿真運(yùn)算法則,可將火焰的擴(kuò)散和對(duì)流融合在一起實(shí)現(xiàn),這將在一定程度上減少運(yùn)算量,使產(chǎn)生的火焰在視覺上更加真實(shí)。實(shí)現(xiàn)上述近似模型的偽代碼可大致設(shè)計(jì)如下:
ARRAY_OF_BYTES: buffer1(xsize*ysize),buffer2(xsize*ysize)
While(TRUE){
for(y=1;y<ysize-2;y++){
for(x=1;x<xsize-2;x++){
n1 = buffer1(x+1, y) //讀取4相臨像素值
n2 = buffer1(x-1, y)
n3 = buffer1(x, y+1)
n4 = buffer1(x, y-1)
p = ((n1+n2+n3+n4+p) /5); //四臨像素均值
p = p-c; //同一固定冷卻衰減值相減
if(p<0)
p=0
buffer2(x,y-1)=p
}
}
copy buffer2 to the screen ; //顯示下一幀
copy buffer2 to buffer1; //更新Buffer1
}
火焰非均勻冷卻的改進(jìn)模型
根據(jù)上述近似模型可對(duì)火焰進(jìn)行一定程度上的仿真,但由于沒有引入隨機(jī)分布火焰往往看上去相當(dāng)單調(diào)規(guī)則,而且火焰總呈線性上升,冷卻速度也嚴(yán)格地保持統(tǒng)一速率。要消除以上問題,可通過引入隨機(jī)非均勻因素來解決。一種途徑是隨機(jī)布置各點(diǎn)冷卻值使火焰冷卻過程非均勻化。但由于火焰的模擬過程是實(shí)時(shí)進(jìn)行的,為確保動(dòng)態(tài)模擬過程中能順暢進(jìn)行,用預(yù)先創(chuàng)建的冷卻位圖(見右圖)來代替。一般采用在屏幕上隨機(jī)撒布幾千個(gè)亮度不同的點(diǎn)并對(duì)其應(yīng)用平滑處理等方法對(duì)冷卻位圖加以填充。通過冷卻圖中獲取的數(shù)值來代替原來固定的冷卻衰減值效果要好的多,此時(shí)的冷卻過程改進(jìn)為Pixel(x,y)=Pixel(x,y)-Coolingmap(x,y) 這樣的衰減結(jié)果將使火焰的冷卻衰減效果更加真實(shí):
p = lightBuf2+imgWidth*2;
pp = coolMap + coolMapWidth*2;
p1 = lightBuf1+imgWidth*2;
p2 = p1 - imgWidth;
p3 = p1 - 1;
p4 = p1 + 1;
p5 = p1 + imgWidth;
for(i=0;i<imgWidth*(imgHeight-4);i++){
//計(jì)算某點(diǎn)及其四鄰像素均值
c1=(unsigned char)(((UINT)*p1+(UINT)*p2+(UINT)*p3+(UINT)*p4+(UINT)*p5)/5);
c2 = *pp;
if(c1>c2)
c1 -= c2;
*p = c1;
pp++,p++,p1++,p2++,p3++,p4++,p5++; //內(nèi)存指針修正
}
由于火焰在進(jìn)行冷卻衰減的同時(shí)也在進(jìn)行著火焰的擴(kuò)散與對(duì)流因此必須使這幾種效果保持同步,這需要以同對(duì)流速度相同的速度向上滾動(dòng)冷卻位圖來實(shí)現(xiàn)。為減少不必要的操作,滾動(dòng)是在內(nèi)存中通過改變冷卻位圖的垂直偏移量來加以實(shí)現(xiàn):
memcpy(lightBuf1,lightBuf1+imgWidth*3,imgWidth*(imgHeight-3));
經(jīng)過以上幾步處理雖有一定程度的改善,但仍存在一些缺陷,比如生存期、火焰上升速度恒定、在整個(gè)空間燃燒等。為使仿真效果更加逼真,可通過設(shè)置種子點(diǎn)來對(duì)上述缺陷加以改進(jìn)。同樣出于處理速度的考慮,將種子點(diǎn)也以位圖的形式預(yù)先設(shè)定,在仿真時(shí)直接在內(nèi)存中通過移動(dòng)指針來完成對(duì)種子點(diǎn)的訪問,其主要代碼大致如下:
int t = RAND_MAX/5;
topX = (imgWidth - seedMapWidth)/2; //seedMapWidth種子位圖寬度
topY = (imgHeight - seedMapHeight)/2; //seedMapHeight種子位圖高度
p = lightBuf1 + (topY+2)*imgWidth + topX; //p, unsigned char型指針
ps = seedMap + seedMapWidth*2; //ps, unsigned char型指針
for(j=0;j<(seedMapHeight-4);j++) {
p1 = p; //p1, unsigned char型指針
for(k=0;k<seedMapWidth;k++){
if(*ps != 0){ //ps, unsigned char型指針
if(rand() < t)
*p1 = 255;
}
p1++,ps++; //指針修正
}
p += imgWidth; //指針修正
}
圖形加速顯示
前面的算法設(shè)計(jì)中一直很注意減少不必要的運(yùn)算量以期獲得盡可能高的處理速度,但僅靠好的算法遠(yuǎn)不能取得滿意的視覺效果。不少大型游戲盡管場景非常復(fù)雜,場景變化快,但玩家很少能感覺到游戲有難以忍受的停頓感。這不僅因?yàn)橛螒虿扇×撕玫乃惴ǜ匾氖怯螒蛟谕婕医换サ倪^程中大量采用了Direct X技術(shù),該技術(shù)是Direct Draw、Direct Sound、Direct 3D等諸多技術(shù)的總稱。DirectDraw是其中主要的一個(gè)部件,主要負(fù)責(zé)對(duì)圖形的加速,并允許程序員可以直接操作顯存、硬件位圖映射以及硬件覆蓋和換頁技術(shù)。而且該技術(shù)還支持雙緩沖和圖形換頁、3D z-buffers (z緩存)以及z方向(z-ordering)硬件輔助覆蓋等許多重要功能。可以看出,通過使用Direct Draw技術(shù)將極大改善仿真結(jié)果的圖形輸出效果,能非常流暢地對(duì)火焰進(jìn)行實(shí)時(shí)的仿真。使用該技術(shù)之前必須先進(jìn)行初試化等預(yù)處理工作:
//創(chuàng)建DirectDraw對(duì)象(為突出程序流程,以下均對(duì)錯(cuò)誤檢測進(jìn)行了省略)
DirectDrawCreate( NULL, &lpDD, NULL );
//取得全屏獨(dú)占模式
lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
//設(shè)置顯示器顯示模式
lpDD->SetDisplayMode( 640,480, 16 );
//填充主頁面信息
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1; //一個(gè)后臺(tái)頁面
//創(chuàng)建主頁面
lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);
DDPIXELFORMAT pixelFormat;
pixelFormat.dwSize = sizeof(DDPIXELFORMAT);
lpDDSPrimary->GetPixelFormat(&pixelFormat);
……
初始化完成后可以通過在后臺(tái)頁面繪圖,并在繪制完畢后將后臺(tái)頁面復(fù)制到主頁面完成對(duì)一幀圖像的顯示:
lpDDSBack->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx);
ddrval = lpDDSBack->Lock(NULL, &ddsd, 0, NULL) //鎖定后臺(tái)頁面
while (ddrval== DDERR_WASSTILLDRAWING);
if( ddrval == DD_OK ){
fire.render((WORD*)ddsd.lpSurface); //完成對(duì)一幀火焰的渲染
lpDDSBack->Unlock(NULL); //解鎖后臺(tái)頁面
}
while( 1 ) {
ddrval = lpDDSPrimary->Flip( NULL, 0 ); //換頁
if( ddrval == DD_OK )
break;
if( ddrval == DDERR_SURFACELOST ){
ddrval = lpDDSPrimary->Restore(); //恢復(fù)主頁面
if( ddrval != DD_OK )
break;
}
if( ddrval != DDERR_WASSTILLDRAWING )
break;
}
根據(jù)以上程序算法對(duì)火焰進(jìn)行了仿真實(shí)驗(yàn),在速度和仿真結(jié)果在視覺的逼真程度上都獲得了非常好的效果。右圖是從仿真過程中截取的一幀畫面,從圖中可以看出,雖然在前面的算法設(shè)計(jì)過程中多處采用了看似過分的近似處理,但并未因此產(chǎn)生負(fù)面效果。實(shí)驗(yàn)表明,本文采用的在數(shù)據(jù)緩沖區(qū)中對(duì)圖象進(jìn)行處理的方法在程序運(yùn)算和顯示的速度上與仿真對(duì)象--火焰的復(fù)雜程度是無關(guān)的,因此用類似的方法完全可以比較容易地實(shí)現(xiàn)對(duì)其他復(fù)雜物理、自然現(xiàn)象的仿真模擬。
結(jié)論
本文通過對(duì)火焰的計(jì)算機(jī)仿真模擬實(shí)現(xiàn)過程,對(duì)仿真模擬類程序一般的設(shè)計(jì)實(shí)現(xiàn)過程做了簡要介紹。通過對(duì)本文所述程序設(shè)計(jì)思路與實(shí)現(xiàn)方法的理解,可以用類似的方法結(jié)合實(shí)際情況靈活選用諸如OpenGL、Direct3D等不同的軟件接口對(duì)其他一些自然現(xiàn)象進(jìn)行仿真模擬。本文所述程序在Windows 98下,由Microsoft Visual C++ 6.0調(diào)試通。
粵嵌動(dòng)態(tài)
推薦閱讀
- ·Linux字符設(shè)備驅(qū)動(dòng)框架解析:file_operations的核心作用與實(shí)現(xiàn)
- ·廣東朝歌數(shù)碼科技股份有限公司專場招聘會(huì)
- ·深化產(chǎn)教融合,共筑技能人才培養(yǎng)新生態(tài) —— 廣州華立學(xué)院到訪粵嵌從化校區(qū)為深化產(chǎn)教
- ·校企合作新突破 | 粵嵌科技與三亞學(xué)院共探產(chǎn)教融合新路徑
- ·粵嵌科技入選國家級(jí)職業(yè)數(shù)字展館聯(lián)合建設(shè)單位,賦能計(jì)算機(jī)程序設(shè)計(jì)員高技能人才培養(yǎng)
- ·嵌入式實(shí)時(shí)操作系統(tǒng)的性能優(yōu)化與實(shí)現(xiàn)路徑
- ·校企攜手賦能教育!粵嵌科技助力海南科技職業(yè)大學(xué)探索 AGI 時(shí)代教學(xué)新范式
- ·嵌入式系統(tǒng)中的低功耗設(shè)計(jì)策略與實(shí)現(xiàn)路徑
- ·深圳市軒宇軟件開發(fā)有限公司專場招聘會(huì)
- ·嵌入式系統(tǒng)中的代碼空間優(yōu)化:策略與實(shí)踐