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

2D Lighting shadows

Discussion in '2D Experimental Preview' started by keirebirth, Feb 11, 2020.

  1. keirebirth


    Jul 6, 2019
    Is it possible to change the length of shadows. For example when you add a 2d point light to scene, the sprites shadows length extend to infinity and its not a desirable effect in a top down rpg. So is there any way you can change its length or do i have to create my own sprite shadows in this case. Thanks in advance.
    sicienss, sandstedt and tonytopper like this.
  2. undecyce


    Oct 17, 2019
    Same problem. I'm using a point light to simulate the sunlight, and the shadow just extend to infinity on everything.
    Hope they would add an attribute or something in the next update.
  3. Chris_Chu


    Unity Technologies

    Apr 19, 2018
    This is actually something I wanted to do, but I'm hesitant to add something official only because the shadows need to be reworked. If you wanted to make the changes yourself, I can try and give you some advice on how to do this.
    OldMage and NotaNaN like this.
  4. undecyce


    Oct 17, 2019
    Thx for the reply.
    I was wondering if there is any script or shader way to make it, would you like to give me some advice?:)
  5. MrPaparoz


    Apr 14, 2018
    Maybe for meantime there should be a personal refactor of yours that we can fiddle more into? I am interested in this also.
    tonytopper likes this.
  6. EgorMahurin


    Nov 23, 2017
    Also looking for a solution
    tonytopper and vals261 like this.
  7. castor76


    Dec 5, 2011
    It has been some time since 2drenderer team has responded to the feedbacks since the last official demo. We would like to see some respond to :

    1. Shadow support for tilemap
    2. Soft Shadow
    2. Missing Emission channel
    3. Adjustable shadow length
    4. Directional light type
    5. Self-Shadow is practically not usable due to its inaccuracy with the source sprite

    And for the last but not least, the way the light layer works, because 2drenderer is rendering light buffer per layer it is affecting it, this is far too performance consuming. Maybe there can't be anything about this, but still..
    Deksover, Kretoskar, AlejMC and 5 others like this.
  8. Kretoskar


    Mar 15, 2019
    Bump. I'm also stuck with it
  9. JoaoSantos


    Mar 31, 2014
    I manipulated the FreeForm of the 2D Light to create a polygon in the limits of the collision enter.

    But its doesn't the better solution of my problem, because I want use the properties existentes in the Point type, for example.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Experimental.Rendering.Universal;
    6. # if UNITY_EDITOR
    7. using UnityEditorInternal;
    8. # endif
    10. [ExecuteAlways]
    11. [RequireComponent(typeof(Light2D))]
    12. public class Light2DAdaptative : MonoBehaviour
    13. {
    14.     [Header("Custom Attributes")]
    15.     [SerializeField]
    16.     [Min(3)]
    17.     private int sides = 4;
    19.     [SerializeField]
    20.     [Min(0.01f)]
    21.     private float radius = 1f;
    23.     [SerializeField]
    24.     [Range(0, 359)]
    25.     private int angle = 45;
    27.     [SerializeField]
    28.     private LayerMask layersFilter;
    30.     [Header("Base Attributes")]
    32.     [SerializeField]
    33.     [Min(0)]
    34.     private int lightOrder = 0;
    36.     [SerializeField]
    37.     [ColorUsage(false)]
    38.     private Color color = Color.white;
    40.     [SerializeField]
    41.     [Range(0, 1f)]
    42.     private float shadowIntensity = 0f;
    44.     private Light2D currentLight;
    46.     public Light2D Light
    47.     {
    48.         get
    49.         {
    50.             if (this.currentLight == null)
    51.             {
    52.                 this.currentLight = GetComponent<Light2D>();
    53.                 this.currentLight.lightType = Light2D.LightType.Freeform;
    54.             }
    55.             return this.currentLight;
    56.         }
    57.     }
    59.     private void OnValidate()
    60.     {
    61.         ChangeProperties();
    62.         TryResizeLight();
    63.     }
    65.     private void OnEnable()
    66.     {
    67. #if UNITY_EDITOR
    68.         ComponentUtility.MoveComponentUp(this);
    69. #endif
    70.         TryResizeLight();
    71.     }
    73.     private void Update()
    74.     {
    75.         TryResizeLight();
    76.     }
    78.     private void ChangeProperties()
    79.     {
    80.         Light.lightOrder = this.lightOrder;
    81.         Light.color = this.color;
    82.         Light.shadowIntensity = this.shadowIntensity;
    83.     }
    85.     private void TryResizeLight()
    86.     {
    87.         var lightNaturalPoints = this.Light.shapePath.Length;
    89.         if (this.sides != lightNaturalPoints)
    90.         {
    91.             this.sides = lightNaturalPoints;
    92.             Debugs.Log("Create or reduce more points in Freeform light 2d component to see the correct draw form");
    93.         }
    95.         ResizeLight();      
    96.     }
    98.     private void ResizeLight()
    99.     {
    100.         var localRadius = this.radius;
    102.         var sides = this.sides;
    103.         var baseAngle = Mathf.PI * 2 / sides;
    105.         var offsetAngle = Mathf.Deg2Rad * this.angle;
    107.         for (int i = 0; i < sides; i++)
    108.         {
    109.             var localAngle = baseAngle * i;
    110.             var position = new Vector3(Mathf.Cos(localAngle + offsetAngle), Mathf.Sin(localAngle + offsetAngle), 0f) * localRadius;
    112.             RaycastHit2D value = Physics2D.Raycast(transform.position, position, localRadius, this.layersFilter);
    114.             var relativePosition = transform.localPosition;
    115.             if (value.collider != null)
    116.             {
    117.                 Vector3 transportPoint = transform.InverseTransformPoint(value.point);
    118.                 relativePosition += transportPoint;
    119.             }
    120.             else
    121.             {
    122.                 relativePosition += position;
    123.             }
    125.             this.Light.shapePath[i] = relativePosition;
    126.         }
    128.     }
    130. }

    With that, I can manipulate the polygon precision, changing the side number. With that, I can change the shadow, because I don't project the light in the wall. I create a custom polygon that create the light until the wall.

    - I have errors with that, when the light throut the wall collider
  10. Encon21


    Nov 27, 2018
    I know this is a bit of an old topic but could you give some hints as to where to start with something like this? I tried looking into it myself but ended up a bit lost; I plan to dig into it a bit more soon but would appreciate the help in getting started, or even a small sample project/script if possible as MrPaparoz mentioned.

    The current 2D lighting support seems extremely limited in where it would be applicable, and offering a way to limit the shadow length would go a long way in improving its usability for top-down games (and other projects). The game I'm working on at the moment is an open world top-down sandbox/RPG, and having dynamic shadows would be a huge help in making the world feel more "alive" (something that's a pretty big focus in this game). Unfortunately having a pot cast an infinite shadow would be incredibly immersion breaking, but having it not cast a shadow at all while taller objects (like trees) do just makes everything feel disjointed.

    Not having any way to make the sun cast shadows really limits its usefulness as well; the entire world looks flat unless the player is forced to always be carrying a torch (which doesn't make sense given the presence of a day/night system), and using a large light just outside of the camera as a fake sun doesn't work because all that does is cast a bunch of infinite shadows.

    While I understand it would be a lot of work to implement, I do think a rework of the shadows makes sense; to be honest even aside from my current project, I have a hard time thinking of any way to ever use the current setup without a) limiting myself to only tall objects of simple shapes (pillars, perfectly straight trees, etc) where infinite shadows make sense (too simplistic/limited of a game world) or b) using it exclusively for line of sight (preventing players from seeing what's around the corner) which I could do without lighting/shadows anyway. In all other use cases I can think of (even outside of top-down games) the current shadows just wouldn't cut it, because the only two options are "no shadow" and "infinite shadow" with nothing in between.

    Some features I'd love to see:
    -Allow setting a shadow length per object as suggested in this topic (bare minimum to make it usable imo)
    -Ambient/sun shadows (give the object a "height" value, give the global light a "sun direction" value, small shadows are cast based on object's height value and the time of day)
    -A "height" value for both shadow casters and light sources; this would be a better way of implementing shadow lengths (and perhaps integrated with ambient/sun shadows as well by giving the sun/global light a height value), for example if an object has a height of 2 and the player's torch has a height of 5, the shadow is shorter depending on how close the player is, and if the object has a height of 10, the shadow is infinite
    -Some way to provide an actual shape for the shadow being cast? For example an additional texture that could be stretched/skewed depending on light direction/height values, so more complex shapes could have more realistic shadows (so a dead tree's shadow could show the branches as well etc); this would be the Holy Grail imo, though I'm not sure it would even be possible to implement in a way that worked well across various use cases and/or performed well

    The first two features would be enough to meet the needs of my current project (preferably implemented using the 3rd idea for more control over how it works, and more realism when multiple light sources exist at different heights like street lamps vs torches), and would make the 2D lighting support a lot more widely viable than I think it is currently. The last idea likely isn't possible/practical to implement but I figured I'd throw it out there anyway just in case (it would be pretty cool to have "3D"/shaped shadows in a 2D project).

    This ended up being a longer post than I meant it to be (oops), but dynamic lighting is something I'd love to use for a lot of the game ideas I have, and it'll likely be some time before I'm able to work on 3D projects, so seeing some improvements to the 2D Lighting system (or at least having a better idea of where to start in making a custom one) in the meantime would be great.
    NotaNaN likes this.
  11. halagame


    Jan 14, 2020
    bump, I'm also looking for to set the shadow caster 2D with height
    anyone has any ideas how to make this? tks
  12. tonytopper


    Jun 25, 2018
    There are actually two other threads expressing interest in a solution to this hurdle.

    I was wondering if some sort of clipping code might be the easiest way to create a workaround.

    ShadowCaster2D needs some love. Interesting to hear it needs reworking because there isn't too much there, at the surface anyway. For example, even the _shapePathField is hidden and I had to use reflections to change the value.
    NotaNaN likes this.
  13. Braza


    Oct 11, 2013
    I think there's was a capability to vote for improvements somewhere on the site. Would that help to bump the internal priority of this?
  14. NotaNaN


    Dec 14, 2018
    You are correct. ;)

    As far as the responses from other Unity departments I have talked to, they have said: 'yes, this is the best way to signal a feature's priority to us' (or something along the lines of that).

    Everybody, send your feature requests! :D
  15. castor76


    Dec 5, 2011
    I have submitted mine for :

    Emissive Channel
    Tilemap Shadow (soft)
    Ability to write to both Normal and Light buffer
    NotaNaN likes this.
  16. Devilbro


    Feb 28, 2020
    you can check out the urp codes, and find the _ShadowRadius parameter which current decided by lights' bounding sphere. I'm trying to add some data into the shadow mesh and change this value in "Hidden/ShadowGroup2D", this should work
  17. MaximPP


    Jan 26, 2019
    I have a top view game and also need to limit the length of the shadow (i.e. the "height" of the sprite casting the shadow)
  18. Chris_Chu


    Unity Technologies

    Apr 19, 2018
    I'll look into this next week
  19. KinuxUnity


    Dec 4, 2015
    any news about this ?
    tonytopper likes this.
  20. DragonByte


    Sep 30, 2012
    I'm also interested in shadow length.
  21. Chris_Chu


    Unity Technologies

    Apr 19, 2018
    Sorry, I was really ill for the last couple weeks. I need to catch up on a few work things, and I'll look into this again. But just to temper expectation, I can't promise what I will be able to deliver.
    toonslab2 and NotaNaN like this.
  22. Chris_Chu


    Unity Technologies

    Apr 19, 2018
    So I looked into this and tried some ideas out. There are issues with the shadow casting geometry that prevent this from working well.

    I have changed the shadow geometry generation in my current work but that work may not be compatible with 2022 and earlier. I'll give this another go when I get the chance to separate and modify that change so it is compatible, but I don't know when that will be.
    MaximPP, KinuxUnity and NotaNaN like this.
  23. badcceb


    Jan 26, 2022
    Hello All - after an entire weekend of searching, I have found a solution to the shadow length issue. There is an article in Mandarin (I believe, but not sure) with a developer/coder who managed to edit the scripts for the Universal Renderer Pipeline to make the shadow length editable (using a slider). Here is a link to the article:
    I have to say, it took me HOURS to work through the changes that needed to be made, because what they have posted doesn't work right away (must have been some changes made since they wrote their article) BUT I have managed to make it work. I will post how I made it work in a little bit, but suffice to say, this coder/developer is a genius, and I am so happy I was able to take their efforts, play with them and make it work! To clarify - I did NOT continue on with the tutorial to alter the falloff, etc. - I only made the editable shadow length work using a slider. Look at the photos, and you will see the shadow length decrease as the "Shadow Radius" slider is moved! AMAZING!

    Attached Files:

    Last edited: Aug 26, 2022
  24. badcceb


    Jan 26, 2022
    Alright, for all those this will help, I will give a short description of how I made the edits to the URP scripts work to shorten the length of the 2d (infinite) shadows:

    This assumes that you have some knowledge/skill in editing scripts, and also assumes that you have URP loaded into your project.

    1) Go to your Unity project->Library->Packagecache and find the two folders: com.unity.render-pipelines.core@[versionnumber] and com.unity.render-piplines.universal@[versionnumber], and cut and paste them into the folder: Unity project->Packages.

    2) Using whatever script editor you work with, open the following scripts (all found in the folders you just moved): Light2D.cs, Light2DEditor.cs, ShadowRendering.cs.

    3) Now, we edit the scripts:

    Light2D.cs - Changes:

    a) Go through the script and find the area where m_ShadowIntensity and m_ShadowVolumeIntensity are outlined. Add the following:
    [SerializeField] float m_ShadowRadius = 1.42f);

    b) Then, move down to where "Public LightType lightType" is listed (don't post IN this function, but UNDER/OUTSIDE this function - I really don't think it matters too much where you post it, I just posted where similar variables were located), and under that, add the following: public float shadowRadius { get => m_ShadowRadius; set => m_ShadowRadius = value; }

    Close and save Light2d.cs

    Light2DEditor.cs - Changes

    a) Go through the script until you find "private static class Styles", and within this function, add the following:
    public static GUIContent generalShadowRadius = EditorGUIUtility.TrTextContent("Shadow Radius");

    b) Move down the script til you find the section where there are a bunch of SerializedProperty variables, and add the following: SerializedProperty m_ShadowRadius;

    c) Go to the "OnEnable" function, and add the following:
    m_ShadowRadius = serializedObject.FindProperty("m_ShadowRadius");

    d) Go the "DrawSpotLight" function (I only added the slider to my SpotLight, but I am sure you can add the slider to the other lights by including this line of code in their draw functions), and add the following:
    EditorGUILayout.Slider(m_ShadowRadius, 0, 1.42f, Styles.generalShadowRadius);

    Close and save Light2DEditor.cs.

    ShadowRendering.cs - Changes

    a) Look through the script until you find the function "Public Static Bool RenderShadows", and then under the "if (hasShadow)" section, look for "var shadowRadius" and edit the code so that it reads: var shadowRadius = light.shadowRadius * light.boundingSphere.radius;

    Close and save ShadowRendering.cs.

    That's it! Load up your project, add a spotlight (or other NON-GLOBAL light), enable shadows, and use the "shadow radius" slider to alter the length of the shadow! HUGE THANK YOU to "ERGEXH", whoever you are, for the amazing work you did! This is the link to the original article, and the poster continues by adding a bunch of additional features, but I stopped with just slider for the shadow length!

    Last edited: Aug 21, 2022
  25. DavidNLN


    Sep 27, 2018
    @Chris_Chu Any updates on this? it's been over a year since this thread started and it's not even in the roadmap :(
  26. Lasutriv


    Dec 29, 2017
    @badcceb Sweet! Thanks for the update. Definitely going to try this out and may give feedback on my use cases and quirks.
    badcceb likes this.
  27. badcceb


    Jan 26, 2022
    So, having experimented with the shadow lengthening, there's a couple things I have noticed: 1) The geometry on the shadows becomes broken - I don't think altering the shape of the geometry of the shadowcaster2d does much other than determining the position of the shadow. I don't mind this so much because I am doing an overhead game, which doesn't call for too detailed shadows (a blob under their feet works for me), but it could be an issue if you want detailed shadows that correspond to the model casting the shadow; 2) All the shadows are the same length! I have trees, rocks, player model, characters, etc., and they are all the same length, which is an issue! Luckily, later in the article, they dealt with this issue specifically by adding a shadow length slider to the shadowcaster2d, which allows you to set a specific ratio of length for each shadowcaster2d. Which is nice. Again, it took a bit of fiddling, but I managed to make it work. If anyone is interested, here is how to do so: Open the following scripts (found in your UnityProject->Packages folder: ShadowCaster2D.cs, ShadowCaster2DEditor.cs and ShadowRendering.cs.

    ShadowCaster2D.cs - Changes

    a) Do a search or look to find where there are a bunch of [SerializeField] variables. Add the following: [SerializeField] [Range(0, 1f)] float m_ShadowLength = 1;

    b) Scroll down a bit in the script until you find where a bunch of public bool variables with get/set functions are located, and add the following:
    public float shadowLength
    get => m_ShadowLength;
    set => m_ShadowLength = value;

    Close and save ShadowCaster2D.cs.

    ShadowCaster2DEditor.cs - Changes

    a) Search or scroll until you find "public static class Styles", and add the following: public static GUIContent shadowLength = EditorGUIUtility.TrTextContent("Shadow Length");

    b) Just below are a few [SerializeField] variables - add the following: SerializedProperty m_ShadowLength;

    c) Search or scroll until you find "public void OnEnable()", and add the following: m_ShadowLength = serializedObject.FindProperty("m_ShadowLength");

    d) Search or scroll until you find "public override void OnInspectorGUI()" and add the following: EditorGUILayout.Slider(m_ShadowLength, 0, 1f, Styles.shadowLength);

    Close and save ShadowCaster2DEditor.cs.

    ShadowRendering.cs - Changes

    a) Search or scroll until you find "public static bool RenderShadows(...)" (same spot, if you followed my previous post, where we altered the shadowRadius variable), and then under the "if (hasShadow)" statement, look for the "for" loop ("for (var group = 0; group < shadowCasterGroups.Count; group++)") and find the last nested if statement ("if (shadowCaster.castsShadows)") and you will see three (3) "cmdBuffer.DrawMesh(...)" statements. Add to them the following: cmdBuffer.SetGlobalFloat("_ShadowRadius", shadowRadius * shadowCaster.shadowLength);

    Close and save ShadowRendering.cs.

    And that's it! Now, you can set the shadow length on the (non-global) light, while also being able to set the shadow length on each individual shadowcaster2d. I highly recommend adding this functionality to the URP system.

    Please let me know if anyone has any issues or questions!
    Last edited: Aug 28, 2022
  28. Drummer24


    Jan 20, 2017
    Hi what URP Version did you use? Because in ShadowRendering.cs there is no "if (hasShadow)" for me.

    Edit: Used an old version of Unity. In the new one it's there
    Last edited: Aug 30, 2022
    badcceb likes this.
  29. driussijoaquin


    Mar 4, 2022
    thank you so much @badcceb, i have a problem tho, i did everything precisely, but when changing an object's shadow length, the slider is affecting another object in the scene with the same component, why could this be happening? cheers and thanks
  30. badcceb


    Jan 26, 2022
    Hey! Sorry for the late reply - I haven't checked in for a while. Just to clarify: are you talking about the slider on the light source or the slider on the shadowcaster? If it is the slider on the light source, then it is supposed to change the shadow length for ALL of the objects in the scene that have a shadowcaster2d on them. However, if you are experiencing the slider on an individual/unique shadowcaster2d component (on an object) changing the shadow length on another object ,then that is a totally different issue ,and off the top of my head I don't know what the cause would be. Please clarify, and I will do my best to help sort it out. :)
  31. Wijolt


    Nov 12, 2021
    @driussijoaquin, move "cmdBuffer.SetGlobalFloat("_ShadowRadius", shadowRadius * shadowCaster.shadowLength);" on the top of other cmdBuffers.
    @badcceb, It would be very nice to see other features that were in the original article, like the fade effect and the correct display of the shape of the shadow.
    Neil-Corre and badcceb like this.
  32. audiodreadofficial


    Aug 10, 2021
    I managed to figure out how to get a fade effect with a lot of trial and error.

    1. open Light2D.Point.shader
    2. at the bottom of the script you can find the lines:
      APPLY_NORMALS_LIGHTING(input, lightColor);
      APPLY_SHADOWS(input, lightColor, _ShadowIntensity);
    3. in between those two lines put:
      _ShadowIntensity = saturate(_ShadowIntensity - ((5 - (attenuation * 5 )) * -_FalloffIntensity));
    Those two arbitrary values of 5 are important, the first one controls the rate of the falloff, and the second on controls the intensity of the falloff, I followed the steps in the above instructions to add serialized sliders for those values, however I couldn't work out how to communicate those slider values to the shader. In fact I couldn't work out how ANY values are being communicated to the shader. I'm going to keep digging into it but if anyone else has an answer or can figure it out I'd greatly appreciate the help.
    Neil-Corre, Lasutriv and badcceb like this.
  33. audiodreadofficial


    Aug 10, 2021
    ALRIGHT I figured it out. Through a lot of trial and error I found how to cast your own variables into the shader.

    1. Follow the above steps but replace the 5s in step 3 with undeclared variables
      _ShadowIntensity = saturate(_ShadowIntensity - ((_ShadowFalloffRate - (attenuation * _ShadowFalloffIntensity )) * -_FalloffIntensity));
      (any lighting in the scene will break and you'll get errors, don't panic the next steps will fix it)
    2. Open LightingUtility.hlsl
      find #define SHADOW_VARIABLES under line 51 and add:

      float _ShadowFalloffRate;\
      float _ShadowFalloffIntensity;\

      somewhere under that line.
    3. in Light2D.cs find where all of the SerializeField variables are (I just put it under the m_ShadowRadius variable) add:

      [Range(0, 10f)]
      [SerializeField] float m_shadowFalloffRate = 1;
      [Range(0, 10f)]
      [SerializeField] float m_shadowFalloffIntensity = 1;

      then find the public get set variables (again I put it under shadowRadius) and add:

      public float shadowFalloffRate { get => m_shadowFalloffRate; set => m_shadowFalloffRate = value; }
      public float shadowFalloffIntensity { get => m_shadowFalloffIntensity; set => m_shadowFalloffIntensity = value; }

    4. in ShadowRendering.cs in the first section of the class add:

      private static readonly int k_ShadowFalloffRateID = Shader.PropertyToID("_ShadowFalloffRate");
      private static readonly int k_ShadowFalloffIntensityID = Shader.PropertyToID("_ShadowFalloffIntensity");

      then find the method SetGlobalShadowTexture and add the lines:

      cmdBuffer.SetGlobalFloat(k_ShadowFalloffRateID, light.shadowFalloffRate);
      cmdBuffer.SetGlobalFloat(k_ShadowFalloffIntensityID, light.shadowFalloffIntensity);

    5. finally in Light2DEditor.cs under the class Styles add the lines:

      public static GUIContent generalshadowFalloffRate = EditorGUIUtility.TrTextContent("Shadow Falloff Rate");
      public static GUIContent generalshadowFalloffIntensity = EditorGUIUtility.TrTextContent("Shadow Falloff Intensity");

      beneath the class find where all of the SerializedProperties are stored and add:

      SerializedProperty m_shadowFalloffRate;
      SerializedProperty m_shadowFalloffIntensity;

      in OnEnable add:

      m_shadowFalloffRate = serializedObject.FindProperty("m_shadowFalloffRate");
      m_shadowFalloffIntensity = serializedObject.FindProperty("m_shadowFalloffIntensity");

      in the method DrawSpotLight add:

      EditorGUILayout.Slider(m_shadowFalloffRate, 0, 10f, Styles.generalshadowFalloffRate);
      EditorGUILayout.Slider(m_shadowFalloffIntensity, 0, 10f, Styles.generalshadowFalloffIntensity);

      you should now be able to control the gradient of all of the shadows under the light. I'm going to figure out how to control it from the individual shadow casters next and then move on to the uniform direction. I'll keep updating here as I do and once all of it is done I'll make a YouTube tutorial on how to set up everything at once (crediting everyone involved of course)
  34. audiodreadofficial


    Aug 10, 2021
    A couple minor improvements to the shadow gradient:

    in the Light2D-Point.shader under the line:

    attenuation = attenuation * spotAttenuation;


    half attenuationOverride = attenuation;

    Then add two new variables to the shader, one which is linked to our shadow radius value, and one called shadow intensity multiplier which is a float between 0 and 1 (I think the previous posts have outlined the process on adding new variables well enough and I'm feeling too lazy to write it all out again haha. Just follow the same stesp as shadow falloff intensity and shadow falloff rate.)
    badcceb likes this.
  35. audiodreadofficial


    Aug 10, 2021
    I'm onto the light position offset tools (these are incredibly useful for my game as I needed to simulate the sun in an outdoor environment... The original reason I found this thread)

    In light2D.cs add a couple new variables and properties as usual:

    [SerializeField] float m_LightPositionOffsetAngle;
    [SerializeField] float m_LightPositionOffsetRadius;

    public float lightPositionOffsetAngle { get => m_LightPositionOffsetAngle; set => m_LightPositionOffsetAngle = value; }
    public float lightPositionOffsetRadius { get => m_LightPositionOffsetRadius; set => m_LightPositionOffsetRadius = value; }

    in Light2DEditor.cs follow the same steps as with previous changes.

    In the Styles class add:

    public static GUIContent lightPositionOffsetAngle = EditorGUIUtility.TrTextContent("ShadowCaster Center Offset Angle");
    public static GUIContent lightPositionOffsetRadius = EditorGUIUtility.TrTextContent("ShadowCaster Center Offset Radius");

    then with the other SerializedProperty variables add:

    SerializedProperty m_LightPositionOffsetAngle;
    SerializedProperty m_LightPositionOffsetRadius;

    then in OnEnable add:

    m_LightPositionOffsetAngle = serializedObject.FindProperty("m_LightPositionOffsetAngle");
    m_LightPositionOffsetRadius = serializedObject.FindProperty("m_LightPositionOffsetRadius");

    lastly in DrawSpotLight add:

    EditorGUILayout.Slider(m_LightPositionOffsetAngle, -180f, 180f, Styles.lightPositionOffsetAngle);
    EditorGUILayout.PropertyField(m_LightPositionOffsetRadius, Styles.lightPositionOffsetRadius);

    All of this has been directly from the article, the big change comes in the last step. The script location and the name of the shader property have both been changed in newer Unity versions.

    Find and open ShadowRendering.cs

    At the top of the script you should find a variable named:

    private static readonly int k_LightPosID = Shader.PropertyToID("_LightPos");

    in the parenthasis change "_LightPos" to "LightPosition"

    in the PrerenderShadows class find the if statement:

    if (RenderShadows(pass, renderingData, cmdBuffer, layerToRender, light, shadowIntensity, m_RenderTargets[textureIndex].Identifier(), colorChannel))

    add curly brackets to the if statement and above:

    m_LightInputTextures[textureIndex] = m_RenderTargets[textureIndex].Identifier();


    Vector3 offset = new Vector3(Mathf.Cos(light.lightPositionOffsetAngle * Mathf.Deg2Rad), Mathf.Sin(light.lightPositionOffsetAngle * Mathf.Deg2Rad), 0);
    cmdBuffer.SetGlobalVector("_LightPos", light.transform.position + offset * light.lightPositionOffsetRadius);

    Next I'm going to work on the shadowcaster specific controls for the gradient, and controlling the outside angle which should cover everything. Once it's done I'll create a video tutorial for YouTube to make everything a bit easier to follow along with.


    I looked into it for about half an hour and I can't be bothered to figure this one out. The current controls work perfectly for my purposes and no version of the shader modified in the article exists anymore. If anyone can find me the script where the triangles for the 2D shadows are currently being calculated then I will absolutely make another post about how to do the angle controls, otherwise I'm going to make a video with everything I have so far and come back to it whenever I have that information.
    Last edited: Jan 30, 2023
    badcceb and Christor_8 like this.
  36. Happy-Bloberfish


    Mar 4, 2023
    ShadowRendering.cs - Changes

    a) Search or scroll until you find "public static bool RenderShadows(...)" (same spot, if you followed my previous post, where we altered the shadowRadius variable), and then under the "if (hasShadow)" statement, look for the "for" loop ("for (var group = 0; group < shadowCasterGroups.Count; group++)") and find the last nested if statement ("if (shadowCaster.castsShadows)") and you will see three (3) "cmdBuffer.DrawMesh(...)" statements. Add to them the following: cmdBuffer.SetGlobalFloat("_ShadowRadius", shadowRadius * shadowCaster.shadowLength);

    On this part mine doesn't have the 3 cmdBuffer.DrawMesh.

    In fact I think it have none.

    if (hasShadow)
    cmdBuffer.SetRenderTarget(renderTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
    using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadowColorsLookup[0]))
    cmdBuffer.ClearRenderTarget(RTClearFlags.All, Color.clear, 1, 0);
    var shadowRadius = light.shadowRadius * light.boundingSphere.radius;
    cmdBuffer.SetGlobalVector(k_LightPosID, light.transform.position);
    cmdBuffer.SetGlobalFloat(k_ShadowRadiusID, shadowRadius);
    cmdBuffer.SetGlobalFloat(k_SoftShadowAngle, Mathf.Deg2Rad * light.shadowSoftness * k_MaxShadowSoftnessAngle);
    var projectedShadowMaterial = pass.rendererData.GetProjectedShadowMaterial();
    var projectedUnshadowMaterial = pass.rendererData.GetProjectedUnshadowMaterial();
    var spriteShadowMaterial = pass.rendererData.GetSpriteShadowMaterial();
    var spriteUnshadowMaterial = pass.rendererData.GetSpriteUnshadowMaterial();
    var geometryShadowMaterial = pass.rendererData.GetGeometryShadowMaterial();
    var geometryUnshadowMaterial = pass.rendererData.GetGeometryUnshadowMaterial();
    for (var group = 0; group < shadowCasterGroups.Count; group++)
    var shadowCasterGroup = shadowCasterGroups[group];
    var shadowCasters = shadowCasterGroup.GetShadowCasters();
    if (shadowCasters != null)
    // Draw the projected shadows for the shadow caster group. Only writes the composite stencil bit
    RenderProjectedShadows(cmdBuffer, layerToRender, light, shadowCasters, projectedShadowMaterial, 0);
    // Render self shadowing or non self shadowing
    RenderSelfShadowOption(cmdBuffer, layerToRender, light, shadowCasters, projectedUnshadowMaterial, spriteShadowMaterial, spriteUnshadowMaterial, geometryShadowMaterial, geometryUnshadowMaterial);

    I have no clues where to put the last line.
  37. FelinaLain


    Aug 21, 2013
    Does anyone have any way of doing this without having to dig into the package files?
    Or do we know if Unity teams have any update planned on the subject?
  38. DavidNLN


    Sep 27, 2018
    Unfortunately the 2d team as been quite silent for a while, they do release some bug fixes for the shadow system (look at the latest path notes) but they have been pretty much ignoring this thread for a while now.

    For now, you are better off using a third party library for 2d lights and shadows
  39. Brebretibby


    Oct 24, 2022
  40. audiodreadofficial


    Aug 10, 2021
    Can you post a picture of your code? Also what Unity version?
  41. ilcane87


    Apr 29, 2022
    @badcceb @audiodreadofficial @Happy-Bloberfish etc...
    All this sounds like something that could become useful to a lot of people, but the way it's been talked about so far (open file X, change line Y, and so on) is not practical and error prone, it would be very welcome if you could post the modified files for people to download.
    I know that base scripts may differ slightly between Unity versions, but having the full working examples on hand would go a long way in avoiding misunderstandings, and could also more easily be checked for 'diff' with the same version base files.
  42. sicienss


    Jun 27, 2018
    Thank you to everyone who worked on this problem and proposed solutions. I followed the method described above to achieve a nice fade.


    But I would love to be able to control this on the ShadowCaster2D rather than on the Light2D.

    Does anyone know how to extend this method so that the value can be set per ShadowCaster2D?

    I tried adding fields to control falloff rate and falloff intensity to ShadowCaster2D and ShadowCaster2DEditor, then exposed the following in LightingUtility.hlsl

        float _ShadowCasterShadowFalloffRate;\
    float _ShadowCasterShadowFalloffIntensity;\

    And finally added these lines to ShadowRendering.RenderShadows() in the usual spot (having first defined and set k_ShadowCasterShadowFalloffIntensityID and k_ShadowCasterShadowFalloffRateID):

    cmdBuffer.SetGlobalFloat(k_ShadowCasterShadowFalloffIntensityID, shadowCaster.shadowFalloffIntensity);
    cmdBuffer.SetGlobalFloat(k_ShadowCasterShadowFalloffRateID, shadowCaster.shadowFalloffRate);

    But it doesn't seem to work. I can get shadow gradients to change, but it still seems based on the distance from the light. Further, shadows cast by different ShadowCaster2Ds all change when the fields are changed on one of them.
    Last edited: May 7, 2023
    audiodreadofficial likes this.
  43. audiodreadofficial


    Aug 10, 2021
    That's a really good point. I'll compile my files and post them tomorrow.
  44. audiodreadofficial


    Aug 10, 2021
    Your code isn't working because it's still being hooked into the "global" or light settings rather than the shadowcaster settings. I'm not smart enough to figure out if the current way 2D shadows work even allows for instanced shadow gradients, my solution is still imperfect in that it takes in the light gradient which means it'll always be effected by distance and size of the light. I might revisit this at some point and see if I can find a solution that doesn't rely on the size and position of the light at all, which would allow for instancing across different shadow casters, but I'm not sure if I'll be able to figure that out.
  45. plusplusgames


    Jul 26, 2021
    oh this is going to be hard isnt it