[CODE] LWRP/URP Flip ShadowCaster2D when flipping sprite renderer

,

I needed this to use sprites with a normal map without having to redraw the ShadowCaster shape;
I made a small script that will simply mirror the ShadowCaster according to the Spriterenderer’s flipX and flipY values, hope someone else finds this useful

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

[ExecuteInEditMode]
public class ShadowCasterFlip : MonoBehaviour
{
    [SerializeField] [HideInInspector] private bool flipX = false;
    [SerializeField] [HideInInspector] private bool flipY = false;
    private SpriteRenderer spriteRenderer;
    private ShadowCaster2D shadowCaster;
    private static BindingFlags accessFlagsPrivate = BindingFlags.NonPublic | BindingFlags.Instance;
    private static FieldInfo meshField = typeof(ShadowCaster2D).GetField("m_Mesh", accessFlagsPrivate);
    private static FieldInfo shapePathField = typeof(ShadowCaster2D).GetField("m_ShapePath", accessFlagsPrivate);
    private static MethodInfo onEnableMethod = typeof(ShadowCaster2D).GetMethod("OnEnable", accessFlagsPrivate);

    //Bounds bounds => GetComponent<Renderer>()?.bounds ?? GetComponent<Collider2D>()?.bounds ?? new Bounds(transform.position, Vector3.one);

    private void flipCaster(bool flipX, bool flipY) {
        if (!flipX && !flipY) return;
        var shapePath = shapePathField.GetValue(shadowCaster) as Vector3[];
        var newShapePath = new Vector3[shapePath.Length];

        int newStartIndex = 0;
        float? lowestAvg = null;

        for(int i = 0; i<shapePath.Length; i++) {
            shapePath[i].x = shapePath[i].x * (flipX ? -1 : 1);
            shapePath[i].y = shapePath[i].y * (flipY ? -1 : 1);
            var newAvg = (shapePath[i].x+shapePath[i].y)/2;
            if (lowestAvg == null || newAvg<lowestAvg) {
                newStartIndex = i;
                lowestAvg = newAvg;
            }
        }
        if (flipX != flipY) for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni--) {
            if (ni < 0) ni = shapePath.Length-1;
            newShapePath[i] = shapePath[ni];
        }
        else for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni++) {
            if (ni >= shapePath.Length) ni = 0;
            newShapePath[i] = shapePath[ni];
        }
       
        shapePathField.SetValue(shadowCaster, newShapePath);
        meshField.SetValue(shadowCaster, null);
        onEnableMethod.Invoke(shadowCaster, new object[0]);
    }

    void Start() {
        spriteRenderer = GetComponent<SpriteRenderer>();
        shadowCaster = GetComponent<UnityEngine.Experimental.Rendering.Universal.ShadowCaster2D>();
    }
   
    void Update() {
        flipCaster((flipX != spriteRenderer.flipX), (flipY != spriteRenderer.flipY));
        flipX = spriteRenderer.flipX;
        flipY = spriteRenderer.flipY;
    }
}

For some reason I cannot edit my post, here is a version that only does changes in inspector mode and saves your precious CPU cycles

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

[ExecuteInEditMode]
public class ShadowCasterFlip : MonoBehaviour
{
    [SerializeField] [HideInInspector] private bool flipX = false;
    [SerializeField] [HideInInspector] private bool flipY = false;
    private SpriteRenderer spriteRenderer;
    private ShadowCaster2D shadowCaster;
    private static BindingFlags accessFlagsPrivate = BindingFlags.NonPublic | BindingFlags.Instance;
    private static FieldInfo meshField = typeof(ShadowCaster2D).GetField("m_Mesh", accessFlagsPrivate);
    private static FieldInfo shapePathField = typeof(ShadowCaster2D).GetField("m_ShapePath", accessFlagsPrivate);
    private static MethodInfo onEnableMethod = typeof(ShadowCaster2D).GetMethod("OnEnable", accessFlagsPrivate);
    private static bool isInspector =>
    #if UNITY_EDITOR
        !UnityEditor.EditorApplication.isPlaying;
    #else
        false;
    #endif

    //Bounds bounds => GetComponent<Renderer>()?.bounds ?? GetComponent<Collider2D>()?.bounds ?? new Bounds(transform.position, Vector3.one);

    private bool flipCaster(bool flipX, bool flipY) {
        if (!flipX && !flipY) return false;
        var shapePath = shapePathField.GetValue(shadowCaster) as Vector3[];
        var newShapePath = new Vector3[shapePath.Length];

        int newStartIndex = 0;
        float? lowestAvg = null;

        for(int i = 0; i<shapePath.Length; i++) {
            shapePath[i].x = shapePath[i].x * (flipX ? -1 : 1);
            shapePath[i].y = shapePath[i].y * (flipY ? -1 : 1);
            var newAvg = (shapePath[i].x+shapePath[i].y)/2;
            if (lowestAvg == null || newAvg<lowestAvg) {
                newStartIndex = i;
                lowestAvg = newAvg;
            }
        }
        if (flipX != flipY) for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni--) {
            if (ni < 0) ni = shapePath.Length-1;
            newShapePath[i] = shapePath[ni];
        }
        else for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni++) {
            if (ni >= shapePath.Length) ni = 0;
            newShapePath[i] = shapePath[ni];
        }
      
        shapePathField.SetValue(shadowCaster, newShapePath);
        shadowCaster.enabled = false;
        meshField.SetValue(shadowCaster, null);
        shadowCaster.enabled = true;
        return true;
    }

    #if UNITY_EDITOR
    void Start() {
        if (isInspector) {
            spriteRenderer = GetComponent<SpriteRenderer>();
            shadowCaster = GetComponent<UnityEngine.Experimental.Rendering.Universal.ShadowCaster2D>();
        }
    }
    #endif
  
    #if UNITY_EDITOR
    void Update() {
        if (isInspector && flipCaster(flipX != spriteRenderer.flipX, flipY != spriteRenderer.flipY)) {
            flipX = spriteRenderer.flipX;
            flipY = spriteRenderer.flipY;
            UnityEditor.EditorUtility.SetDirty(shadowCaster);
            UnityEditor.EditorUtility.SetDirty(this);
        }
    }
    #endif
}