1. 程式人生 > >手機端戰爭迷霧的實現

手機端戰爭迷霧的實現

先展示效果:

最早是在war3看到戰爭迷霧,當時覺得真牛逼。到現在技術基本已經成熟,自己也就抽空做一個。

思路還是定在用tile來實現,畢竟從效能優化角度說,tile可以預先烘焙資料,比實時計算要快不少,這樣的話手遊也可以使用。

先畫一批格子:

有了基本的地圖資料,我們就需要開始考慮怎麼實現我們的戰爭迷霧。首先把人的座標轉化到地圖座標,先考慮最基本的圓形,根據每個格子距離人的座標的距離和視野半徑比較,我們就可以得到這個格子是否可見。為了能夠實現迷霧的效果,我們需要將這些資料儲存在一張貼圖中。而迷霧在人運動過程中需要變化,我們需要在這個過程中提供平滑的漸變過度,首先想到的是用兩張圖做過度,但其實只表示可見性的話,一個通道就夠了,那麼我們就用r通道儲存上一次的可見範圍,g通道儲存這次的可見範圍,然後做線性插值完成過度。

這裡要注意,如果半徑大,計算可見性範圍其實會比較耗時,特別是如果要支援障礙視野的情況下,於是我們可以將這些計算放到子執行緒中做。現在手機多核,特別適合去用子執行緒做計算量大的東西。

算出全部的視野後,我們需要做一個世界座標到螢幕座標的投影,注意,這裡的螢幕其實是貼圖那個螢幕,

 實際使用過程中我們無需注意z軸,所以只需要設定好矩陣的xy和w部分就行。另外,由於這是opengl推倒出來的,我們可以知道它所對應的座標系是(-1,1)的螢幕座標,同時,紋理貼圖是(0-1),這裡要注意dx是左上角0,0,而opoengl是左下角0,0,這個我們可以通過在shader裡處理,這裡暫時先不管。

然後是要怎麼具體實現迷霧效果的問題。首先我們思考在場景中的一個點,我們通過上面算的矩陣可以得到他在貼圖中的座標,根據貼圖的畫素值,我們可以得到這個點是否可見。問題在於,在知道點不可見後,我們如何遮住它。我們可以使用Projector,也可以在螢幕空間進行計算得到螢幕畫素顏色。但考慮到手機上追求效能,我覺得將一個plane放在整個場景的上部,通過渲染plane達到遮蓋的目的。當然問題也存在,就是如果地形高低變化很大,那麼計算的迷霧就會產生錯誤,考慮到使用迷霧的大部分都是平地以及高低變化不大的地面,所以我認為這麼做是值得的。

用了這樣的做法,效能是達標了,但效果還是差了點。

仔細研究了一下,發現還有兩個優化的點,一個是判斷格子的時候,其實可以適當增加計算量,增加視野的精確度。

第二是需要改變先混合再計算這樣的模式,而是混合時支援同步計算。這樣可以是過度更加平滑。

最後我覺得還有一個點,就是場景要複雜一些,加上一點點半透明,整個戰爭迷霧的感覺會好很多。

修改了下判斷格子的演算法:

精確度上去了,然後就是平滑,首先把探索過的區域用一點點透明,然後把blend和update同時進行。

放到手機上跑了一下,可以到60幀,而且整個體驗還算平滑。最後就是完善demo,做成外掛了。

最後說幾個細節點:

1.其實格子並不是越多越好,越多意味著效能開銷越大,同時邊界不為由於過度精確,做模糊的時候需要做更多模糊次數才有過度平滑的效果。個人覺得一個格子站住一個人調出來的效果其實是最好的。

2.如果是手機上,建議不要使用螢幕空間去計算,因為螢幕空間需要一張額外的深度圖。除非你的地形高低變化很大,否則直接用一個大平面覆蓋在你的地形上就好。只要起伏不大,位置誤差還可以接受。

3.做迷霧變化過度要考慮到過度到一半視野發生更新的情況,要保證從現在的情況+多執行緒計算的時間到最終情況的過度。這樣做出來的才會順滑。

4.多執行緒立了大功,將迷霧計算和模糊都用多執行緒處理,基本不會引起幀率下降。而且視野計算精度可以用高一點的精度演算法。

5.幀同步遊戲我想了一下,應該沒法使用多執行緒,或者說用多執行緒要做大量的額外工作去控制。所以幀同步估計還是需要地圖預烘焙的方案,把模糊丟給gpu,應該就可以了。對於動態障礙物遮蔽視野,需要額外優化處理了。

最後是外掛地址: