2017年1月17日 星期二

Unity案例介紹:Trifox裡的遮擋處理和溶解著色器(一)

原文
潤稿:Kelvin Lo


本文作者是來自Glowfish Interactive的開發者Brecht Lecluyse,目前正在開發一款
靈感源自經典機台,獨特的鳥瞰視角動作冒險遊戲Trifox。玩家在Trifox中扮演一隻技藝超群的狐狸拯救被侵略的家園,今天將由Brecht Lecluyse為大家分享Trifox專案中遇到的角色與障礙物間的遮擋處理,以及溶解著色器相關的問題。


角色應該如何顯示

定義問題

在開發過程中,我們面臨的首要挑戰就是在全3D的場景中讓主角保持在頭上相機範圍內。也就是說如果有東西擋住了主角,是要選擇避開這些遮擋物還是把遮擋物隱藏起來?假如選擇隱藏的話,如何用一個視覺上可以接受的方式來讓隱藏的過程符合遊戲風格?如何保持不會妨礙遊戲體驗的空間感?

對於那些視角類似Trifox的遊戲而言,這是一個很常見的問題,所以在開始執行方案之前,我們參考了一些方案。


鳥瞰視角

第一個方案是禁止關卡中出現任何會擋住玩家與鏡頭之間的巨大障礙物。這代表大部分區域必須非常廣闊,而牆壁和障礙物要盡量保持低矮,或乾脆避免使用它們,並且鏡頭與玩家要保持一定距離盡可能接近垂直往下看。這種形式非常適合"街機",或場景中所有物體都面向同一個方向的傳統45度角RPG。然而在我們的案例中,視角與角色的距離拉遠會導致玩家與主角產生疏遠感。同時也會使場景顯得更加不自然,使玩家不容易感受我們的遊戲、沉浸感以及視覺風格。

鳥瞰視角案例:Arrow Head的Helldivers



切割及掀蓋


下一個方案是對環境進行切割,你可以把場景想像為一個多層蛋糕,依照目前鏡頭區域讓玩家只能看到某一層的內容。

例如,當主角站在建築外時可以看到建築的屋頂,而當他進入建築內時,整個屋頂以及較高樓層就會被隱藏,只顯示當下的樓層牆壁和地板。大多數情況下不顯示屋頂,這樣能避免額外的處理工作。這種方法能夠給玩家自然進出建築物的感覺,讓遊戲能有更複雜的關卡設計和更強的空間感。雖然我們依舊需要將鏡頭定位在一個合適的距離並向下看,但由於障礙物可以被隱藏或顯示,建構環境的方法可以更自由。

為了進一步優化這個方法,我們隱藏牆壁和其他物體,決定它們是否遮擋我們的視野,是否允許更低的鏡頭角度及玩家角色視野更近。

掀蓋式鏡頭範例:Firaxis Games的XCom:Enemy Unknown


這種方法唯一的缺點是會讓人感覺不太自然。雖然可以通過淡出和使用透明材質來降低這種感覺,但整體來說,我們希望盡可能不要用這些效果來避免重繪的效能問題和全螢幕的透明覆蓋。這種方法確實效果不錯,但對於我們的遊戲而言仍然不是非常理想。



自然演化


在考察了一些解決方法之後,我們仍舊感覺有些問題要解決。這些方法在大多數遊戲中都運作良好,但在這個專案上,我們總感覺似乎缺了點什麼。

我們想要達成以下目標:

  • 障礙物應該要平滑而自然的被隱藏。 
  • 關卡企劃要能控制哪些東西能夠被隱藏,於是我們就可以保留一部分能夠遮擋視野的物體,在環境中增加縱深感。 
  • 鏡頭和角色之間的距離發生變化時,系統應該運作如常。
  • 遮擋處理應該在任何角度下都能運作。
  • 障礙物被隱藏後,玩家依然能感受到它的存在。 
  • 設定工作需要盡可能簡化。


我們整合了之前所有的方法後最終得出方案,並加了額外的障礙物隱藏風格。



當玩家往遮物移動的時候,遮蔽物會逐漸變透明確保視野不被遮擋,同時清楚地表現出此處確實有物體存在。這樣封閉空間場景依然可以保持封閉的感覺,牆面逐漸淡出也不至於太顯眼。這代表我們可以讓多個相疊大小形狀不同的物件統一消失而不需要額外的設定。

如何達成這個目標?解決這個問題需要考慮如何創造一個很棒的隱藏效果,可用於各種遊戲中的各種物體上。本文將說明實現最終方案的過程,從深入研究一些常用的溶解著色器技術開始。

強大的著色器

基礎溶解著色器與世界空間UV

裁切噪點貼圖

最簡單的溶解效果可以使用2D噪點貼圖和一種名為"裁剪"的著色器技術來實現。這個功能會把裁剪值大於或等於0的部分畫到螢幕上,所有小於0的值被隱藏起來,鏡頭看到它當作一個觸發開關處理材質。

上述的噪點貼圖貼到Unity的方塊示意圖如下。





下一步是透過處理噪點貼圖來讓立方體逐漸消失。參考這個著色器和漸變貼圖的原理要達成想要的結果不難,只需取出貼圖中的灰階值,並減去一個0到1之間的值,這個值可以作為透明度百分比。

half gradient = tex2D(_MainTex, IN.uv_MainTex).r;
clip(gradient- _DissolvePercentage);



當把_DissolvePercentage變數往上加時,你會看到像這樣的效果:


就這樣完成基本的融解特效,是不是很簡單?

你可能會注意到上圖的方塊會在大概75%的透明度下完全消失,而不是100%。這並不是我們想要的從0(黑)到1(白)之間完整轉換範圍,為什麼會這樣呢?

這是因為當貼圖匯入引擎時會進行一次伽馬校正。這種情況下我們需要將貼圖當作線性資料貼圖(Linear data texture)使用,也就是說我們需要將RGBA的值當作資料而非顏色來使用。為了確保資訊不在匯入過程被改變。這可以透過調整貼圖的導入設定來實現。

在"Import Settings"介面將貼圖類型設為"Advanced"並啟用"Bypass sRGB Sampling"。下面的動畫展示了啟用該設定前後的區別。在處理一些用到貼圖資料更加複雜的著色器效果時,這個設定很重要。









這種方式對於一些可展開的網格非常適用,但如果是其它網格呢?如果有一些互相疊再一起的物件,能否做一個效果讓它們表現得像是單一物件?





除非特地在溶解貼圖上展開每一個物件,否則相鄰的物件在溶解時會出現很大的不同。而對於縮放過的物件,還需要針對每一個縮放級別各自使用不同的材質來保持噪音細節同步。很明顯這會導致很多設定工作,不太現實。

下一步:用程式化世界空間展開來替代手動展開。


世界空間UV


通常貼圖是依照網格在建立時定義的UV座標映射到網格表面的。現在我們想要替換這些UV座標,改用一個基於表面在場景中位置的坐標系。透過增加Unity內建的著色器輸入參數“worldPos”,我們就可以在著色器中存取到這個資訊。

這裡的範例你可以看到XY空間中移動的四邊形用程式調整的結果。我們使用存在worldPos的變數裡紅色和綠色通道中的x和y世界空間座標,而不是存取在網格中的UV座標。

原本的:
half gradient = tex2D(_MainTex, IN.uv_MainTex).r;

用世界空間座標代替UV座標
half gradient = tex2D(_MainTex, IN.worldPos.rg).r;



這是一個常見的著色器技術,可以用於各種有趣的程式貼圖技術。例如,可以用它自動在表面低於某個特定高度時產生浸水的效果。

再次把調整好的著色器用於立方體,這裡需要一些額外步驟才能使世界空間貼圖技術能夠正常用於淡出效果。目前這個展開程式僅支援3D平面,這裡的範例是XY平面,因為用到了x和y座標來代替UV座標。


可以透過一些向量運算出能夠作用於所有表面的UV集合,無論這些表面在空間中的位置和方向如何。最終實現一個貼圖應用於網格後,它能在不同的方向、縮放以及位置下保持連續性。


最終應用到遊戲的效果如下:




這足以應付大多數情況,但我們並未就此滿足。從上圖可以看出使用這種噪點可能會產生令人不適的邊緣溶解效果。此外,由於使用了貼圖,在接近物件的時候會觀察到明顯的圖元變化。我們同樣也無法保證噪點貼圖能夠在很大的表面角度差和互相交錯的物體之間都保持很好的連續性。






以上就是第一章的內容。第二章將闡述如何解決使用噪點貼圖產生的問題,改善溶解效果的整體品質,如何在Trifox中使用這個簡單的技術來做出像是動態鏡頭遮擋處理以及一些很酷的遊戲效果。

沒有留言:

張貼留言

關於我自己

我的相片
Unity台灣官方部落格 請上Facebook搜尋Unity Taiwan取得Unity中文的最新資訊