My goal was to set out in creating a cel-shader that reacts to point lights, rather than using the included Toon shader which uses a premade cubemap and a directional light source to control the movement of the cel-shaded regions. I began by deconstructing the Normal-Diffuse.shader until I had revealed the dot product calculation for figuring out the Lambertian reflectance. After that it was simply a matter of dividing the range into segments based on a Levels value to control how many tones are produced.
Shader "Experimental/Posterize" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_Levels ("Levels", Range (2, 10)) = 2
}
SubShader {
Pass {
Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
float4 _Color;
float _Levels;
struct v2f {
V2F_POS_FOG;
LIGHTING_COORDS
float2 uv;
float3 normal;
float3 lightDir;
};
uniform float4 _MainTex_ST;
v2f vert (appdata_base v) {
v2f o;
PositionFog( v.vertex, o.pos, o.fog );
o.normal = v.normal;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.lightDir = ObjSpaceLightDir( v.vertex );
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
uniform sampler2D _MainTex;
float4 frag (v2f i) : COLOR {
half4 texcol = tex2D(_MainTex, i.uv);
#ifndef USING_DIRECTIONAL_LIGHT
i.lightDir = normalize(i.lightDir);
#endif
half diffuse = dot(i.normal, i.lightDir);
half4 c;
half step = 1 / round(_Levels);
half currentLevel = floor(diffuse / step);
if(diffuse < step-1){
c.rgb = texcol.rgb * _ModelLightColor0.rgb * (0 * LIGHT_ATTENUATION(i) * 2);
} else {
c.rgb = texcol.rgb * _ModelLightColor0.rgb * (currentLevel * step);
}
c.a = 0;
return c;
}
ENDCG
}
}
}
However I’m running into one issue now that I am not sure how to get around. I’d like to affect the shader with multiple point lights with potentially different colors, so cool overlapping effects may occur. However when I use two lights, it seems like whichever one is closest is what affects the shader. This is most likely because of the _ModelLightColor0.rgb variable. Ideally I would like to iterate over any point lights within range and apply my algorithm within that loop. Can anyone suggest a method for doing this?
