1. 程式人生 > >Unity Shader 卡通渲染 基於退化四邊形的實時描邊

Unity Shader 卡通渲染 基於退化四邊形的實時描邊

一、邊緣檢測演算法

3D模型描邊有兩種方式,一種是基於影象,即在所有3D模型渲染完成一張圖片後,對這張圖片進行邊緣檢測,最後得出描邊效果。一種是基於空間,即針對3D模型的三角面三個頂點構成的線條做邊緣檢測(注:和基於影象的邊緣檢測的檢測方式是不同的,但都叫邊緣檢測)。在本文中使用的是基於空間的3D模型的描邊。

空間的3D模型的描邊的邊是有型別的,大致總結有4種:輪廓邊、邊界邊、折縫邊、材質邊。其中前3種是本文認為卡通渲染所必須有的。

圖1 空間中的邊分類 來自文獻[1]

輪廓邊的檢測根據定義就是,1條邊的2個鄰接面的法線分別和視線方向的點乘結果再相乘,結果小於0就是輪廓邊。數學上表達就是:(N1·V)*(N2·V) < 0,N1和N2是2個鄰接面的法向量,V是視線方向。

邊界邊的檢測比較簡單,如果1條邊只有1個面鄰接,那麼這條邊就是邊界邊。

折縫邊的檢測需要使用1個角度引數α,1條邊的2個鄰接面的夾角和這個引數做大小比較。一般在0~180度,但本文選擇在0~90度,並規定小於引數α的就是折縫邊。

總結:要在3D模型上實現這3類邊的繪製,只需要知道構成1條邊的2個鄰接面即可完成3類邊的檢測。在學術上有人把這2個鄰接面當做1個點輸入到著色器中,並作為1條邊作為輸出,並稱這2個鄰接面為退化四邊形。

圖2 退化四邊形

 

二、具體實現

本文使用目前最主流的Uinty3D遊戲引擎實現,由於這是脫離正常真實感渲染的演算法,因此如果不能自定義這部分渲染流程,那麼實現起來就無比困難,幸運Unity3D支援自定義渲染流程,其中使用到的關鍵類為CommandBuffer、ComputeBuffer。

由於不同的圖形引擎,對圖形介面的高階用法支援程度並不一致,例如Unity3D的幾何著色器就沒辦法獲取鄰接三角形。因此預處理是有必要的。

實現步驟:

步驟1:預處理階段,在這個階段找出模型所有的邊,以及邊所對應的2個鄰接面(預設所有邊都是由2個鄰接面相交構成,不規範的請自行處理)。

步驟2:把預處理階段的資料儲存下來,Uinty3D提供了很好介面ScriptableObject 。(注:預設儲存退化四邊形4個頂點的索引,如果儲存的不是頂點索引,請自行處理)

步驟3:通過CommandBuffer、ComputeBuffer把預處理據保輸入到顯示卡(GPU)中進行檢測和繪製。

 

shader中邊緣檢測步驟:

步驟1:通過退化四邊形4個頂點資料,計算出2個鄰接面的法向量。如果頂點數不足4個則表明該邊只有1個鄰接面,因此它是邊界邊。

步驟2:計算出2個鄰接面的法向量和視線方向的點乘結果dot(N1, V) * dot(N2, V),如果結果為負則是輪廓邊。

步驟3:pow(dot(N1, N2) / cos(α), 2)在[0, PI/2]上單調遞增, 可避免開方的特點,完成和dot(N1, N1) * dot(N2, N2)比較,如果小於則為折縫邊。

 

三、實驗結果

由於Uinty3D的幀數實在看不太懂,運算量低的時候幀數基本保持在90幀左右,運算量高一點點的時候就跑到120幀,估計是內部做了優化,因此執行結果僅供參考,並不準確,執行環境I5-4210M,GTX765M。

 

四、總結

這個描邊演算法在很早就被提出,這種基於空間的描邊極大程度的得到模型豐富的描邊細節,可惜在市面上貌似並不為人所知。某崩公司貌似是使用了這種演算法,結合其他卡通渲染演算法,畫面效果驚人,把同行遠遠甩在後面。因此如果想讓自己的作品更有競爭力,開發人員應該靜下心來學習一下這些教科書上沒有的論文想法。本文的後續工作是控制線條的大小,理論上應該是可以在裁剪空間實現近粗遠細的線條演算法,但由於剛剛踏足這一塊,還有很多其他工需要去研究,本文到此結束,謝謝。

 

附:原始碼

 

參考文獻:

[1]基於著色器技術實時卡通渲染的的研究

[2]基於GPU實時非真實感渲染的研究與實現

[3]3D日式卡通人物渲染的經驗分享

[4]Unity網格程式設計篇(二) 非常詳細的Mesh程式設計入門文章

[5]Unity Shader入門精要

[6]Geometry Shader Input: GL_TRIANGLES_ADJACENCY

[7]Adjacency information in geometry shaders

[8]Direct X 12 – Geometry Shader 幾何著色器

[9]OpenGL 圖元處理

 

從csdn轉移過來,順便把寫過的文章改寫一下轉過來。原文在這,比較凌亂,不再建議閱