how to create 2D visibility/shadow effects for your game

以下翻譯轉載自:indienova

原文:http://ncase.github.io/sight-and-light/

注意:手機瀏覽可能會不能加載內嵌網頁

 

今天,我要介紹大家制作如下這個效果:(請在下面的區域內移動鼠標,如果沒有反應請點擊一下該區域再嘗試)

width="840" height="360" src="http://cocokele.com/includes/sight_and_night/draft7.html">

這個效果被用在了我最新的開源遊戲 Nothing To Hide 裏面。您可能知道,有不少遊戲都有類似的效果,比如《摩納哥:你的就是我的(Monaco: What’s Yours Is Mine)》、《爆破傑克(Dynamite Jack)》以及《史萊姆吉什(Gish)》等……說不定也會出現在你的遊戲中!

我會將自己的實現步驟以及在開發過程中犯過的錯誤展示出來。首先,是一些預熱的內容,下面的演示展示了繪製一些線段並且跟蹤鼠標的位置。(提示:一個方形由四條線段組成,以此類推)

width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft0.html">

接下來是比較數學的一部分。別擔心,只是回憶一下之前學過的代數。

我們需要找到視線(也可以是光線,我們用視線來統一代替)和這些線段之間最近的交點。任何一條線都可以這樣來表示:

這樣,我們就可以得到關於視線和線段的四個等式

注意:在我們開始之前,要注意檢查視線和相對應的線段是否平行,也就是方向是否相同。如果平行,就沒有交點,不用處理。

如果它們(視線和相對應的線段)相交,那麼交點的 X 和 Y 應該相等,也就是:


我們將用下面的方法取得 T1 和 T2

要確保 T1>0 和 0<T2<1。如果不是這樣,那麼預計中的交點並不在視線或者線段上,其實也就是無交點。如果由交點,那很好!你找到一個交點。現在用同樣一條視線和所有線段計算,以便找到最近的交點(應該是 T1 值最小的那個)。

下面是看起來的樣子:(請在下面的區域內移動鼠標)

width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft1.html">

很好,現在讓我們發射出 50 條視線來: width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft2.html">

然後,我想,我只要連接起這些交點來,就可以得到一個看起來不錯的多邊形,結果看起來是這樣:

width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft3.html">

見鬼。就算我發出 360 條視線,也還是看起來不對勁兒。這個問題困擾了我半天,直到我意識到:我不用向所有方向發出視線,我只需要向每個線段的端點發出視線就可以。

針對每一條(不同的)線段的端點,我直接發出視線,另外增加兩條偏移量爲 +/- 0.00001 弧度的視線。這兩條額外的視線用來去和線段後面的牆來相交。

width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft4.html">

接下來,我按照這些視線的角度將這些交點排序,這樣我就可以簡單的按照順時針順序將它們連接起來,可以繪製出一個看起來滿意的多邊形。

width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft5.html">

最後!看起來確實不錯了。我又添加了一些效果,看起來就像下面這樣,帶有一些模糊的陰影效果。紅點代表的是 11 個初始點——是的,11 個多邊形。

width="640" height="360" src="http://cocokele.com/includes/sight_and_night/draft6.html">

最後,做了些改進,我放了兩幅圖。然後,將這兩幅圖混合,就成了我們在開始的時候看到的那個效果那樣。

然後我又添加了額外的光源,就成了下面這樣

width="840" height="360" src="http://cocokele.com/includes/sight_and_night/draft8.html">

多光源、投射陰影、激光感應炸彈、顯示你或者敵人的可視範圍……這種 2D 的效果有很強的可擴展性,如果應用得當,加上好的創意,可以大大增強你的遊戲的吸引力

 


 

Cocos2dx實現過程

這個效果最初是在 indienova 看到的相關介紹,於是就開始琢磨如何在cocos2dx中實現這個效果。

第一次嘗試:

這個效果是由 背景圖(骷髏)和前景(美女)圖 疊加形成的,在光線變動的情況下背景保持不變,而前景根據光線的明暗相應的顯示對應部分的明暗度,而沒有被光線照射到的地方隱藏掉。

首先想到的自然是 DrawNode 繪畫出光照射到的多邊形區域,然後用ClippingNode 設置DrawNode 爲模板來繪製前景圖。

但是從效果中可以看出影子中還會區分透明度,越偏離視線的方向的光線越暗,並與前景疊加,前景被分成了幾個層次的透明度。

ClippingNode在繪製模板的時候會把模板扣摳掉,如果可以保留模板的繪製的話,就可以將前景與模板的顏色做blend處理,形成多層次透明度。

查閱 ClippingNode 代碼,發現ClippingNode在做模板設置的時候設置了 模板測試 從不通過,所以模板怎麼都不會被繪製出來。

可以修改爲

然後設置前景的blend func 爲

此時測試模板和前景是能很好的疊加效果的。

但是接下來使用DrawNode繪製多邊形的時候卻出現了問題,DrawNode對於處理複雜多邊形並不能勝任,畫出來的形狀都是亂飛的。

 

第二次嘗試:

這次嘗試了使用了 前一篇文章 介紹的nanovg 來繪製多邊形,首先建了個NvgNode,重載draw 裏面寫繪製函數,將這個node作爲模板,最後發現新問題:

1.nanovg 繪製的效率比較低,簡單測試同爲使用多邊形填充整個屏幕,nanovg 30幀,DrawNode 60幀,差的還是比較多。

2.nanovg 處理多邊形是 也是 使用 模板來處理 填充顏色,修改了一番還是不能夠很好的和cocos結合,沒有再往深處繼續研究。

 

第三次嘗試:

這次還是回到了DrawNode上,對於opengl 繪製 複雜多邊形上進行資料搜索,

看到幾種解決方案(參考):

第一種解決方案:多邊形網格化法

對於非簡單多邊形、非凸多邊形或有洞的多邊形,OpenGL在GLU庫中提供了一個多邊形網格化對象GLUtesselator,對多邊形進行網格化————將它們分解成一組簡單的、能夠進行渲染的OpenGL多邊形。

經測試這種方法對凹凸多邊形和自交、帶孔多邊形都能正確的渲染。

第二種解決方案:模板緩衝法stencil Buffer

可以參考 nanovg中的實現方法

第三種解決方案: 凹多邊形凸分解法

思路: 使用算法將凹多邊形分解爲多個凸多邊形或一系列的三角形,然後進行渲染。

 

這裏 列出了許多三角形劃分多邊形算法的實現,這裏選了一個比較靠譜的  Triangulate 來使用。

將最後輸出的多邊形分解爲三角形後調用DrawNode::drawTriangle 來繪製,成功!

--------------------------------------------------------------華麗的分割線--------------------------------------------------------

這個效果我親自做出了多個陰影,但是發現存在某些bug:每次啓動App的時候,一旦加上光源,會出現色彩完全失真現象,還沒找到原因,如有知道的大神,還望留言告知,謝謝。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章