人物的卡通渲染:方案彙總與選擇

Marcus Xie發表於2020-05-11
人物的卡通渲染:方案彙總與選擇

都是市面上常見的,沒啥新鮮東西,是我自己的學習筆記。希望大家多多指正。

一、描邊

①視線法線夾角

計算視線與法線的夾角的餘弦值,太大了就是邊緣。可以通過閾值或者(一維)紋理取樣的方法來控制描邊寬度,但是作用有限。因為在box之類的幾何體上,視線法線夾角大小不一,同一個物體上可能寬度會變化很大,描邊寬度不好控制。

優點:簡單,就在原來的pass里加幾行程式碼就搞定,也不用渲染紋理什麼的。

缺點:描邊寬度受限於模型。可能有些模型用不了這種方法。

②後處理邊緣檢測

在後處理中,在深度緩衝(或把法線寫進一張渲染紋理)上用Sobel運算元進行邊緣檢測。但是Sobel運算元等濾波模板會大量取樣,而且不談取樣它們本身的計算量也不小。所以可以只讓需要的物體描邊,讓這些物體渲兩個pass,第二個pass進行邊緣檢測。但是這樣渲染負擔會隨場景複雜度提升而提升,這時候另一個做法是讓想描邊的幾個物體寫進stencil buffer,然後後處理的時候在通過模板測試的地方進行邊緣檢測,雖然這樣就不能每個物體單獨制定描邊顏色了。

優點:開銷固定,都是一整個螢幕。鏤空的地方也可以描邊,因為鏤空的地方雖然在mesh上是實心的,但是它們不會寫入深度緩衝。

缺點:描邊寬度仍然不好控制。而且我尋思在移動平臺上用後處理本身就很蛋疼了,就算是隻用深度緩衝(不把法線寫進一張渲染紋理),濾波模板帶來的大量取樣也會給移動裝置的頻寬造成很大的壓力。只是個人猜想

③擴大背面

渲兩個pass,後一個pass就正常地渲正面,前一個pass用黑色或別的深色渲背面,但是要在vertex shader裡把背面撐大一點(沿法線擴張),這樣邊緣上會多出來一圈黑的。或者不撐大,讓背面往前挪一點,邊緣處會穿插出來,也看來像描邊,只不過是在輪廓以內描的(撐大的方案是在輪廓以外描的)。但是往前挪的話,描邊寬度受限於三角面的角度。還可以根據遠近實時調整描邊的寬度,也就是根據z值調整頂點擴張的距離。

優點:簡單,效能友好。可以逐頂點地控制描邊寬度(頂點色裡儲存該處的擴張距離)。

缺點:對於有內凹的模型,背面面片會遮擋正面面片。

我選③。

二、著色

漫反射方案選擇:

①Tone Based Shading(漸變,類似半蘭伯特光照)

計算光線和法線的餘弦值,以前是會把負的也就是背光出的餘弦值直接截到0,但是現在還是讓它參與計算。最背光的地方(dot=-1)指定一個冷色,最向光(dot=1)的地方指定一個暖色。然後用餘弦值在兩個顏色之間差值。

人物的卡通渲染:方案彙總與選擇

優點:大概是不用取樣紋理,漫反射顏色直接是計算出來的。不取樣紋理對移動平臺的頻寬貌似就友好一點

缺點:太美式了(其實也談不上缺點,風格差異而已,只是這篇的主題是日本二次元),而且留給藝術家控制的餘地不大。

②Cel Shading(突變,純色色塊)

風格上來說就是明暗之間有一個很楞的交界線,是明暗是突變過去的。實現上最好是不要粗暴地把光線和法線的餘弦值用閾值砍一刀,那樣鋸齒比較難搞,手機又不能開抗鋸齒。要用smoothstep之類的東西抗鋸齒又會有額外的效能消耗。而且就明暗兩個階梯還好,多了怎麼辦,用一串if嗎,shader效能會爆的. 所以所以最好是用一個紋理來控制,用法線-光的餘弦值去取樣這個查詢表,這樣的話方便藝術家控制,想稍微要一點柔和的漸變的話在紋理上塗抹模糊一下就可以了,而且想要好幾個階梯的明暗變化也不成問題。

人物的卡通渲染:方案彙總與選擇

優點:很好很日本()。留給藝術家的發揮空間大。既然都用紋理了,紋理座標多出來的一個維度豈不是浪費了,還不如一個維度是光線-法線夾角,另一個維度是視線-法線夾角,來做個rim light(邊緣光),不過這樣藝術家就有點辛苦了. 我倒是在想有沒有什麼機制或者外掛能夠把藝術家畫的紋理實時體現(渲染)出來,每畫一筆就能看到效果(扯遠了

缺點:大概是又多了一張貼圖要取樣吧。這種彩色的貼圖還不能跟別人合併通道(?),移動平臺頻寬悲鳴(心痛 所以整個16×16的貼圖就可以了,大了也沒意義。

我選②(

More about 日本二次元:

既然都二次元了我們就快樂地二次元到底叭,關於這個日本二次元渲染再說幾句。漫反射這裡還可以加上次表面散射的貼圖和AO,沒什麼高大上的,無非是給藝術家和頻寬增加一點痛苦而已,不想給頻寬增加痛苦就合併顏色通道叭。

光一個漫反射肯定還不夠。還有很多與視角相關的成分,rim light剛才在②的優點裡已經提到過了。高光的話甚至可以繼續用glossness和specular的貼圖,這個意思有點類似於PBR流程裡的光澤度和金屬度貼圖(?)。當然還是可以合併通道的啦。

三、頭髮的高光

可以把頭髮在微觀層面上抽象成直徑小於一個畫素的圓柱體:

人物的卡通渲染:方案彙總與選擇

高光計算中,half-way向量與法線越接近,高光就越強。如果是普通的平面,法線方向是固定的,所以如果half-way向量和法線偏很多,高光就較弱。但是既然頭髮是圓柱體,而且這個圓柱體直徑小於一個畫素,那麼這一個畫素裡可以認為這個表面有很多個朝向,哪個朝向能更好地把光線反射到我們眼睛裡,哪個朝向的影響就越大。也就是說,可以認為這裡的法線是能夠自動適應half-way向量、自動旋轉到與光線和視線共面。

接下來我們來看看這個高光項具體怎麼計算。這裡的法線是旋轉的,不是固定值,所以就不能像傳統的Blinn模型那樣拿法線和half-way向量做點積。但是可以觀察到,切線、half-way向量、法線在此時是共面的,且切線和法線成直角,所以想要求法線和half-way向量的點積(餘弦值),直接求切線和法線的正弦值就可以了,切線是已知的是固定的。

從巨集觀上來看,這樣計算會讓高光沿著髮絲的垂直方向伸展。

但是這還不夠。實際的頭髮高光在髮絲的方向是有鋸齒狀的擾動的。這是因為不同的頭髮與頭髮之間的切線方向是不同的,髮絲的走向方向不一樣,有點往頭裡鑽,有的往頭外邊冒,他們不是一路都肩並肩順順地長下來的,這樣高光就看起來“上下顫動”:

人物的卡通渲染:方案彙總與選擇

為了顫動。讓切線往法線(指mesh的法線)方向偏移就可以了,可以用一張噪聲控制偏移的方向和程度:

人物的卡通渲染:方案彙總與選擇

仔細觀察會發現,上上圖裡有兩條光帶,一條強烈的白色的高光,和一條較弱的有顏色的高光(此處暫且稱為“次高光”)。次高光的特點是帶顏色,而且更向髮根偏移,強度較弱。那麼我們計算兩個不同的高光然後疊加,其中次高光用前一段提到的方法偏移,只不過加一個向髮根偏移的基礎偏移量罷了。

至於怎麼把這種方法轉換成日本二次元的,二次元的特點是明暗是突變的。那麼還是用梯度漫反射的老方法(Cel Shading)來處理高光,用高光項取樣一個Ramp貼圖即可。

四、邊緣光

也就是前面講到的rim light。Cel shading的Ramp貼圖裡,紋理座標多出來的一個維度豈不是浪費了,還不如一個維度是光線-法線夾角,另一個維度是視線-法線夾角,來做個rim light(邊緣光)。

五、杜絕臉上的硬光照

看日本二次元的人物畫比較多的盆友會注意到,臉部的光一般都顯得比較“平”,也就是和美國西部漫畫的硬漢的陰陽臉形象相差較大:

人物的卡通渲染:方案彙總與選擇

其實就是說光源的方向不能是垂直於視線方向的,不然就會把明暗部之間的強烈對比呈現出來,那樣不日本。一個解決辦法是專門為臉部補一個光,光源是從觀察者這邊射出去的。

造成陰陽臉的除了臉的表面和光的朝向,還有各種陰影。我們常說紙片人,但是臉的實際模型肯定不可能是一個片,有幾何的起伏勢必會造成陰影。所以可以加一個陰影mask,由美術來指定哪裡可以接受陰影,哪裡不可以。

還有一個是,我們形容某個人好看的時候,會說他好像在發光。其實他可能真的在發光,這也就是自發光,或說emission,數學上只是簡單地把畫好的albedo色加上明暗,而不是乘上明暗(可能這個描述不太準確)。也就是說就算是在暗處也能保持一定的明度,不會有死黑。

杜絕陰陽臉,除了不能有特別暗的地方(背面暗部、陰影),還不能有特別亮的地方(邊緣光、高光)。

上一節講到邊緣光,邊緣光在下眼瞼/顴骨上方等臉上的地方最好就是不要出現了。這個同樣可以加一個mask控制。

高光也是一樣,臉上就免了,況且顯得油多

總結一下:

不要太暗:①面部補光;②陰影mask; ③自發光。

不要太亮:①邊緣光mask;②不要高光。

六、參考

都是各位大佬智慧的結晶:

3D日式卡通人物渲染的經驗分享
https://gameinstitute.qq.com/community/detail/100050
卡通渲染及其相關技術
https://zhuanlan.zhihu.com/p/26409746
簡易二次元角色渲染風格(一)
http://walkingfat.com/

作者:Marcus Xie
專欄地址:https://zhuanlan.zhihu.com/p/132388004

相關文章