自己动手制作Unity 5卡通风格Shader

发表于2015-07-14
评论0 4.6k浏览
Cel Shading是用于模拟卡通及动漫中光照的渲染技术。在传统的diffuse shading中,光照会根据物体的法线在其表面创建渐变;Cel Shading让渐变两极分化,像素只有亮或不亮,不需任何插值。

 

从上图中可以看到diffuse lighting和cel shading的区别。光的方向与表面法线的点积(称之为“NdotL”)决定了像素所接收的光量。将该值四舍五入得到0或1,或者定义不同的“灰度”或“阈值”就会呈现不同的cel shading风格。

在游戏中有很多实现cel shading的方法,其中一些效果非常棒(视频稍后奉上),本文介绍一种在unity5中快速实现cel shading光照模型的方法。

根据使用的渲染管线(rendering path)不同有几种实现方式。可以在Camera组件或Player Settings中设置想要的Rendering Path。

Forward Rendering
使用Forward Rendering,引擎会遍历场景中的各顶点,各像素和各光照。当场景中有多个光源时其渲染复杂度会非常高,但如果光源不多它就是一个轻量的渲染管线。
使用Forward Rendering实现Cel Shading最好的办法就是自定义一个光照模型表面着色器
[Applenoxss] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
Shader "Custom/CelShadingForward" {
        Properties {
                _Color("Color", Color) = (1, 1, 1, 1)
                _MainTex("Albedo (RGB)", 2D) = "white" {}
        }
        SubShader {
                Tags {
                        "RenderType" = "Opaque"
                }
                LOD 200
 
                CGPROGRAM#pragma surface surf CelShadingForward#pragma target 3.0
 
                half4 LightingCelShadingForward(SurfaceOutput s, half3 lightDir, half atten) {
                        half NdotL = dot(s.Normal, lightDir);
                        if (NdotL <= 0.0) NdotL = 0;
                        else NdotL = 1;
                        half4 c;
                        c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
                        c.a = s.Alpha;
                        return c;
                }
 
                sampler2D _MainTex;
                fixed4 _Color;
 
                struct Input {
                        float2 uv_MainTex;
                };
 
                void surf(Input IN, inout SurfaceOutput o) {
                        // Albedo comes from a texture tinted by color
                        fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
                        o.Albedo = c.rgb;
                        o.Alpha = c.a;
                }
                ENDCG
        }
        FallBack "Diffuse"
}
 


“LightingCelShadingForward”函数计算NdotL并极化为0或1。然后使用该值来决定像素所接收的光量,从而得到cel shading效果。
极化“操作还有 更好的办法,但为了方便起见我们使用下面的语句来代替”if else“:
[Applenoxss] 纯文本查看 复制代码
1
 
NdotL = 1 + clamp(floor(NdotL), -1, 0);
 

或者如果你希望边缘更柔和可以使用:
[Applenoxss] 纯文本查看 复制代码
1
 
NdotL = smoothstep(0, 0.025f, NdotL);
 

 
同样的做法还可用于其它使用高光、法线映射、边缘光照等的自定义着色器。

Light Pre-Pass (Legacy Deferred)

使用Legacy Deferred,引擎只遍历场景中的光照一次然后将其存入缓冲区。Light Pre-Pass只保存光照信息,然而Unity 5中新的Deferred保存场景中所有的几何体信息。当场景中有大量光源时该方法会非常高效,但它对硬件需求更高。
使用Light Pre-Pass时不能用自定义光照来更改光照信息,因为光照信息已经在Deferred LightingPass中进行计算了。我们要做的是更改内部的延迟光通道。首先需要从官网下载Unity的内置着色器
打开文件并在“DefaultResourcesExtra”文件夹下找到"Internal-PrePassLighting.shader”。拷贝该文件到Unity工程,放在Resources文件夹下(没有就创建一个)。在unity5中可以更改文件名:

 
打开文件找到以下行:
[Applenoxss] 纯文本查看 复制代码
1
 
half diff = max (0, dot (lightDir, normal));
 

将其改为:
[Applenoxss] 纯文本查看 复制代码
1
2
3
 
half diff = max (0, dot (lightDir, normal));
if (diff > 0.0f) diff = 1.0f;
else diff = 0.0f;
 


保存文件。现在要让Unity使用该文件代替默认的Pre-Pass Lightingpipeline。
依次点击菜单项Edit -> ProjectSettings -> Graphics,将Legacy Deferred从默认的Built-in shader改为刚刚编辑的文件。如果你用的是Unity4,Unity应该已经识别该文件(如果文件名没变)可以直接使用。确保Camera的rendering path为Use PlayerSettings或Legacy Deferred (Light Pre-Pass),并且材质使用的是Legacy shader。如果所有设置都正确就可以看到cel shading的效果。

 

Deferred Rendering
但如果不能好好利用Unity5的新特性及其强大的标准着色器那使用Unity5的意义何在呢?
解决方法是使用Unity新的延迟渲染管线,其中保存场景的所有几何信息结合缓冲区中的光照信息计算出最终物体的阴影。
与Light Pre-Pass的步骤相同,下载内置着色器然后将“Internal-DeferredShading.shader”拷贝到工程。打开该文件找到‘CalculateLight’函数的如下行:
添加以下代码:
[Applenoxss] 纯文本查看 复制代码
1
2
 
if (light.ndotl <= 0.0) light.ndotl = 0;
else light.ndotl = 1;
 

像上次一样,依次点击菜单项Edit -> ProjectSettings -> Graphics,将Deferred 改为刚刚编辑的文件。确保Camera组件的Rendering Path设置为Deferred,并且材质使用的是Standard shader。现在就可以发现模型使用了新的标准着色器而且也应用了Cel Shading。

 

卡通描边及其它效果
现在已经有了Unity5中的Cel Shading了,但还没有达到最终的效果。我们需要进行描边。
依次点击菜单项Assets ->Import Package -> Effects导入 CameraImage Effects。
现在选中Camera并添加Edge Detection组件。根据自己的喜好来配置Mode(我通常会选择Robert Cross Depth Normals)。现在可以加入一些图像效果如Anti Aliasing使线条更柔和,或一些高级效果如Ambient Occlusion、Bloom或Depth of Field等来实现我们想要的效果。
 

结论
正如你所见,只需花一点点时间“黑进”Unity的Deferred管线就可以完全改变游戏的画面风格。
在Twin Souls: The Pathof Shadows(我正制作的游戏)中使用上述方法及一些其它操作就可以实现如下效果:

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引