Esfog_UnityShader教程_遮擋描邊(原理篇)

林堯彬發表於2020-04-04

  咳咳,有段時間沒有更新了,最近有點懶!把不少精力都放在C++身上了。閒言少敘,今天要講的可和之前的幾篇有所不同了,這次是一個次綜合應用.這篇內容中與之前不同主要體現在下面幾點上.

  1.之前我們寫的都是隻用一個Shader來實現某些效果,而這次我們要使用多個Shader結合起來發揮作用。

  2.之前我們只是寫的都是純Shader程式碼,沒有涉及到客戶端的C#指令碼(你愛用JS也可).而這次也要使用到。

  3.這篇教程涉及到的程式碼量也是之前是之前的幾倍了.

  4.總的來說之前的都是比較簡單的,而這篇就有了些難度了。

  不過不要怕,我們先講解實現的原理,因為這個教程內容比較多,所以只能抽出一篇來單獨講原理了,建議看這篇教程的同學,最好能有基本的UnityShader基礎,不妨去看看我的前幾篇教程,在後面講解程式碼中我不會事無鉅細的都講到,直跳比較重點的地方進行說明。

  好了進入正題,什麼是遮擋描邊呢?直接上圖吧。

    

  如上圖, 在很多遊戲中,特別是3D遊戲中,當我們的角色被一些牆體或者其它物體擋著的時候,為了讓玩家清楚的看到角色當前身處的位置,就需要把角色被遮擋部分的外輪廓描出來(上圖中的綠色邊框)。這就是我們要實現的"遮擋描邊"。大家可以聯想一下自己玩過的遊戲看看有沒有這種情況。


重要概念


   在講解具體原理之前,我們要先了解幾個比較重要的概念:

  1.後期處理:有點類似於影音方面後期處理的意思,在這裡指的就是,當攝像機把當前幀渲染完畢之後,我們不是直接把影像對映到螢幕上,而是利用我們的程式碼來對原影像進行處理,把處理後的顯示在螢幕上。遊戲中非常多的效果都通過後期處理實現的,比如Bloom效果,運動模糊效果等等。我們這篇說的"遮擋描邊"也算作是後期處理。

  2.深度緩衝:對於一款3D遊戲,要將三維世界裡攝像機看到的部分展示到二維的螢幕上,除了要展示物體本身的顏色,還要處理物體的前後關係。而在我們的視訊記憶體裡有兩個緩衝區(和具體顯示卡架構有關,這裡只是舉個例子)來分別用來儲存遊戲的畫面和物體的前後關係。我們把它們分別稱作顏色緩衝區和深度緩衝區。顏色緩衝區你可以理解為他是一個二維陣列,裡面的一個元素對應著螢幕的一個畫素點的顏色(還會附帶一些其他資訊)。深度緩衝區也可以理解為一個二維陣列,裡面存放著螢幕畫素上每一個點所對應場景中物體上的點距離相機的距離。在渲染流程中深度緩衝非常重要的,如果沒有它,也就沒有了物體間的前後關係,我們在螢幕上看到的可能是雜亂的影像了。

  3.深度圖:深度圖適合深度緩衝相關聯的一個概念,深度緩衝是由作業系統通過顯示卡API來控制的,而我們使用引擎的時候也只能通過引擎提供的有限的API來讀寫利用深度緩衝來實現一些效果。那當我們需要利用深度緩衝來做一些特殊效果的時候就要抓狂了,別急我們可以通過制定一個相機,讓它把渲染的影像不是顯示到螢幕上,而是顯示到一張我們設定好的二維圖片上,我們在通過我們寫的Shader來讓它把這個相機所拍攝到物體的深度資訊儲存到這個二維圖片(它現在就是深度圖了)上,而不是顏色資訊。這樣在接下來的處理用我們就可以利用這個深度圖來做一下事情了。


原理


   有了上面的一些概念我們就來了解一下實現的原理(當然了,實現遮擋描邊的方法很多,而每一款遊戲需要的效果也不盡相同,這裡的方法僅供參考):

  大體上可以分四個大步驟:(下面的兩張圖片,在遊戲中玩家是看不到的,開發人員也是看不到的,全部都是在程式碼中處理的,這裡顯示出來只是為了讓大家能更好的理解一下)

  1.獲得一共只包含我們要進行遮擋描邊處理的物體(在我們的例子中,就是上圖的那個士兵)深度資訊的深度圖。對於我們的例子,這一步的結果如下圖,粗看起來是一片紅,但是大家細看右邊你會看到那個士兵的.至於為什麼影像這麼偏紅,大家可以想想,我在下篇中會說明。

  

  2.通過比較判斷主攝像機(就是你在Game視窗看到的影像所用到的攝像機)的深度資訊和我們第一步中獲得到的深度圖資訊,來界定出我們要處理的物體的哪些部分被擋住了。並對被遮擋全部塗上描邊顏色。如下圖

  

  3.把被遮擋部分分別進行一次左右,上下方向的拉伸一畫素.這個就不用圖了基本和上面的圖一樣,只是上下左右都多了一個畫素,所以看起來不明顯。

  4.最後把除了我們在第三步中額外繪製的一畫素外輪廓以外,對角色的被遮擋部分還使用原來的顏色(就是牆本身的顏色)。效果就是本文一開始放的那個圖片了。


涉及到的一些API


  這樣我們就實現了遮擋描邊,不過上面只是比較籠統的概括,有很多細節需要注意。具體的程式碼實現我會在下次的教程中進行具體講解,這裡我先把需要設計到的一些Unity知識列出來,很多內容都可以通過Unity的官方API文件查到,大家可以自己先了解一下然後試著實現一下遮擋描邊。這樣看下一次教程的時候會效果更好:

  1.在Unity進行後處理需要涉及到的一些API,有 OnRenderImage(...),RenderTexture.GetTemporary,RenderTexture.ReleaseTemporary,Graphics.Blit,RenderWithShader.

  2.在C#指令碼中對Shader進行傳值設計到的一些API,如Shader.SetGlobalXXX(),Shader.Find,Material.SetXXX().

  3.相機的深度模式,和Unity提供給我們的一個預設深度圖.Camera.depthTextureMode,_CameraDepthTexture等.

 

  好了關於遮擋描邊的原理篇基本就講完了,怎麼樣是不是和之前幾篇的內容有很多不同,這篇內容也只是做了一個拋磚引玉,只是希望大家能瞭解一下渲染中的幾個重要概念,然後自己去做一些擴充套件,比如說深度緩衝和深度圖,他們兩個能夠實現的效果遠遠不只是"遮擋描邊"。更多神奇的功能還等待大家自己一起去探索。另外我會在近期完成"實現篇"的,這段時間大家不妨自己動手試著寫寫看,沒準在我發下一篇之前,聰明的你啊已經搞定了呢!!!

 

  尊重他人智慧成果,歡迎轉載,請註明作者esfog,原文地址 http://www.cnblogs.com/Esfog/p/CoverOutline_Shader.html

 

轉載於:https://www.cnblogs.com/Esfog/p/CoverOutline_Shader.html

相關文章