Search Unity

  1. Unity 2019.4 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  3. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

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

Discussion in '2D' started by alesimula, May 26, 2020.

  1. alesimula

    alesimula

    Joined:
    Mar 27, 2019
    Posts:
    7
    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

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Experimental.Rendering.Universal;
    3. using System.Reflection;
    4.  
    5. [ExecuteInEditMode]
    6. public class ShadowCasterFlip : MonoBehaviour
    7. {
    8.     [SerializeField] [HideInInspector] private bool flipX = false;
    9.     [SerializeField] [HideInInspector] private bool flipY = false;
    10.     private SpriteRenderer spriteRenderer;
    11.     private ShadowCaster2D shadowCaster;
    12.     private static BindingFlags accessFlagsPrivate = BindingFlags.NonPublic | BindingFlags.Instance;
    13.     private static FieldInfo meshField = typeof(ShadowCaster2D).GetField("m_Mesh", accessFlagsPrivate);
    14.     private static FieldInfo shapePathField = typeof(ShadowCaster2D).GetField("m_ShapePath", accessFlagsPrivate);
    15.     private static MethodInfo onEnableMethod = typeof(ShadowCaster2D).GetMethod("OnEnable", accessFlagsPrivate);
    16.  
    17.     //Bounds bounds => GetComponent<Renderer>()?.bounds ?? GetComponent<Collider2D>()?.bounds ?? new Bounds(transform.position, Vector3.one);
    18.  
    19.     private void flipCaster(bool flipX, bool flipY) {
    20.         if (!flipX && !flipY) return;
    21.         var shapePath = shapePathField.GetValue(shadowCaster) as Vector3[];
    22.         var newShapePath = new Vector3[shapePath.Length];
    23.  
    24.         int newStartIndex = 0;
    25.         float? lowestAvg = null;
    26.  
    27.         for(int i = 0; i<shapePath.Length; i++) {
    28.             shapePath[i].x = shapePath[i].x * (flipX ? -1 : 1);
    29.             shapePath[i].y = shapePath[i].y * (flipY ? -1 : 1);
    30.             var newAvg = (shapePath[i].x+shapePath[i].y)/2;
    31.             if (lowestAvg == null || newAvg<lowestAvg) {
    32.                 newStartIndex = i;
    33.                 lowestAvg = newAvg;
    34.             }
    35.         }
    36.         if (flipX != flipY) for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni--) {
    37.             if (ni < 0) ni = shapePath.Length-1;
    38.             newShapePath[i] = shapePath[ni];
    39.         }
    40.         else for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni++) {
    41.             if (ni >= shapePath.Length) ni = 0;
    42.             newShapePath[i] = shapePath[ni];
    43.         }
    44.        
    45.         shapePathField.SetValue(shadowCaster, newShapePath);
    46.         meshField.SetValue(shadowCaster, null);
    47.         onEnableMethod.Invoke(shadowCaster, new object[0]);
    48.     }
    49.  
    50.     void Start() {
    51.         spriteRenderer = GetComponent<SpriteRenderer>();
    52.         shadowCaster = GetComponent<UnityEngine.Experimental.Rendering.Universal.ShadowCaster2D>();
    53.     }
    54.    
    55.     void Update() {
    56.         flipCaster((flipX != spriteRenderer.flipX), (flipY != spriteRenderer.flipY));
    57.         flipX = spriteRenderer.flipX;
    58.         flipY = spriteRenderer.flipY;
    59.     }
    60. }
     
  2. alesimula

    alesimula

    Joined:
    Mar 27, 2019
    Posts:
    7
    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

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Experimental.Rendering.Universal;
    3. using System.Reflection;
    4.  
    5. [ExecuteInEditMode]
    6. public class ShadowCasterFlip : MonoBehaviour
    7. {
    8.     [SerializeField] [HideInInspector] private bool flipX = false;
    9.     [SerializeField] [HideInInspector] private bool flipY = false;
    10.     private SpriteRenderer spriteRenderer;
    11.     private ShadowCaster2D shadowCaster;
    12.     private static BindingFlags accessFlagsPrivate = BindingFlags.NonPublic | BindingFlags.Instance;
    13.     private static FieldInfo meshField = typeof(ShadowCaster2D).GetField("m_Mesh", accessFlagsPrivate);
    14.     private static FieldInfo shapePathField = typeof(ShadowCaster2D).GetField("m_ShapePath", accessFlagsPrivate);
    15.     private static MethodInfo onEnableMethod = typeof(ShadowCaster2D).GetMethod("OnEnable", accessFlagsPrivate);
    16.     private static bool isInspector =>
    17.     #if UNITY_EDITOR
    18.         !UnityEditor.EditorApplication.isPlaying;
    19.     #else
    20.         false;
    21.     #endif
    22.  
    23.     //Bounds bounds => GetComponent<Renderer>()?.bounds ?? GetComponent<Collider2D>()?.bounds ?? new Bounds(transform.position, Vector3.one);
    24.  
    25.     private bool flipCaster(bool flipX, bool flipY) {
    26.         if (!flipX && !flipY) return false;
    27.         var shapePath = shapePathField.GetValue(shadowCaster) as Vector3[];
    28.         var newShapePath = new Vector3[shapePath.Length];
    29.  
    30.         int newStartIndex = 0;
    31.         float? lowestAvg = null;
    32.  
    33.         for(int i = 0; i<shapePath.Length; i++) {
    34.             shapePath[i].x = shapePath[i].x * (flipX ? -1 : 1);
    35.             shapePath[i].y = shapePath[i].y * (flipY ? -1 : 1);
    36.             var newAvg = (shapePath[i].x+shapePath[i].y)/2;
    37.             if (lowestAvg == null || newAvg<lowestAvg) {
    38.                 newStartIndex = i;
    39.                 lowestAvg = newAvg;
    40.             }
    41.         }
    42.         if (flipX != flipY) for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni--) {
    43.             if (ni < 0) ni = shapePath.Length-1;
    44.             newShapePath[i] = shapePath[ni];
    45.         }
    46.         else for(int i = 0, ni = newStartIndex; i < shapePath.Length; i++, ni++) {
    47.             if (ni >= shapePath.Length) ni = 0;
    48.             newShapePath[i] = shapePath[ni];
    49.         }
    50.      
    51.         shapePathField.SetValue(shadowCaster, newShapePath);
    52.         shadowCaster.enabled = false;
    53.         meshField.SetValue(shadowCaster, null);
    54.         shadowCaster.enabled = true;
    55.         return true;
    56.     }
    57.  
    58.     #if UNITY_EDITOR
    59.     void Start() {
    60.         if (isInspector) {
    61.             spriteRenderer = GetComponent<SpriteRenderer>();
    62.             shadowCaster = GetComponent<UnityEngine.Experimental.Rendering.Universal.ShadowCaster2D>();
    63.         }
    64.     }
    65.     #endif
    66.  
    67.     #if UNITY_EDITOR
    68.     void Update() {
    69.         if (isInspector && flipCaster(flipX != spriteRenderer.flipX, flipY != spriteRenderer.flipY)) {
    70.             flipX = spriteRenderer.flipX;
    71.             flipY = spriteRenderer.flipY;
    72.             UnityEditor.EditorUtility.SetDirty(shadowCaster);
    73.             UnityEditor.EditorUtility.SetDirty(this);
    74.         }
    75.     }
    76.     #endif
    77. }
    78.  
     
    Last edited: May 27, 2020
unityunity