Ok, it is too long but I am still learning how to optimize this, so here it is :):
Shader "UnityCookie/NoobToProTut/Intermediate/10 - Toon Map"
{
Properties
{
_Color ("Lit Color", Color) = (1.0,1.0,1.0,1.0)
_UnlitColor ("Unlit Color", Color) = (0.5,0.5,0.5,1.0)
_MainTex ("Diffuse Texture", 2D) = "white" {}
_BumpMap ("Normal Texture", 2D) = "bump" {}
_BumpDepth ("Bump Depth", Range(0.0, 1.0)) = 1.0
_DiffuseThreshold ("Lighting Threshold", Range(0.0, 1.0)) = 0.1 // Control the line transition between both colors
_Diffusion ("Diffusion", Range(0.0, 1.0)) = 0.0 // Control the blurry the line transition it is
_SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0)
_Shininess ("Shininess", Range(0.5, 1)) = 1
_SpecDiffusion ("Specular Diffusion", Range(0, 0.99)) = 0.0 // Controls the blurry border line of the specular light
_OutlineColor ("Outline Color", Color) = (0.0,0.0,0.0,1.0)
_OutlineThickness ("Outline Thickness", Range(0.0, 1.0)) = 0.1
_OutlineDiffusion ("Outline Diffusion", Range(0.0, 1.0)) = 0
}
SubShader
{
// FIRST RENDERER PASS
Pass {
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// compile shader into multiple variants, with and without shadows
// (we don't care about any lightmaps yet, so skip these variants)
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
// shadow helper functions and macros
#include "AutoLight.cginc"
#include "UnityCG.cginc"
//user defined variables
uniform fixed4 _Color;
uniform fixed4 _UnlitColor;
uniform sampler2D _MainTex;
uniform half4 _MainTex_ST;
uniform sampler2D _BumpMap;
uniform half4 _BumpMap_ST;
uniform fixed _BumpDepth;
uniform fixed _DiffuseThreshold;
uniform fixed _Diffusion;
uniform fixed4 _SpecColor;
uniform fixed _Shininess;
uniform fixed _SpecDiffusion;
uniform fixed4 _OutlineColor;
uniform fixed _OutlineThickness;
uniform fixed _OutlineDiffusion;
//unity defined variables
uniform half4 _LightColor0;
//base input structs
struct vertexInput
{
half4 vertex : POSITION;
half3 normal : NORMAL;
half4 texcoord : TEXCOORD0; // Gets the UV map from the texture on the object
half4 tangent : TANGENT; // Gets the tangent direction of the normals
};
struct vertexOutput
{
half4 pos : SV_POSITION;
half4 tex : TEXCOORD0;
SHADOW_COORDS(1) // put shadows data into TEXCOORD1
fixed3 normalDir : TEXCOORD2;
fixed4 lightDir : TEXCOORD3;
fixed3 viewDir : TEXCOORD4;
fixed3 tangentDir : TEXCOORD5; // Store the tangent direction of the normals
fixed3 binomialDir : TEXCOORD6; // Store the perpendicular direction between the normal and tangent
};
//vertex Function
vertexOutput vert(vertexInput v)
{
vertexOutput o;
//normalDirection
o.normalDir = normalize( mul( half4( v.normal, 0.0 ), unity_WorldToObject ).xyz );
// calculate directions for bump map
o.tangentDir = normalize( mul( unity_ObjectToWorld, v.tangent).xyz);
o.binomialDir = normalize( cross( o.normalDir, o.tangentDir) * v.tangent.w);
// Store texture coordinates
o.tex = v.texcoord;
//unity transform position
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//world position
half4 posWorld = mul(unity_ObjectToWorld, v.vertex);
//view direction
o.viewDir = normalize( _WorldSpaceCameraPos.xyz - posWorld.xyz );
//light direction
half3 vertexToLightSource = _WorldSpaceLightPos0.xyz - posWorld.xyz;
o.lightDir = fixed4(
normalize( lerp(_WorldSpaceLightPos0.xyz , vertexToLightSource, _WorldSpaceLightPos0.w) ),
lerp(1.0 , 1.0/length(vertexToLightSource), _WorldSpaceLightPos0.w)
);
// compute shadows data
TRANSFER_SHADOW(o)
return o;
}
//fragment function
fixed4 frag(vertexOutput i) : SV_TARGET
{
// Texture and Bump Maps
fixed4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
fixed4 texN = tex2D(_BumpMap, i.tex.xy * _BumpMap_ST.xy + _BumpMap_ST.zw);
// Unpack Normal function
fixed3 localCoords = fixed3( 2.0 * texN.ag - float2( 1.0, 1.0), _BumpDepth);
// Normal transpose matrix
fixed3x3 local2WorldTranspose = fixed3x3(
i.tangentDir,
i.binomialDir,
i.normalDir
);
// Calculate Bump Direction
fixed3 bumpDirection = normalize( mul( localCoords, local2WorldTranspose));
// compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
fixed shadow = smoothstep(0.0, 1.0, SHADOW_ATTENUATION(i));
// Transition Masks
fixed diffuseCutoff = saturate( smoothstep( _DiffuseThreshold, 1.0, i.lightDir.w * dot(bumpDirection, i.lightDir.xyz) * shadow) * pow( (2 - _Diffusion), 10));
fixed specularCutoff = saturate( smoothstep( _Shininess, 1.0, i.lightDir.w * dot( reflect( -i.lightDir.xyz, bumpDirection), i.viewDir)) * shadow * pow( ( 2 - _SpecDiffusion), 10));
// Calculate outlines
fixed outlineStrenth = saturate( ( dot( i.normalDir, i.viewDir) - _OutlineThickness) * pow( ( 2 - _OutlineDiffusion), 10) + _OutlineThickness);
fixed3 outlineOverlay = (_OutlineColor.xyz * _LightColor0.xyz * ( 1 - outlineStrenth)) + outlineStrenth;
// Lighting
fixed3 ambientLight = tex.xyz * ( 1 - diffuseCutoff) * _UnlitColor.xyz * (_LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz);
fixed3 diffuseReflection = tex.xyz * (1 - specularCutoff) * _Color.xyz * _LightColor0.xyz * diffuseCutoff;
fixed3 specularReflection = specularCutoff * _SpecColor.xyz * tex.a;
fixed3 lightFinal = (ambientLight + diffuseReflection) * outlineOverlay + specularReflection;
return fixed4(lightFinal, 1.0);
}
ENDCG
}
// SECOND RENDERER PASS
Pass {
Tags {"LightMode" = "ForwardAdd"}
Blend SrcAlpha OneMinusSrcColor
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd_fullshadows
#include "AutoLight.cginc"
#include "UnityCG.cginc"
//user defined variables
uniform fixed4 _Color;
uniform fixed4 _UnlitColor;
uniform sampler2D _MainTex;
uniform half4 _MainTex_ST;
uniform sampler2D _BumpMap;
uniform half4 _BumpMap_ST;
uniform fixed _BumpDepth;
uniform fixed _DiffuseThreshold;
uniform fixed _Diffusion;
uniform fixed4 _SpecColor;
uniform fixed _Shininess;
uniform fixed _SpecDiffusion;
uniform fixed4 _OutlineColor;
uniform fixed _OutlineThickness;
uniform fixed _OutlineDiffusion;
//unity defined variables
uniform half4 _LightColor0;
//base input structs
struct vertexInput
{
half4 vertex : POSITION;
half3 normal : NORMAL;
half4 texcoord : TEXCOORD0;
half4 tangent : TANGENT;
};
struct vertexOutput
{
half4 pos : SV_POSITION;
half4 tex : TEXCOORD0;
SHADOW_COORDS(1)
fixed3 normalDir : TEXCOORD2;
fixed4 lightDir : TEXCOORD3;
fixed3 viewDir : TEXCOORD4;
fixed3 tangentDir : TEXCOORD5;
fixed3 binomialDir : TEXCOORD6;
};
//vertex Function
vertexOutput vert(vertexInput v)
{
vertexOutput o;
//normalDirection
o.normalDir = normalize( mul( half4( v.normal, 0.0 ), unity_WorldToObject ).xyz );
// calculate directions for bump map
o.tangentDir = normalize( mul( unity_ObjectToWorld, v.tangent).xyz);
o.binomialDir = normalize( cross( o.normalDir, o.tangentDir) * v.tangent.w);
// Store texture coordinates
o.tex = v.texcoord;
//unity transform position
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//world position
half4 posWorld = mul(unity_ObjectToWorld, v.vertex);
//view direction
o.viewDir = normalize( _WorldSpaceCameraPos.xyz - posWorld.xyz );
//light direction
half3 vertexToLightSource = _WorldSpaceLightPos0.xyz - posWorld.xyz;
o.lightDir = fixed4(
normalize( lerp(_WorldSpaceLightPos0.xyz , vertexToLightSource, _WorldSpaceLightPos0.w) ),
lerp(1.0 , 1.0/length(vertexToLightSource), _WorldSpaceLightPos0.w)
);
// compute shadows data
TRANSFER_SHADOW(o)
return o;
}
//fragment function
fixed4 frag(vertexOutput i) : SV_TARGET
{
// Texture and Bump Maps
fixed4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
fixed4 texN = tex2D(_BumpMap, i.tex.xy * _BumpMap_ST.xy + _BumpMap_ST.zw);
// Unpack Normal function
fixed3 localCoords = fixed3( 2.0 * texN.ag - float2( 1.0, 1.0), _BumpDepth);
// Normal transpose matrix
fixed3x3 local2WorldTranspose = fixed3x3(
i.tangentDir,
i.binomialDir,
i.normalDir
);
// Calculate Bump Direction
fixed3 bumpDirection = normalize( mul( localCoords, local2WorldTranspose));
// compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
fixed shadow = smoothstep(0.0, 1.0, SHADOW_ATTENUATION(i));
// Transition Masks
fixed diffuseCutoff = saturate( smoothstep( _DiffuseThreshold, 1.0, i.lightDir.w * shadow * dot(bumpDirection, i.lightDir.xyz)) * pow( (2 - _Diffusion), 10));
fixed specularCutoff = saturate( smoothstep( _Shininess, 1.0, i.lightDir.w * dot( reflect( -i.lightDir.xyz, bumpDirection), i.viewDir)) * shadow * pow( ( 2 - _SpecDiffusion), 10));
// Calculate outlines
fixed outlineStrenth = saturate( ( dot( i.normalDir, i.viewDir) - _OutlineThickness) * pow( ( 2 - _OutlineDiffusion), 10) + _OutlineThickness);
fixed3 outlineOverlay = (_OutlineColor.xyz * ( 1 - outlineStrenth)) + outlineStrenth;
// Lighting
fixed3 ambientLight = tex.xyz * ( 1 - diffuseCutoff) * _UnlitColor.xyz;
fixed3 diffuseReflection = tex.xyz * (1 - specularCutoff) * _Color.xyz * _LightColor0.xyz * diffuseCutoff;
fixed3 specularReflection = specularCutoff * _SpecColor.xyz * _LightColor0.xyz * tex.a;
fixed3 lightFinal = (ambientLight + diffuseReflection) * outlineOverlay + specularReflection;
return fixed4(lightFinal, 1.0);
}
ENDCG
}
// SHADOW CASTER RENDERING PASS
Pass
{
Tags {"LightMode" = "ShadowCaster"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
//base input structs
struct v2f
{
V2F_SHADOW_CASTER;
};
v2f vert (appdata_base v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
half4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
//Fallback "Specular"
}