本文参考博客Unity Toon Shader 卡通着色器(一):卡通着色
这是我实现的最后效果
我们先一步一步来
最开始我们实现一个只有漫反射效果的Shader,效果和代码如下
Shader "Unlit/ToonLearn"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color",Color)=(1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 normal:TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float3 _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal=mul(v.normal,(float3x3)unity_WorldToObject);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
float3 normal=normalize(i.normal);
float NdotL=saturate(dot(normal,lightDir));
fixed3 albedo = tex2D(_MainTex, i.uv)*_Color.rgb;
fixed3 diffuse= albedo*_LightColor0.rgb*NdotL;
float4 finalColor=float4(diffuse,1);
return finalColor;
}
ENDCG
}
}
}
这就是一个比较简单的漫反射着色器
接下来把色阶降到两个
代码如下
_RampThreshold("Ramp Threshold",Range(0,1))=0.5
_RampSmooth("Smooth Threshold",Range(0,1))=0.1
......
fixed3 ramp=smoothstep(_RampThreshold-_RampSmooth*0.5,
_RampThreshold+_RampSmooth*0.5,NdotL);
fixed3 albedo = tex2D(_MainTex, i.uv)*_Color.rgb;
fixed3 diffuse= albedo*_LightColor0.rgb*ramp;
在这里我们引入_RampThreshold,当NdotL>_RampThreshold,ramp=1,当NdotL<_RampThreshold,ramp=0,
同时我们引入_RampSmooth作为平滑度,同时使smoothstep进行平滑过渡,这篇博客对smoothstep的介绍就挺好的Shader smoothstep使用
接下来我们可以用颜色叠加来作为阴影和亮部,于是引入了_SColor和_HColor,挑一个好看的参数。
反正比黑漆漆要好看得多,以下是代码
_HColor ("Highlight Color", Color) = (0.8, 0.8, 0.8, 1.0)
_SColor ("Shadow Color", Color) = (0.2, 0.2, 0.2, 1.0)
...
_SColor=lerp(_HColor,_SColor,_SColor.a);
float3 rampColor=lerp(_SColor.rgb,_HColor.rgb,ramp);
fixed3 diffuse= albedo*_LightColor0.rgb*rampColor;
最后我们需要增加一些高光和边缘光,效果如下(只是高光计算有点问题)
最后的代码
Shader "Unlit/ToonLearn"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RampThreshold("Ramp Threshold",Range(0,1))=0.5
_RampSmooth("Smooth Threshold",Range(0,1))=0.1
_Color("Color",Color)=(1,1,1,1)
_HColor ("Highlight Color", Color) = (0.8, 0.8, 0.8, 1.0)
_SColor ("Shadow Color", Color) = (0.2, 0.2, 0.2, 1.0)
_SpecularColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
_SpecThreshold ("Specular Threshold", Range(0, 1)) = 0.5
_SpecSmooth ("Specular Smooth", Range(0, 1)) = 0.1
_Shininess ("Shininess", Range(0.001, 10)) = 0.2
_RimColor ("Rim Color", Color) = (0.8, 0.8, 0.8, 0.6)
_RimThreshold ("Rim Threshold", Range(0, 1)) = 0.5
_RimSmooth ("Rim Smooth", Range(0, 1)) = 0.1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 normal:TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
float4 _SColor;
float4 _HColor;
float _RampThreshold;
float _RampSmooth;
float4 _SpecularColor;
float _SpecThreshold;
float _SpecSmooth;
float _Shininess;
float4 _RimColor;
float _RimThreshold;
float _RimSmooth;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal=mul(v.normal,(float3x3)unity_WorldToObject);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz);
fixed3 halfDir=normalize(lightDir+viewDir);
float3 normal=normalize(i.normal);
float NdotL=saturate(dot(normal,lightDir));
float NdotH=saturate(dot(normal,halfDir));
float NdotV=saturate(dot(normal,viewDir));
fixed3 ramp=smoothstep(_RampThreshold-_RampSmooth*0.5,
_RampThreshold+_RampSmooth*0.5,NdotL);
fixed4 albedo = tex2D(_MainTex, i.uv)*_Color;
_SColor=lerp(_HColor,_SColor,_SColor.a);
float3 rampColor=lerp(_SColor.rgb,_HColor.rgb,ramp);
fixed3 diffuse= albedo.rgb*_LightColor0.rgb*rampColor;
float gloss=albedo.a;
float spec=pow(NdotH,_Shininess*128)*gloss;
spec=smoothstep(_SpecThreshold-_SpecSmooth*0.5,
_SpecThreshold+_SpecSmooth*0.5,spec);
fixed3 specular=_SpecularColor.rgb*_LightColor0.rgb*spec;
float rim=(1-NdotV)*NdotL;
rim=smoothstep(_RimThreshold-_RimSmooth*0.5,_RimThreshold+_RimSmooth*0.5,rim);
fixed3 rimColor=_RimColor.rgb*_LightColor0.rgb*_RimColor.a*rim;
float4 finalColor=float4(diffuse+specular+rimColor,1);
return finalColor;
}
ENDCG
}
}
}
这就是全部了,感谢你的阅读,如有错误,欢迎指正。