Tilemap Shader

Shader "Custom/TilemapShader" {
    Properties {        
        _MainTex ("Map", 2D) = "white" {}
        _Tileset("Tileset", 2D) = "white" {}
        _Size("Map & Tileset Size", Vector) = (16, 16, 20, 13)
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _Tileset;

        struct Input {
            float2 uv_MainTex;
        };

        float4 _Size;
        // _Size.xy is the size of the map in tiles.
        // _Size.zw is the size of the tileset in tiles.

        void surf (Input IN, inout SurfaceOutputStandard o) {

            // Scale up the uvs into tile space.
            float2 mapLocation = IN.uv_MainTex * _Size.xy;

            // Get this pixel's position within the tile we're drawing.
            float2 inTileUV = frac(mapLocation);

            // Clamp the texel we read from.
            // ("Point" filtering does this too, but its math is slightly
            // different, which can show up as a shimmer between tiles)
            mapLocation = (mapLocation - inTileUV) / _Size.xy;

            // Slightly inset tiles so they don't bleed at the edges.
            inTileUV = inTileUV * 126.0f / 128.0f + 1.0f / 128.0f;

            // Calculate texture sampling gradients using original UV.
            // Otherwise jumps at tile borders make the hardware apply filtering
            // that lets adjactent tiles bleed in at the edges.
            float4 grad = float4(ddx(IN.uv_MainTex), ddy(IN.uv_MainTex));

            // Read our map texture to determine what tiles go here.
            float4 tileIndex = tex2D(_MainTex, mapLocation);

            // Generate UV offsets into our tileset texture.
            tileIndex = (tileIndex * 255.0f + inTileUV.xyxy )/_Size.zwzw ;

            // Sample two tiles from our tileset: one base tile and one overlay.
            // (Hey, we have room for two indices, might as well use it!)
            fixed4 base = tex2Dgrad(_Tileset, tileIndex.xy, grad.xy, grad.zw);
            fixed4 over = tex2Dgrad(_Tileset, tileIndex.zw, grad.xy, grad.zw);

            // Combine overlaid tile with base using standard alpha blending.
            fixed4 c = lerp(base, over, over.a);

            // Put all this into terms the Unity lighting model understands.
            o.Albedo = c.rgb;           
            o.Metallic = 0.0f;
            o.Smoothness = 0.0f;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
Colorful Corncrake