Unity自帶Shader(一)(卡通著色)
阿新 • • 發佈:2019-01-24
前言:最近有必要系統的學習下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沒啥區別,唯一不同的是使用了自己寫的光照模型。所以這裡不再做介紹,有興趣的同學可以自己研究下