Cel Shading on Pixel Art

I’m new to shaders and have been trying to get cel shading working with some 2D pixel art. I’ve almost got it working how I want except for some small shading artifacts…

I circled a few of the problem areas I am getting. I’d like to get the shader to fill entire pixels in the sprite the same color instead of splitting them like it’s currently doing. Any idea why this is happening or how to fix it? Also, both the sprite and normal map are 24x15 pixels.

edit: only point and spot lights produce this artifact

Shader "Custom/Toon"
{
    Properties
    {
        _TintColor("Tint", Color) = (1,1,1,1)
        _MainTex("Sprite Sheet", 2D) = "white" {}
        _NormalTex("Normal Map", 2D) = "bump" {}
        _EmissionTex("Emission Map", 2D) = "black" {}
        _CelShadingLevel("Cel Level", Range(0, 10)) = 3
    }
    SubShader
    {
        Tags{ "RenderType"="Cutout" }

        LOD 100
      
        CGPROGRAM
        #pragma surface surf Toon alpha

        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _NormalTex;
        sampler2D _EmissionTex;
        sampler2D _RampTex;
        fixed4 _TintColor;
        float _CelShadingLevel;

        struct Input
        {
            float2 uv_MainTex;
        };


        half4 LightingToon(SurfaceOutput s, half3 lightDir, half atten)
        {
            half NdotL = dot(s.Normal, lightDir);
            half cel = floor(NdotL * _CelShadingLevel) / (_CelShadingLevel - 0.5);

            half4 c;
            c.rgb = s.Albedo * _LightColor0.rgb * cel * atten;
            c.a = s.Alpha;
            return c;
        }

        void surf(Input IN, inout SurfaceOutput o)
        {
            float3 normalMap = UnpackNormal(tex2D(_NormalTex, IN.uv_MainTex));
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _TintColor;
            fixed4 e = tex2D(_EmissionTex, IN.uv_MainTex);
          
            o.Normal = normalMap.rgb;
            o.Albedo = c.rgb;
            o.Emission = e.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
}

The light direction between a point light and a flat surface changes as you move across a surface, so even if your surface and normals are flat, the lighting isn’t.

A solution would be to calculate the light direction yourself, using a constant position for the each pixel area. It’s possible, but a tricky thing to do, and I honestly have no idea how to do it working within the limitations of a surface shader.