Unity Shader 实现卡通渲染效果

本文参考博客Unity Toon Shader 卡通着色器(一):卡通着色
这是我实现的最后效果Unity Shader 实现卡通渲染效果_第1张图片
我们先一步一步来
最开始我们实现一个只有漫反射效果的Shader,效果和代码如下
Unity Shader 实现卡通渲染效果_第2张图片

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
		}
	}
}

这就是一个比较简单的漫反射着色器
接下来把色阶降到两个
Unity Shader 实现卡通渲染效果_第3张图片
代码如下

	_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,挑一个好看的参数。
Unity Shader 实现卡通渲染效果_第4张图片
反正比黑漆漆要好看得多,以下是代码

	_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;

最后我们需要增加一些高光和边缘光,效果如下(只是高光计算有点问题)
Unity Shader 实现卡通渲染效果_第5张图片
最后的代码

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
		}
	}
}

这就是全部了,感谢你的阅读,如有错误,欢迎指正。

你可能感兴趣的:(Unity,Shader,卡通渲染,Unity,Shader)