劉賢梅,王 偉,薛繼偉 (東北石油大學計算機與信息技術學院,黑龍江大慶1 6331 8)
對火焰等景物進行仿真模擬一直是計算機圖形學研究中的熱點課題[1]。由于這些形狀不規則物體都具有實時變化的特征,并且含有豐富的細節,因此很難用傳統的造型方法來表現。
粒子系統是模擬復雜的、運動的、不規則物體非常有效的一種圖形生成技術[2]。以往的粒子系統的計算完全是在CPU上完成的。由于CPU的任務繁多,因此在實際運算的時候常常出現顯卡等待CPU數據的情況,影響了繪制速度[3]。針對以上問題,筆者在進行油田井口事故火焰實時仿真時將粒子系統的所有計算完全放入GPU中,在GPU中完成粒子屬性的更新和繪制,不需要每次更新時從CPU中讀取粒子數據進行繪制。因此,減少了粒子系統更新中GPU和CPU之間的頻繁通信、系統內存和顯存間的頻繁數據傳送,降低CPU的負擔,使粒子系統達到更高的實時性和高仿真性。
為每個粒子定義一個頂點,目的是可以在屏幕上顯示粒子的屬性值,從而實現火焰的模擬。頂點結構定義如下:

Postion是頂點最終繪制在屏幕上的位置,在Vertex Shader中對其進行賦值。
Coords是頂點所對應的屬性紋理的紋理坐標。
在CPU上二維網格表現為一個數組,而在GPU中二維網格則表現為一張紋理,紋理具有GRBA 4個通道,提供了一個天然的數據結構。最基本的運算是二維網格上數據的讀取,在GPU中使用紋理查詢來完成。CPU中數組的偏移對應GPU中紋理的紋理坐標。
根據以上分析,把粒子屬性數據存儲到紋理中。油田井口事故火焰粒子中最重要的屬性是位置和速度。由于速度精度低,使用16位的浮點格式紋理存儲速度;位置的精度相對比較高,使用32位浮點格式紋理存儲位置數據。火焰粒子的其他屬性如生命值、顏色值、透明度都使用16位的浮點格式紋理存儲。
由于受當前圖形硬件的限制,同一個紋理不能同時被寫入和讀出,因而更新后的屬性不能存儲到原有紋理中。要解決上述問題,需要引入雙緩存技術。每個屬性都需要2張具有相同大小和格式的紋理。首先將其中一塊作為輸入,另一塊作為輸出。在下一幀的計算中,輸入緩沖區變為輸出,輸出緩沖區變為輸入。存儲方式如圖1所示。

圖1 粒子屬性存儲方式
為了計算火焰粒子運動,對每個粒子定義如下屬性紋理:①2張16位的浮點格式速度紋理 VelTex:分別存儲前一幀和下一幀粒子的速度。②2張32位浮點格式位置紋理PosTex:分別存儲前一幀和下一幀粒子的位置。③2張 16位的浮點格式生命紋理AgeTex:分別存儲前一幀和下一幀粒子的生命值。④2張16位的浮點格式顏色紋理ColTex:分別存儲前一幀和下一幀粒子的顏色值。⑤2張16位的浮點格式透明度紋理tranTex:分別存儲前一幀和下一幀粒子的透明度。⑥1張初始位置紋理InitPosTex,存儲每個粒子的初始位置。⑦1張初始速度紋理InitVelTex,存儲每個粒子的初始速度。
著火極限、著火溫度和燃燒速度,常統稱為火焰3要素。油田井口發生火災具有燃燒速度快、火焰溫度高、易發生爆炸和火勢極易蔓延的特點。因此,用粒子系統模擬油田井口事故火焰時應突出上述特點。
1)火焰粒子的產生 油田井口事故火焰粒子系統產生粒子的過程即對新粒子的屬性進行初始化。在該系統中,由于火焰是從井口中產生的。井口相當是一個圓柱體,采用了一種新的方法實現粒子的發射源,即用Y值確定井口的高度,用θ和X軸之間的夾角確定井口表面的任何一點作為粒子的發射器。如圖2所示。

圖2 粒子發射器
Velocity為粒子的速度值,f為粒子速度的大小。火焰粒子發射速度的3個分量為:①粒子沿X軸、Y軸和Z軸方向的速度值分別為Velocity.x=f*cosθ、Velocity.y=f和Velocity.z=f*sinθ。
2)火焰粒子的初始位置及速度 火焰粒子的初始位置及速度是實現動態火焰必不可少的因素。Centerpos、VarPos、Velocity和VarSpeed是粒子系統中的4個系統參數,分別表示粒子的火焰燃燒的中心位置、位置變化范圍、粒子的平均速度和速度變化范圍。初始位置和速度的設置分別如下:

3)火焰粒子的貼圖 粒子的貼圖對火焰的外觀極為重要。石油著火焰色反應表現為火焰中外焰溫度最高顯紅火黃色,內焰溫度稍低顯黃色并有一定的透明度。由于外焰和內焰的顏色不一樣,因而通過著色語言對所屬范圍的粒子顏色屬性和透明度屬性做不同的賦值。著色語言如下:

為了盡量使模擬的火焰逼真,采用真實的油田井口事故火焰的照片并進行處理,截取火焰的內焰和外焰的貼圖,對火焰粒子的所屬內焰和外焰分別進行貼圖,以達到最佳火焰模擬效果。火焰粒子內焰和外焰的貼圖分別如圖3和圖4所示。

圖3 內焰貼圖

圖4 外焰貼圖
4)火焰粒子大小 粒子的大小決定了火焰模擬的精細程度。粒子過大,火焰失真;反之,系統的實時性較差。采用四邊形面片表示火焰粒子,當繪制離井口中心較遠的火焰時,使用較大的粒子;當繪制離井口中心較近的火焰時,使用較小的粒子。粒子大小定義如下:

5)火焰粒子數量 粒子的數量決定了火焰的密度,由于油田井口事故火焰的火勢比較兇猛,因此模擬火焰需要大量的粒子才能達到更加逼真的效果。根據屏幕上每單位區域產生粒子數目的平均值(AveNumber)和顯示區域 (Area)粒子大小 (Size),確定初始時刻產生的粒子數量 (Number):

6)粒子屬性數據的更新 火焰粒子屬性的更新可以通過編寫像素著色器實現。根據分析油田井口事故火焰粒子的運動模型,通過shader編程完成粒子速度、位置的更新計算,最后將計算的結果以輸出流的形式渲染到輸出紋理緩沖區中。用粒子的當前速度v(t)和時間增量(Δt)來確定粒子一幀經過的距離。該距離加上粒子的當前位置p(t)可得出其下一個位置p(t+Δ t)。通過將當前加速度值a(t)加上當前速度v(t)可將粒子的速度更新。火焰粒子的位置、速度、加速度的計算公式分別為:

7)粒子的消亡 油田井口事故火焰的高度由粒子的生命決定,因而賦給粒子生命值 (Li f e)一個初始值,把Li fe值存儲到紋理中的a通道中,隨著粒子的運動,Lif e值不斷減小。當減小到值等于零時,將該粒子設定為死亡。如果從a通道取出的生命值是負數,可將生命值截取為0,如果生命值大于1,截取為1。用all函數判斷 li f e值是否為零,若li fe值為零,則粒子消亡:isdead=all(saturate(tex2D(SamPrePosition,t0).a))。
使用渲染到頂點緩沖區的方法實現粒子的繪制[6]。紋理中的像素和頂點數據都以數組的形式存儲在顯存中。紋理中的像素數據是按照紋理的形式存儲的二維數組,而頂點數據是按照頂點的形式存儲的一維數據。Render to vertex buffer原理就是清除紋理中像素的固有解釋方式,以頂點的形式重新解釋這些數據,使GPU可以直接從渲染目標 (紋理)中讀取頂點數據,用于渲染[6]。

圖4 試驗結果截圖
該試驗使用的顯卡為NVIDIA GeForce GT 240M,顯卡顯存512MB,開發工具為Virtools,試驗結果截圖如圖4所示,圖4顯示火焰效果逼真。
對基于CPU和基于GPU 2種算法的幀率進行比較 (見表1)。從表1可以看出,當粒子數比較少的時候,2種算法的幀率沒有太大區別;當粒子數逐漸增多的時候,2種算法的幀率則產生明顯區別。如當粒子數為160000時,基于CPU算法的幀率為4幀/s,而基于GPU算法的幀率為90幀/s,其模擬火焰的效果逼真,能滿足人們正常的視覺效果。

表1 基于CPU和基于GPU 2種算法的幀率的比較
筆者提出了一種基于GPU和粒子系統實現油田井口事故火焰的模擬方法。該方法具有較高的計算速度,能夠進行大規模火焰的繪制,且模擬火焰的效果逼真。但該方法也有需要完善之處,即進一步優化GPU算法和實現火焰粒子間碰撞檢測算法。
[1]金小進,馬堯海.基于粒子系統的火焰模擬與優化 [J].計算機工程與設計,2010,31(5):1118-1120.
[2]Akeninemoller T,Haines E,Hoffman N.Real-time Rendering[M].2thed.Wellesley.Massachusetts:A.KPETERSLtd,2002.
[3]許楠,郝愛民,王莉莉.一種基于GPU的粒子系統 [J].計算機工程與應用,2009,42(19):77-79.