Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  3. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Can 2D Shadow Caster use current sprite silhouette?

Discussion in '2D Experimental Preview' started by IvanNevesDev, Apr 5, 2020.

  1. IvanNevesDev

    IvanNevesDev

    Joined:
    Jan 28, 2019
    Posts:
    27
    Since i have to setup manually the Shadow Caster shape, it'll work fine for static objects but looks weird on an animated character sometimes, specially in cases where there's multiple directions and each sprite direction have a somewhat unique silhouette.
    Is it possible for the 2D Shadow Caster use the Sprite pixel instead?
     
    ezebongiovi likes this.
  2. CookieWood

    CookieWood

    Joined:
    Apr 26, 2020
    Posts:
    2
    Hi !

    Same problem here, did you find a way to make it works in the meantime ?
     
  3. the_Simian

    the_Simian

    Joined:
    Mar 13, 2011
    Posts:
    37
    I've spent a lot of time working on this today, here's the short answer: there's no good way at this time. Or if there is, I'm not able to see how really. The reason is that the ShadowCaster2d ShapePath is currently a private field. You can do some.. really hacky things to get closer to your goal but nothing like using the non-alpha mask on an image to cast shadows (yet) afaik.

    I was initially planning to use a preprocessed shape and just apply a polygon that way. I was intending to use this in the context of an animated sprite, so you'd need to update the polygon pretty often.

    I'll show you what you .. sorta can do. But this is not really all that great, and not performant, but it does sorta work.

    Since you can't really change the shadow shape programmatically (At least I couldn't do it) you can use System.Reflection to get the FieldInfo like this
    Code (CSharp):
    1. private ShadowCaster2D shadowCaster;
    2. private static BindingFlags accessFlagsPrivate =
    3.     BindingFlags.NonPublic | BindingFlags.Instance;
    4. private static FieldInfo meshField =
    5.     typeof(ShadowCaster2D).GetField("m_Mesh", accessFlagsPrivate);
    6. private static FieldInfo shapePathField =
    7.     typeof(ShadowCaster2D).GetField("m_ShapePath", accessFlagsPrivate);
    8. private static MethodInfo onEnableMethod =
    9.     typeof(ShadowCaster2D).GetMethod("OnEnable", accessFlagsPrivate);
    10.  
    Then in your Start() method you can do something like this
    Code (CSharp):
    1. shadowCaster = GetComponent<UnityEngine.Experimental.Rendering.Universal.ShadowCaster2D>();
    2. var somePathYouLoadedMaybe= new Vector3[]{
    3.   new Vector3(0,0,0),
    4.   new Vector3(0,1,0),
    5.   new Vector3(1,1,0),
    6. };
    7. shapePathField.SetValue(shadowCaster, somePathYouLoadedMaybe);
    8. meshField.SetValue(shadowCaster, null);
    9. onEnableMethod.Invoke(shadowCaster, new object[0]);
    10.  
    Here is that code running, makes a simple triangle:
    upload_2020-6-7_17-35-26.png

    I attempted to update this polygon with different values in the Update() & FixedUpdate() Methods and it basically made the game unplayable and slow.

    I am definitely curious to see if others have figured out something of more substance here.
     
    AzureMasters likes this.
  4. suxiangting

    suxiangting

    Unity Technologies

    Joined:
    Jun 12, 2020
    Posts:
    5
    That's a great suggestion regarding the use of sprite silhouettes for the Shadow Caster 2D! Thank you! It's certainly worth for us to look into. Let me feedback it to the 2D team.
     
    MaykeBr likes this.
  5. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    All this nonsense, because we are trying to come up with work arounds which is understandably in experimental stage.
    However, it doesn't mean that the demand isn't there for more robust update with 2DRenderer. In fact, it is the otherway around. I think there is high demand for the more frequent, robust update plan for 2DRenderer so that devs can plan ahead around the features it will bring/change. We can understand that we may have to wait, it is just that we don't know how long, for what features if any. I don't have problem with delay, but I do have issue with not knowing the plan, estimated schedules, information on what features to be implemented etc.. bottom line is the communication. Unity can all of sudden bomb us with "here is this new feature, just released it now go get it" but ideally, and unfortunately that is not the most of devs wants.
     
    Christor_8 and NotaNaN like this.
  6. suxiangting

    suxiangting

    Unity Technologies

    Joined:
    Jun 12, 2020
    Posts:
    5
    Thank you for your feedback, Castor! We definitely hear you there and understand your frustration of not knowing the upcoming features and their estimated schedules. I've already feedbacked this to the teams and it has been escalated to the appropriate members. We are now working towards greater transparency in our roadmaps so that our users would be the first to know of these new features and would also be able to share our excitement as we work hard towards the next releases. We will keep you posted on any updates as soon as we have them!
     
    castor76 likes this.
  7. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    Having worked at the large corp before, I do understand the fear of exposing the schedules and plans ahead because frankly anything can happen and the promise may not be met. But I feel that the community of Unity developers are much more forgiving and understanding than usual software retail customers because we ourselves are the developers. All we really want is to be able to ride the adventure together. Share the plan, share the dream, and we will rally behind it.
     
  8. suxiangting

    suxiangting

    Unity Technologies

    Joined:
    Jun 12, 2020
    Posts:
    5
    Yeah we are so glad you feel this way too! Anyway, adding on to what happened after I raised your suggestion to my team yesterday - they really do feel the need to make that public roadmap happen where we could show you guys the upcoming features, their statuses and the dates of our releases in advance. So they initiated to amplify your suggestion to the higher-ups first thing this morning today. We are really hoping to push something out and we are excited to see what we can do to make that happen.
     
    Saafris, AzureMasters and castor76 like this.
  9. Saafris

    Saafris

    Joined:
    Nov 22, 2017
    Posts:
    5
    Hi, sorry to revive a dead thread, but this feature is also very important to my project. Almost all of our assets are loaded at runtime, and it would be near impossible to define the sprite shapes for the shadow caster like this.
    Even an inaccurate shadow based on the pixels would be useful.

    Has there been any news of a roadmap so I can watch for a feature like this? Thank you very much
     
  10. Xiangting_Su

    Xiangting_Su

    Unity Technologies

    Joined:
    Sep 22, 2020
    Posts:
    253

    Yes! The discussion regarding 2D Shadow Caster using the Sprite pixel data has come up a few times now. More updates on this soon.

    It's not ready yet as far as I know but there has been initiatives to set one up soon.
     
  11. SuperSmithBros

    SuperSmithBros

    Joined:
    Jul 15, 2019
    Posts:
    4
    Using the reflection method @the_Simian suggested I wrote a helper class that can do this at runtime. @Saafris might be useful for you.

    The reason Simians approach becomes unplayable is because its infinitely generating meshes, if you watch your vert/tri count in the game window it'll keep getting larger until the FPS tank.

    The ShadowCaster2D class already forcefully re-generates its mesh in Update() when the shapeHash changes, I use reflection to set the points and then set the hash so the mesh rebuilds. Im not particularly knowledgeable about hash codes so I copied how its done for Sprite Shape Splines.

    Heres the full class, just add it to the same object as the ShadowCaster2D.

    Call UpdateShadowFromPoints() and pass it the array of points whenever you want the shadow to change or just call UpdateFromCollider() and it'll use the collider points instead.

    Code (CSharp):
    1.  
    2. using System.Reflection;
    3. using UnityEngine;
    4. using UnityEngine.Experimental.Rendering.Universal;
    5.  
    6. [RequireComponent(typeof(ShadowCaster2D))]
    7. [ExecuteInEditMode]
    8. public class ShadowCaster2DController : MonoBehaviour
    9. {
    10.     [SerializeField] private bool setOnAwake;
    11.     [HideInInspector, SerializeField] private ShadowCaster2D shadowCaster;
    12.     [HideInInspector, SerializeField] EdgeCollider2D edgeCollider;
    13.     [HideInInspector, SerializeField] PolygonCollider2D polyCollider;
    14.  
    15.     // Shadow caster fields to change
    16.     private readonly FieldInfo _shapePathField;
    17.     private readonly FieldInfo _shapeHash;
    18.  
    19.     private ShadowCaster2DController()
    20.     {
    21.         _shapeHash = typeof(ShadowCaster2D).GetField("m_ShapePathHash", BindingFlags.NonPublic | BindingFlags.Instance);
    22.         _shapePathField = typeof(ShadowCaster2D).GetField("m_ShapePath", BindingFlags.NonPublic | BindingFlags.Instance);
    23.     }
    24.  
    25.     private void Awake()
    26.     {
    27.         shadowCaster = GetComponent<ShadowCaster2D>();
    28.         edgeCollider = GetComponent<EdgeCollider2D>();
    29.         polyCollider = GetComponent<PolygonCollider2D>();
    30.  
    31.         if (!setOnAwake) { return; }
    32.  
    33.         if (edgeCollider != null)
    34.         {
    35.             UpdateShadowFromPoints(edgeCollider.points);
    36.         }
    37.         else if (polyCollider != null)
    38.         {
    39.             UpdateShadowFromPoints(polyCollider.points);
    40.         }
    41.     }
    42.  
    43.     /// <summary>
    44.     /// Updates the shadow based on the objects own collider
    45.     /// </summary>
    46.     public void UpdateFromCollider()
    47.     {
    48.         if (edgeCollider != null)
    49.         {
    50.             UpdateShadowFromPoints(edgeCollider.points);
    51.         }
    52.         else if (polyCollider != null)
    53.         {
    54.             UpdateShadowFromPoints(polyCollider.points);
    55.         }
    56.     }
    57.  
    58.     /// <summary>
    59.     /// Updates the shadow from an array of Vector3 points
    60.     /// </summary>
    61.     /// <param name="points"></param>
    62.     public void UpdateShadowFromPoints(Vector3[] points)
    63.     {
    64.         // Set the shadow path
    65.         _shapePathField.SetValue(shadowCaster, points);
    66.  
    67.         unchecked
    68.         {
    69.             // I have no idea what im doing with hashcodes but other examples are done like this
    70.             int hashCode = (int)2166136261 ^ _shapePathField.GetHashCode();
    71.             hashCode = hashCode * 16777619 ^ (points.GetHashCode());
    72.  
    73.             // Set the shapes hash to a random value which forces it to update the mesh in the next frame
    74.             _shapeHash.SetValue(shadowCaster, hashCode);
    75.         }
    76.     }
    77.  
    78.     /// <summary>
    79.     /// Updates the shadow from an array of Vector2 points
    80.     /// </summary>
    81.     /// <param name="points"></param>
    82.     public void UpdateShadowFromPoints(Vector2[] points)
    83.     {
    84.         // Set the shadow path
    85.         _shapePathField.SetValue(shadowCaster, Vector2ToVector3(points));
    86.  
    87.         unchecked
    88.         {
    89.             // I have no idea what im doing with hashcodes but other examples are done like this
    90.             int hashCode = (int)2166136261 ^ _shapePathField.GetHashCode();
    91.             hashCode = hashCode * 16777619 ^ (points.GetHashCode());
    92.  
    93.             // Set the shapes hash to a random value which forces it to update the mesh in the next frame
    94.             _shapeHash.SetValue(shadowCaster, hashCode);
    95.         }
    96.     }
    97.  
    98.     /// <summary>
    99.     /// Converts an array of Vector2 to an array of Vector3
    100.     /// </summary>
    101.     /// <param name="points"></param>
    102.     private Vector3[] Vector2ToVector3(Vector2[] vector2s)
    103.     {
    104.         Vector3[] vector3s = new Vector3[vector2s.Length];
    105.  
    106.         for (int i = 0; i < vector2s.Length; i++)
    107.         {
    108.             vector3s[i] = vector2s[i];
    109.         }
    110.  
    111.         return vector3s;
    112.     }
    113. }
    114.  
     
    Last edited: Dec 1, 2020
    NotaNaN likes this.
  12. vambier

    vambier

    Joined:
    Oct 1, 2012
    Posts:
    103

    Has this ever been implemented?
     
  13. Xiangting_Su

    Xiangting_Su

    Unity Technologies

    Joined:
    Sep 22, 2020
    Posts:
    253
    Hey @vambier, sorry for the delayed response.

    Yes our 2D Public Roadmap is now up and running for all five areas of our 2D feature-set: 2D foundations, world-building, animation, graphics and physics.

    Also, regarding the request for 2D Shadow Caster to use the Sprite pixel, that is being prioritised and someone on our team is already looking into it. So we will be posting more updates on our 2D Public Roadmap soon!
     
  14. vambier

    vambier

    Joined:
    Oct 1, 2012
    Posts:
    103

    Is this implemented yet? I can't find it in the 2d roadmap
     
  15. Xiangting_Su

    Xiangting_Su

    Unity Technologies

    Joined:
    Sep 22, 2020
    Posts:
    253
    Not yet but works on the shadow interoperability are already in R&D and are well underway in collaboration with the respective 2D feature areas.
     
  16. Inoc

    Inoc

    Joined:
    Dec 1, 2014
    Posts:
    7
    Any update on the sprite silhouette for the shadow caster? On the roadmap, we can see what has been released but not what is working on...
     
  17. Chris_Chu

    Chris_Chu

    Unity Technologies

    Joined:
    Apr 19, 2018
    Posts:
    257
    The major changes for shadows for 2023.1 are:

    ShadowCaster2D now can use sprites (including 2d animation, and flipbook), sprite shape, and colliders, or custom geometry as a source.

    2D Soft Shadows
     
  18. PanthenEye

    PanthenEye

    Joined:
    Oct 14, 2013
    Posts:
    2,127
    Hopefully that also includes shadow falloff distance.
     
  19. Chris_Chu

    Chris_Chu

    Unity Technologies

    Joined:
    Apr 19, 2018
    Posts:
    257
    23.1 doesn't. I want to add z for shadow casting at some point. That will do what I think you want, but in case it doesn't, do you have a screenshot of what you'd like to do?
     
  20. IvanNevesDev

    IvanNevesDev

    Joined:
    Jan 28, 2019
    Posts:
    27
    I
    Is this already available on some 2023.1 beta version? I'd really like to try it ou to see how it is working
     
  21. Chris_Chu

    Chris_Chu

    Unity Technologies

    Joined:
    Apr 19, 2018
    Posts:
    257
    Yes actually both features are in, but I'm still working on some known bugs mainly with the providers.

    Also I need to write up some docs
     
  22. PanthenEye

    PanthenEye

    Joined:
    Oct 14, 2013
    Posts:
    2,127
    I want a huge spotlight to simulate the sun in a sidescroller, but shadows are as long as the light's radius, so that's not possible right now. Alternatively, a new Directional Light could be introduced. Something akin to this but with optionally controllable shadow length per shadow caster:
     
    Last edited: Feb 18, 2023
  23. Zaknarfen

    Zaknarfen

    Joined:
    Jun 29, 2015
    Posts:
    4
    This makes no sense to me. How can I make the Shadow Caster 2D work?

    upload_2023-6-12_22-33-26.png

    Where can I link to the animated sprite?
     
  24. BacMan12

    BacMan12

    Joined:
    Apr 30, 2019
    Posts:
    3
    Has the docs been written? I need this bad XD
     
  25. BacMan12

    BacMan12

    Joined:
    Apr 30, 2019
    Posts:
    3
    Figured out it's in the 2023 version of unity, but I'm getting a memory leak error if I play the an animation with shadow caster attached
     
  26. Ijisthee

    Ijisthee

    Joined:
    Aug 30, 2014
    Posts:
    13
    Same here. But with 2023.02.x it works. Also with the polygon collider 2d as source.

    I've tried some approaches but nothing made me happy.

    I've tried to replace the polygonCollider2d on an object that has a composite collider attached, set the composite operation to merge but then the shadowCaster2d sets the source to "none" and there is no way to programmatically change that.

    This happens only with animations. Without animations it works fine.

    But when I use SpriteRenderer as source, I cannot set a kind of outline threshhold. It only generates a path with 10-20 points at runtime. Even if I set a custom physics shape at the image. It generates the shadow path based on the custom phyics shape, but only in editor, not at runtime after the animator replaced the image(s).

    I'm gonna try the approach from https://forum.unity.com/threads/can...urrent-sprite-silhouette.861256/#post-6576742