Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

DropShadow scale independent

Discussion in 'Scripting' started by Damast, Jul 30, 2022.

  1. Damast

    Damast

    Joined:
    Apr 25, 2019
    Posts:
    13
    Hello, I found this really helpful script on the Internet.
    It creates a nice Drop shadow but there's one problem: The shadow isn't scale-independent.
    How can I tweak the script so that the shadow has the same width on both images (the script has the same settings on both GameObjects)
    upload_2022-7-30_9-34-33.png
    As I'm still learning Unity, I really appreciate any help you can provide.

    Code (CSharp):
    1. /*
    2. * Hello there :)
    3. *
    4. * I'm happy to be read
    5. * Sadly my author didn't wrote his name :'( too bad
    6. * I guess I'm free then
    7. */
    8.  
    9. using System.Collections.Generic;
    10. using UnityEditor;
    11.  
    12. namespace UnityEngine.UI
    13. {
    14.     [AddComponentMenu("UI/Effects/DropShadow", 14)]
    15.     public class DropShadow : BaseMeshEffect
    16.     {
    17.         [SerializeField]
    18.         private Color shadowColor = new Color(0f, 0f, 0f, 0.5f);
    19.  
    20.         [SerializeField]
    21.         private Vector2 shadowDistance = new Vector2(0f, -2f);
    22.  
    23.         [SerializeField]
    24.         private bool m_UseGraphicAlpha = true;
    25.         public int iterations = 20;
    26.         public Vector2 shadowSpread = Vector2.one;
    27.  
    28.         protected DropShadow()
    29.         { }
    30.  
    31.  
    32. #if UNITY_EDITOR
    33.         protected override void OnValidate()
    34.         {
    35.             EffectDistance = shadowDistance;
    36.             base.OnValidate();
    37.         }
    38.  
    39. #endif
    40.  
    41.         public Color effectColor
    42.         {
    43.             get { return shadowColor; }
    44.             set
    45.             {
    46.                 shadowColor = value;
    47.                 if (graphic != null)
    48.                     graphic.SetVerticesDirty();
    49.             }
    50.         }
    51.  
    52.         public Vector2 ShadowSpread
    53.         {
    54.             get { return shadowSpread; }
    55.             set
    56.             {
    57.                 shadowSpread = value;
    58.                 if (graphic != null)
    59.                     graphic.SetVerticesDirty();
    60.             }
    61.         }
    62.  
    63.         public int Iterations
    64.         {
    65.             get { return iterations; }
    66.             set
    67.             {
    68.                 iterations = value;
    69.                 if (graphic != null)
    70.                     graphic.SetVerticesDirty();
    71.             }
    72.         }
    73.  
    74.         public Vector2 EffectDistance
    75.         {
    76.             get { return shadowDistance; }
    77.             set
    78.             {
    79.                 shadowDistance = value;
    80.  
    81.                 if (graphic != null)
    82.                     graphic.SetVerticesDirty();
    83.             }
    84.         }
    85.  
    86.         public bool useGraphicAlpha
    87.         {
    88.             get { return m_UseGraphicAlpha; }
    89.             set
    90.             {
    91.                 m_UseGraphicAlpha = value;
    92.                 if (graphic != null)
    93.                     graphic.SetVerticesDirty();
    94.             }
    95.         }
    96.  
    97.  
    98.         void DropShadowEffect(List<UIVertex> verts)
    99.         {
    100.             UIVertex vt;
    101.             int count = verts.Count;
    102.  
    103.             List<UIVertex> vertsCopy = new List<UIVertex>(verts);
    104.             verts.Clear();
    105.  
    106.             for (int i = 0; i < iterations; i++)
    107.             {
    108.                 for (int v = 0; v < count; v++)
    109.                 {
    110.                     vt = vertsCopy[v];
    111.                     Vector3 position = vt.position;
    112.                     float fac = (float)i / (float)iterations;
    113.                     position.x *= (1 + shadowSpread.x * fac * 0.01f);
    114.                     position.y *= (1 + shadowSpread.y * fac * 0.01f);
    115.                     position.x += shadowDistance.x * fac;
    116.                     position.y += shadowDistance.y * fac;
    117.                     vt.position = position;
    118.                     Color32 color = shadowColor;
    119.                     color.a = (byte)((float)color.a / (float)iterations);
    120.                     vt.color = color;
    121.                     verts.Add(vt);
    122.                 }
    123.             }
    124.  
    125.             for (int i = 0; i < vertsCopy.Count; i++)
    126.             {
    127.                 verts.Add(vertsCopy[i]);
    128.             }
    129.         }
    130.  
    131.         public override void ModifyMesh(VertexHelper vh)
    132.         {
    133.             if (!IsActive())
    134.                 return;
    135.  
    136.             List<UIVertex> output = new List<UIVertex>();
    137.             vh.GetUIVertexStream(output);
    138.  
    139.             DropShadowEffect(output);
    140.  
    141.             vh.Clear();
    142.             vh.AddUIVertexTriangleStream(output);
    143.         }
    144.     }
    145. }
     
  2. TheFunnySide

    TheFunnySide

    Joined:
    Nov 17, 2018
    Posts:
    192
    I am not going to test that for you but my assumption is that you have to set spread to 0 and use shadow distance instead. That should solve half your problem.
    Then Replace 115 and 116
    Code (CSharp):
    1.                  
    2. position.x += shadowDistance.x * fac /   transform.localScale.x;
    3. position.y += shadowDistance.y * fac /   transform.localScale.y;
    4.  
     
    Damast likes this.
  3. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    in my opinion, you should change shadowSpread.x/y according to your objects scale.
    distance is probably the offset of the underlying shadow from the object, while spread is how much it will spread from the baseline.

    that said, shadowSpread.x should diminish by how much the object is scaled on x, which means it is inversely proportional.

    Code (csharp):
    1. shadowSpread.x = 50f / transform.localScale.x;
    2. shadowSpread.y = 50f / transform.localScale.y;
    Meaning that an object stretched by 50% on X should have its shadow spread on X set at 33.33 (which will be stretched by 50% to appear as if it was 50). This is because
    50 / 1.5 = 33.333


    edit:
    Do note however, that this will inevitably destroy perceived quality of your shadow when stretching is too big. Your approach isn't very good, but it does offer some flexibility, and I don't know how exactly the shadow code was written, so it might be the best you can do.
     
    Damast likes this.
  4. Damast

    Damast

    Joined:
    Apr 25, 2019
    Posts:
    13
    Thank you very much for the replies, I modified the two lines and the script works as expected.
    Code (CSharp):
    1. position.x *= (1 + (shadowSpread.x / rectTransform.rect.width) * fac * 1f);
    2. position.y *= (1 + (shadowSpread.y / rectTransform.rect.height) * fac * 1f);
    Is there a disadvantage if I take the RectTransform values compared to the local scale values?
    (the RectTransform is referenced in Awake by using GetComponent())

    remark:
    shadowDistance affects the stretching/compression of the shadow in one direction while shadowSpread expands/decreases the shadow in both directions of the axis
     
    Last edited: Aug 6, 2022