Hey all,
I wrote a surface shader to get a toon ramp effect, but realised that it samples the ramp texture for all applicable lights seperately. This means that instead of having one set of toon cels, or “bands”, the toon bands on objects overlap. I figured I would have to write a vertex/pixel shader to handle this so that the ramp lookup could be done after the diffuse value for all available lights was calculated, making the object only have one set of “bands” dependant on the ramp lookup texture.
The circled areas should only have three seperate areas of shading
I decided to first write a vertex/fragment shader that just handled the input from one directional light first. It seems to be working, and it samples the lookup texture, but the bands of light are extremely low resolution.

The bands of light are extremely low res here
The code for the vertex shader is as follows:
Shader "Character/Banded Light Ramp Tex Vertex" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_RampTex ("Ramp", 2D) = "white"{}
_Color ("Color", Color) = (1,1,1,1)
_LightCutoff("Maximum distance", Float) = 5.0
}
SubShader {
Pass{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#pragma glsl
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform sampler2D _RampTex;
uniform float4 _Color;
uniform float _LightCutoff;
uniform float4 _LightColor0;
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct fragmentInput{
float4 pos : SV_POSITION;
float4 color : COLOR0;
half2 uv : TEXCOORD0;
};
// struct vertexOutput {
// float4 pos : SV_POSITION;
// };
fragmentInput vert(vertexInput i){
fragmentInput o;
o.pos = mul(UNITY_MATRIX_MVP, i.vertex);
o.uv = TRANSFORM_TEX(i.texcoord, _MainTex);
float3 normalDirection = normalize(mul(float4(i.normal,1.0), _World2Object).xyz);
float3 lightDirection = normalize( _WorldSpaceLightPos0.xyz);
float NdotL = max(0.0, dot(normalDirection, lightDirection));
float2 lookUpPos = (NdotL,NdotL);
float rampDiffuse = tex2D(_RampTex, lookUpPos);
float3 theColor = _LightColor0.xyz * _Color.rgb * rampDiffuse * 2 ;
o.color = float4(theColor, 1.0);
return o;
}
float4 frag(fragmentInput i) : COLOR
{
return tex2D(_MainTex, i.uv) * i.color;
}
ENDCG
Lighting On
}
}
}
I’m very new to shaders, and if there’s a way to sample the ramp texture after the total light value has been calculated in a surface shader that would also be super helpful. Mainly, I would like to know why the sampling is resulting in such low resolution light bands. Thanks for any help.
