Shadow Caster 2D not working on TileMap?

It’s been more than a whole year I posted here about the shadow support for tilemap. A Whole year! And Still ! no support for the shadow tilemap!

If anyone else is like me and is doing some 2D stuff with tilemaps and just wants a convenient way to get shadows going with this experimental system, without modifying the package scripts, I’ve adapted the approach from this thread & another into a component that’ll work with an arbitrary input list of CompositeCollider2Ds and create a set of children ShadowCaster2Ds that you can use with a sister CompositeShadowCaster2D script on the parent to conveniently manage a scene with stuff like tilemap colliders.

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Experimental.Rendering.Universal;

/**
* Usage: Make an empty game object and attach this component script to it. Drag & drop CompositeCollider2D components
* into the sourceColliders field.
*
* This script isn't ideal, but it's simple and an okay jumping off point for more advanced changes (like caching).
*
* The main caveat is that it'll regenerate the child objects that comprise the shadow group every time you enter
* edit mode. For larger scenes this might be slow or annoying. It's a rough sketch I'm using for a jam game so I'm
* not too concerned about this, future travelers may way to dig into more optimal ways of not having to recreate the
* child object shadow casters.
*/
[ExecuteInEditMode]
[RequireComponent(typeof(CompositeShadowCaster2D))]
[DisallowMultipleComponent]
public class ShadowWrangler : MonoBehaviour
{
    public CompositeCollider2D[] sourceColliders = { };

    private static BindingFlags accessFlagsPrivate =
        BindingFlags.NonPublic | BindingFlags.Instance;

    private static FieldInfo shapePathField =
        typeof(ShadowCaster2D).GetField("m_ShapePath", accessFlagsPrivate);

    private static FieldInfo meshHashField =
        typeof(ShadowCaster2D).GetField("m_ShapePathHash", accessFlagsPrivate);


    // Start is called before the first frame update
    void OnEnable()
    {
        // only refresh this stuff in edit mode since the ShadowCaster components will serialize/persist their
        // shadow mesh on their own.
        // TODO: maybe only trigger the refresh when a difference is detected
        if (Application.isEditor) RefreshWorldShadows();
    }

    private void RefreshWorldShadows()
    {
        ClearChildShadows();
        foreach (var source in sourceColliders)
        {
            CreateGroupsForCollider(source);
        }
    }

    private void ClearChildShadows()
    {
        var doomed = new List<Transform>();
        for (int i = 0; i < transform.childCount; i++)
        {
            var child = transform.GetChild(i);
            if (child.GetComponent<ShadowCaster2D>() == null || !child.name.StartsWith("_caster_")) continue;
            doomed.Add(transform.GetChild(i));
        }

        foreach (var child in doomed)
        {
            DestroyImmediate(child.gameObject);
        }
    }

    /**
     * This is adapted from strategies in these two discussion threads:
     * - https://discussions.unity.com/t/769178
     * - https://discussions.unity.com/t/776893
     * Hopefully a day comes where we're allowed to programmatically mutate the shadow caster shape
     * programmatically.
     */
    private void CreateGroupsForCollider(CompositeCollider2D source)
    {
        for (int i = 0; i < source.pathCount; i++)
        {
            // get the path data
            Vector2[] pathVertices = new Vector2[source.GetPathPointCount(i)];
            source.GetPath(i, pathVertices);
            Vector3[] finalVerts = Array.ConvertAll<Vector2, Vector3>(pathVertices, input => input);

            // make a new child
            var shadowCaster = new GameObject("_caster_" + i + "_" + source.transform.name);
            shadowCaster.transform.parent = transform;

            // create & prime the shadow caster
            var shadow = shadowCaster.AddComponent<ShadowCaster2D>();
            shadow.selfShadows = true;
            shapePathField.SetValue(shadow, finalVerts);
            // invalidate the hash so it re-generates the shadow mesh on the next Update()
            meshHashField.SetValue(shadow, -1);
        }
    }
}

Example scene hierarchy (inputted from a single tilemap’s CompositeCollider2D):

Example of the shadow meshes in the scene (the white outline around the main tilemaps):

Cross post from here .