Shader學(xué)習(xí):初步了解卡通渲染Cel Shading

卡通渲染(英文Cel Shading或者Toon shading),是一種能夠使3D的圖像產(chǎn)生動漫效果的渲染手段。它具體的定義我們先看一段來自維基的解釋:

Cel shading or toon shading is a type of non-photorealistic rendering designed to make 3-D computer graphics appear to be flat by using less shading color instead of a shade gradient or tints and shades. Cel-shading is often used to mimic the style of a comic bookor cartoon and/or give it a characteristic paper-like texture.

(卡通渲染(英語:Cel-shading或者Toon Shading)是一種去真實感的渲染方法,旨在使電腦生成的圖像呈現(xiàn)出手繪般的效果检柬。為了使圖像可以與漫畫或者卡通達(dá)到形似的效果,專業(yè)人員通常使用卡通渲染著色器進(jìn)行處理)

總結(jié)來說,卡通渲染是一種NPR(非真實感繪制)任柜,可以使用在一些3D的日系二次元風(fēng)格的手游或者端游中,使得畫面的質(zhì)感更加接近動漫中的感覺沛厨。

比較的有名的使用卡通渲染的游戲宙地,這里我必須提一下崩壞三(崩壞學(xué)園3)。每次看到崩崩崩的視頻逆皮,總是會被它的畫風(fēng)給驚嘆到宅粥。米忽悠真不愧是被游戲耽誤的動畫公司。崩壞三大量使用了卡通渲染技術(shù)电谣,這一點在米哈游的技術(shù)總監(jiān)賀甲對于崩壞3的技術(shù)演講中可以了解到秽梅。B站有關(guān)于這個演講的視頻(不過是日語的,因為是在Unite Tokyo 2018上的演講剿牺,貌似被官方翻譯了)风纠。文字版本的可以百度

這種風(fēng)格對于喜歡動漫的人來說簡直是完美牢贸,恨不得把自己的所有游戲都加上一個卡通渲染竹观。那么,卡通渲染具體是怎么實現(xiàn)的呢?原理又是什么臭增?

簡單來說懂酱,在正常的渲染著色過程中,由于使用了真實的光照模型誊抛,在模型上的顏色是隨著光照的角度漸變的列牺,而卡通渲染為了模擬動畫繪制時候的風(fēng)格,根據(jù)每個像素的法線和光照的方向的關(guān)系拗窃,來使得這片區(qū)域的像素投影到其中一個明暗區(qū)域上面瞎领,達(dá)到多段離散的明暗區(qū)域的效果。

接下來我們將分別在Unreal Engine 4(UE4)中和WebGL中來實現(xiàn)簡單的Cel Shading随夸,可以選擇自己感興趣的閱讀九默,其中WebGL涉及shader代碼。

Unreal Engine 4

在UE4當(dāng)中宾毒,我們甚至不需要寫shader的代碼驼修,只需要通過材質(zhì)的藍(lán)圖編輯器就能夠?qū)崿F(xiàn)卡通渲染的效果。首先先新建一個Material诈铛。然后在Material Domain中選擇PostProcessing,這樣這個材質(zhì)就會被作為后處理的材質(zhì)乙各,能夠作用在計算了光照和顏色的模型上面。


選擇Material domain

接下來就是在藍(lán)圖中實現(xiàn)卡通渲染的細(xì)節(jié)了幢竹。在UE4中耳峦,我們無法直接獲得光照的信息,這里需要使用一些手段來獲得光照LightMap焕毫。

UE4中可以通過SceneTexture來獲得一些有用的信息蹲坷,在SceneTextureID中可以選擇其類型


這里我們需要一個PostProcessingInput0來獲得場景中應(yīng)用了光照和后處理之后的顏色,再添加一個SceneTexture節(jié)點并且選擇DiffuseColor來獲得場景中初始(無光照和后處理)的顏色咬荷,用一個divide節(jié)點來從PostProcessingInput0中除去DiffuseColor獲取LIghtMap的灰階值冠句。

當(dāng)然,可以先先將兩個輸出連接DeSaturation的節(jié)點來更徹底地將顏色去除幸乒。

我們將獲得的結(jié)果映射到0-1的范圍內(nèi)

通過這個結(jié)果懦底,我們可以大概地了解到對于每個像素點的光照信息。這樣我們就可以根據(jù)光照信息來計算最后的顏色值罕扎。

這里我采用了最簡單的方法聚唐,只有兩種明暗差別,如果之前獲得結(jié)果大于0.5腔召,則最后的顏色信息直接為DIffuseColor杆查,否則要將DiffuseColor乘一個系數(shù)。最后的整個藍(lán)圖如下圖顯示

當(dāng)然你可以將結(jié)果更加細(xì)分(WebGL的部分中就更加細(xì)分)臀蛛,這樣結(jié)果就會有更多段的明亮度亲桦。之后在場景中添加一個PostProcessingVolume并且把整個后處理材質(zhì)添加到PostProcessingVolume中就可以作用到場景上崖蜜。

設(shè)置PostProcessingVolume中的Infinite Extend為Infinite,整個場景就會被PostProcessingVolume給覆蓋客峭,添加的后處理材質(zhì)就能夠作用到整個場景上

這里你可能會發(fā)現(xiàn)結(jié)果有點和想象中的不一樣豫领。記住,在卡通渲染的藍(lán)圖選項中把Blendable location選為Before tonemapping

關(guān)于Blendable location的解釋舔琅,我們可以在官網(wǎng)中看到這個介紹

簡單來說等恐,Before tonemapping能夠作為在HDR的顏色上,而After tonemapping只剩下LDR的顏色备蚓,會失去很多細(xì)節(jié)课蔬。至于Translucency(透明度)相關(guān)的選項,Before translucency作用在Before tonemapping之前郊尝。

假如你想要把卡通渲染只作用在一些模型上而不是整個場景二跋。這時就要使用custom depth buffer了。把需要使用卡通渲染的模型中的render custom depth pass勾選上

然后修改剛才的藍(lán)圖為如下


可以看到虚循,我們主要添加了對于depth buffer的判斷同欠,根據(jù)custom depth buffer和scene depth的關(guān)系來進(jìn)行最后明亮度的取舍样傍。

到目前為止横缔,我們都是將顏色乘一個自定義的系數(shù)來表明明亮度。更好的方法是使用一個材質(zhì)查詢表(Texture LUT<look-up table>)衫哥。

這樣就能夠使用計算出來的值通過查表來乘相應(yīng)的系數(shù)茎刚。

到此,超簡單版本的卡通渲染就完成了撤逢,結(jié)果大概是這個樣子膛锭。當(dāng)然如果你是把它作用在整個場景上的話,可能會丟失光照蚊荣。場景的背景就是黑色的初狰,下圖是只用在了人物的模型上,就很動畫互例。

參考資料:

  1. Anime-Look Cel Shading in UE4(貌似是一個日本學(xué)生寫的奢入,模型就是用他推薦的,強推)
  2. Unreal Engine 4 Cel Shading Tutorial(這個人的很多Unreal教程都不錯)

WebGL

Webgl上面的實現(xiàn)就很算法了媳叨,沒用什么好的模型腥光,webgl的一個好處在于不需要像opengl什么的要去配置一下環(huán)境,只要一個支持webgl的瀏覽器就能跑了糊秆。而且這個教程還給了一個在線的編輯器(cyos)武福,直接在上面能夠像在IDE里面一樣寫shader的代碼,能直接運行展示結(jié)果痘番,并且把結(jié)果下載下來捉片,對于新手特別友好平痰。

流程和UE4中的基本沒什么兩樣,只是用代碼實現(xiàn)了伍纫。下面直接上shader代碼:

Vertex shader(頂點著色器)

precision highp float;

// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

// Uniforms
uniform mat4 world;
uniform mat4 worldViewProjection;

// Varying
varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUV;

void main(void) {
    gl_Position = worldViewProjection * vec4(position, 1.0);

    vUV = uv;
    vPos = vec3(world * vec4(position, 1.0));
    vNormal = normalize(vec3(world * vec4(normal, 1.0)));
}

在vertex shader中觉增,我們把UV,世界坐標(biāo)系下的頂點坐標(biāo)和正規(guī)化后的法線計算出來傳給pixel shader翻斟,以便后面的光照計算逾礁。

Pixel (fragment)shader(片元著色器)

precision highp float;

// Lights
varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUV;

// Refs
uniform sampler2D textureSampler;

void main(void) {
float celShadingThreshold[4];
    celShadingThreshold[0] = 0.02;
    celShadingThreshold[1] = 0.1;
    celShadingThreshold[2] = 0.6;
    celShadingThreshold[3] = 0.9;
    float celShadingVal[5];
    celShadingVal[0] = 0.1;
    celShadingVal[1] = 0.5;
    celShadingVal[2] = 0.87;
    celShadingVal[3] = 0.95;
    celShadingVal[4] = 1.0;

    vec3 lightPos = vec3(0, 5, 20);
    vec3 lightDir = normalize(lightPos - vPos);

    float angle = dot(lightDir, vNormal);
    vec3 color = texture(textureSampler, vUV).rgb;
    if (angle < celShadingThreshold[0])
    {
        color = color * celShadingVal[0];
    }
    else if (angle < celShadingThreshold[1])
    {
        color = color * celShadingVal[1];
    }
    else if (angle < celShadingThreshold[2])
    {
    color = color * celShadingVal[2];
    }
    else if (angle < celShadingThreshold[3])
    {
        color = color * celShadingVal[3];
    }
    else
    {
        color = color * celShadingVal[4];
    }
    gl_FragColor = vec4(color, 1.0);
}

片元著色器中,通過計算法線和光線的點積(光源的點是自定義的)访惜,我們得到一個浮點數(shù)結(jié)果嘹履,使用這個結(jié)果去查詢一個系數(shù)表,我們可以知道最后顯示的顏色是材質(zhì)貼圖中采樣得到的顏色乘一個多大的系數(shù)债热。這樣通過頂點的法線和光線的夾角的不同砾嫉,就能使得其明亮度落入不同的區(qū)域,造成手繪的質(zhì)感窒篱。

結(jié)果大概是這個樣子

結(jié)論

以上焕刮,我們已經(jīng)完成了初步的簡單卡通渲染,當(dāng)然想要達(dá)到崩崩崩的那種效果還任重而道遠(yuǎn)墙杯,除了要模型上面的配合外配并,至少還要加一個描邊。描邊又是一個大話題高镐,我現(xiàn)在也還在學(xué)習(xí)怎么給模型描邊(sobel溉旋,laplacian算子)。所以嫉髓,待續(xù)中观腊。

(以上首發(fā)于知乎)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市算行,隨后出現(xiàn)的幾起案子梧油,更是在濱河造成了極大的恐慌,老刑警劉巖州邢,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件儡陨,死亡現(xiàn)場離奇詭異,居然都是意外死亡偷霉,警方通過查閱死者的電腦和手機迄委,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來类少,“玉大人叙身,你說我怎么就攤上這事×蚰” “怎么了信轿?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵晃痴,是天一觀的道長。 經(jīng)常有香客問我财忽,道長倘核,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任即彪,我火速辦了婚禮紧唱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘隶校。我一直安慰自己漏益,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布深胳。 她就那樣靜靜地躺著绰疤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舞终。 梳的紋絲不亂的頭發(fā)上轻庆,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音敛劝,去河邊找鬼余爆。 笑死,一個胖子當(dāng)著我的面吹牛攘蔽,可吹牛的內(nèi)容都是我干的龙屉。 我是一名探鬼主播呐粘,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼满俗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了作岖?” 一聲冷哼從身側(cè)響起唆垃,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痘儡,沒想到半個月后辕万,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡沉删,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年渐尿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾瑰。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡砖茸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出殴穴,到底是詐尸還是另有隱情凉夯,我是刑警寧澤货葬,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站劲够,受9級特大地震影響震桶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜征绎,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一蹲姐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧人柿,春花似錦淤堵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隘截,卻和暖如春扎阶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背婶芭。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工东臀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人犀农。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓惰赋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呵哨。 傳聞我的和親對象是個殘疾皇子赁濒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容