1. 程式人生 > >Unity自帶Shader(一)(卡通著色)

Unity自帶Shader(一)(卡通著色)

前言:最近有必要系統的學習下shader了,雖然平時也用著,原理什麼的都懂,而且覺得應用層的shader特別簡單,真的難的是隱藏在shader後面的演算法,這裡準備了一個系列,這個系列是對unity 標準庫shader的學習,從而對shader有更深的認識,同時也希望能認識更多搞圖形學的朋友一起交流。

遊戲shader中最常見的Toon shader(卡通shader)

. Toon 效果圖 四種不同的效果,分為帶燈光和不帶燈光的

本文shader原始碼所在目錄:Standard Assets/Effects/ToonShading

ToonBasic 的原理與寫法

Basic的原理是通過一個Cubemap型別的貼圖和當前的shader進行疊加相乘得到的(兩個畫素相乘是改變對應畫素的亮度或者色值,具體可以查閱下資料畫素相乘和相加的意義)。這個時候你就會看到模型的臉,腿的部分很亮,其他部分就暗色些。
具體的寫法如下:

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"
//pass的名字,這個後續的shader會用到 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) //②獲取fog的座標 }; v2f vert (appdata v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); //③獲取2d紋理座標 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); //⑤i.fogcoord是從頂點資料取出來的一個2維的紋理座標 return c; } ENDCG } } Fallback "VertexLit" }

補充說明下:這裡有幾條unitycg.cginc裡面定義的指令
①:是編譯多種型別的霧的變體,你可以在fog設定的地方看到fog mode的設定情況,這句話就表明了在不同mode 的時候對對本shader的編譯
②:fog的頂點資料,為後面作色做準備
③:獲取2d紋理的座標資料
④:獲取無效資料
⑤:對霧的顏色值和當前的畫素進行插值,如果渲染的模式是renderpath的那麼末日的作色是黑色

ToonBasicOutLine的原理與寫法

outline的原理:沿著視角垂直的地方向外拉昇畫素,用於作色使用(這個應該是目前遊戲中使用最多的演算法了)
具體的寫法如下:

Shader "Toon/Basic Outline" {
    Properties {
        _Color ("Main Color", Color) = (.5,.5,.5,1)
        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
        _Outline ("Outline width", Range (.002, 0.03)) = .005
        _MainTex ("Base (RGB)", 2D) = "white" { }
        _ToonShade ("ToonShader Cubemap(RGB)", CUBE) = "" { }
    }

    CGINCLUDE
    #include "UnityCG.cginc"

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

    struct v2f {
        float4 pos : SV_POSITION;
        UNITY_FOG_COORDS(0)
        fixed4 color : COLOR;
    };

    uniform float _Outline;
    uniform float4 _OutlineColor;

    v2f vert(appdata v) {
        v2f o;
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

        float3 norm   = normalize(mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal));
        float2 offset = TransformViewToProjection(norm.xy);

        #ifdef UNITY_Z_0_FAR_FROM_CLIPSPACE //to handle recent standard asset package on older version of unity (before 5.5)
            o.pos.xy += offset * UNITY_Z_0_FAR_FROM_CLIPSPACE(o.pos.z) * _Outline;
        #else
            o.pos.xy += offset * o.pos.z * _Outline; //核心地方:在處理頂點的時候沿著視線垂直的地方進行向外拉昇
        #endif
        o.color = _OutlineColor;
        UNITY_TRANSFER_FOG(o,o.pos);
        return o;
    }
    ENDCG

    SubShader {
        Tags { "RenderType"="Opaque" }
         UsePass "Toon/Basic/BASE"  //引用之前的base pass也就是先作色人物
        Pass {
            Name "OUTLINE"  //命名為outline
            Tags { "LightMode" = "Always" }
            Cull front //剔除正面
            ZWrite On  //開啟寫快取
            ColorMask rgb //對rgb顏色值進行蒙板
            Blend SrcAlpha OneMinusSrcAlpha //混合


            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            fixed4 frag(v2f i) : SV_Target
            {
                UNITY_APPLY_FOG(i.fogCoord, i.color);
                return i.color;
            }
            ENDCG
        }
    }

    Fallback "Toon/Basic"
}

發現這篇文章很長了,而後面的兩個帶光的shader其實和這兩個shader沒啥區別,唯一不同的是使用了自己寫的光照模型。所以這裡不再做介紹,有興趣的同學可以自己研究下