【Unity】Unity自带卡通shader(toon shader)分析(一)

  • Post author:
  • Post category:其他


Unity Standard Assets中自带4个卡通相关的shader,可以通过导入Effects Package导入:


这里写图片描述

然后我们可以在Assets->Standard Assets/Effects/ToonShading/Shaders中找到这四个shader


这里写图片描述

首先来看一下ToonBasic这个shader,我从asset store上下载了一个名叫Tiger的免费模型,下面就用这个模型来做实验。下图是刚放进场景的prefab:

这里写图片描述

然后我们使用ToonBasic替换Tiger身上的原材质,效果如下:

这里写图片描述

可以发现,ToonBasic并没有描边,但是模型的色彩产生了明显的变化,色块之间的边界更为明显了。

ToonBasic的代码如下所示:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Toon/Basic" {
    Properties {
        _Color ("Main Color", Color) = (.5,.5,.5,1)
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _ToonShade ("ToonShader Cubemap(RGB)", CUBE) = "" { }
    }


    SubShader {
        Tags { "RenderType"="Opaque" }
        Pass {
            Name "BASE"
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            samplerCUBE _ToonShade;
            float4 _MainTex_ST;
            float4 _Color;

            struct appdata {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f {
                float4 pos : SV_POSITION;
                float2 texcoord : TEXCOORD0;
                float3 cubenormal : TEXCOORD1;
                UNITY_FOG_COORDS(2)
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos (v.vertex);
                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.cubenormal = mul (UNITY_MATRIX_MV, float4(v.normal,0));
                UNITY_TRANSFER_FOG(o,o.pos);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = _Color * tex2D(_MainTex, i.texcoord);
                fixed4 cube = texCUBE(_ToonShade, i.cubenormal);
                fixed4 c = fixed4(2.0f * cube.rgb * col.rgb, col.a);
                UNITY_APPLY_FOG(i.fogCoord, c);
                return c;
            }
            ENDCG           
        }
    } 

    Fallback "VertexLit"
}

在这里先忽略雾效相关代码,我们发现,该材质需要两个贴图,一张老虎原来的贴图和一张控制色彩变化的cubemap贴图,分别对应


_MainTex ("Base (RGB)", 2D) = "white" {}

_ToonShade ("ToonShader Cubemap(RGB)", CUBE) = "" { }



这里写图片描述

然后让我们来看一下顶点函数:

v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos (v.vertex);                   -- 将顶点从模型空间转化到裁剪空间
                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);          -- 获取贴图uv
                o.cubenormal = mul (UNITY_MATRIX_MV, float4(v.normal,0));  -- 获取控制toon的cubemap的法线
                UNITY_TRANSFER_FOG(o,o.pos);
                return o;
            }

然后是片元函数:

fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = _Color * tex2D(_MainTex, i.texcoord);       -- 获取2D贴图上对应uv处的颜色
                fixed4 cube = texCUBE(_ToonShade, i.cubenormal);         -- 获取cubemap上对应的颜色(控制颜色块)
                fixed4 c = fixed4(2.0f * cube.rgb * col.rgb, col.a);     -- 用2倍的toon控制色乘上源颜色
                UNITY_APPLY_FOG(i.fogCoord, c);
                return c;
            }

可以得出结论,ToonBasic的原理其实就是用一个cubemap来控制色彩边界的变化,使色彩块之间有明显的界限。



版权声明:本文为RICKShaozhiheng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。