Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Small movements of directional light produce oscillating shadows

Discussion in 'General Graphics' started by AlTheSlacker, Mar 26, 2021.

  1. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    I initially thought this was a HDRP issue:
    https://forum.unity.com/threads/sha...ency-with-rotating-directional-light.1081928/

    But I now find it is a general problem, so I have posted here hoping for some insight.

    When rotating a directional light by small amounts the shadows become noisy, oscillating about an average position. The attached package replicates the problem. I was trying to move a directional light to represent the rotation of the sun. I'm tempted to think this is a floating point precision issue as the angle of the light approaches 90 degrees, but it seems such a basic requirement to have a moveable sun I'm assuming I have made a mistake.
     

    Attached Files:

  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    You’re seeing aliasing artifacts. The same aliasing artifacts you’ll see if you were to slowly rotate a camera around a position with no anti-aliasing enabled. The way Unity does shadows doesn’t support any anti-aliasing techniques beyond blurring them which only really helps to hide the artifacts when the light isn’t moving. There’s not really anything you can do to fix the problem either. Big AAAA games have exactly the same problem. A few will sidestep it a bit by moving the sun direction in steps, either snapping to a new direction or quickly lerping, and then staying still for a while. Some don’t actually move the sunlight direction at all and just change the color to give the impression of time of day changes!
     
    arkano22 likes this.
  3. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    I just took a look at Valheim, which I believe is using Unity, and whilst they have a *very* small amount of aliasing on the shadow edge, they seem to be able to produce a continuously moving, smooth shadow from their sun, with the shadow cast from both static and dynamic objects, so it is possible. I wonder what their strategy was?

    Whilst I am happy to accept just about everyone on the planet has more knowledge about this than me, I didn't see my issue so much as aliasing as the line of the shadow not moving consistently with the light - it seemed like an unexpectedly large amount of movement back and forth, almost as if the shadow was either being cached or the light position rounded to the nearest half degree in an inconsistent direction.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    I tried grabbing that package and using it with the default 2020.3 HDRP scene ... and it fails fairly spectacularly. Not the shadows mind you, unpacking the package itself into the project results in the scene being basically deleted because it uses the same GUID as the one in the default HDRP package which is a no-no.

    Grabbing only the script from the package and assigning it to the main direction light (along with setting said light to be fully real time, etc.) resulted in no obvious artifacts even when changing the increment to something super tiny like 0.00001. At least no artifacts beyond the aliasing I expected to see. The only significant difference I noticed is the HDRP blends between shadow cascades using a noisy transition which the built in renderer does not, though this really only appears in the scene view as the temporal anti-aliasing cleans this up in the game view.
    upload_2021-3-30_11-23-6.png

    Can you capture a short video of the artifact you're seeing?
     
  5. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Thank you so much for testing this bgolus.

    I think you got the HDRP GUID clash as I made a non-HDRP package for this forum, so if you had created a HDRP project and imported my package from this forum I can see how that may have gone wrong. Sorry for any confusion.

    It's very interesting that you did not see the problem. I wonder, perhaps you were testing this with a plane receiving the shadow instead of a terrain? Because I was not getting much progress last week I logged it as a bug and just this morning my test scene was accepted as a reproducible bug:

    https://issuetracker.unity3d.com/is...e-shadow-slash-shadow-distance-is-high-enough

    So I am going to walk away from this mess for a while and see if that goes anywhere.
     
  6. BattleAngelAlita

    BattleAngelAlita

    Joined:
    Nov 20, 2016
    Posts:
    400
    Capture a video of what you mean by "oscillating shadows".
     
  7. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Zipped, mp4 attached. But you should be able to generate that by importing my previously supplied package into a new unity session (not HDRP).
     

    Attached Files:

  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Loaded that into an empty project ... still doesn't actually work since the scene file is completely empty apart from the default camera and directional light, and you didn't include all of the files for the terrain so that doesn't render correctly if you import it into the scene.

    However, I was able to reproduce exactly what you're seeing and the cause is ... kind of still "aliasing". Though not in the way I described. The kind of aliasing I described is happening too, but the pulsing is caused by Stable Fit Shadow Projection. You can fix the pulsing by switching to Close Fit in the Quality Settings.

    Stable Fit Shadow Projection attempts to keep the directional shadow projection snapped to a virtual world space grid aligned with the shadow map texels. For directional lights that don't rotate, this minimizes aliasing when the camera is moving around in the world. Unfortunately it seems like a rotating light causes the grid to jump around some. The "aliasing" in this case is the alignment of the projection trying to match shadow map texels and a changing virtual world space grid.
     
    AlTheSlacker likes this.
  9. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Sorry, I must have something else set incorrectly as even with Close Fit I still see the same problem. Would you be able to attach an example package of it working?
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Maybe "fix" was too strong a word. "Potentially reduce" maybe be more accurate.

    Your example case of a large-ish terrain with a box aligned with the one rotation angle of the light using Stable Fit is going to be a giant combination of aliasing and floating point limitations working together to make the problem as obvious as possible. Use a Yaw of something other than 0.0 and the problem disappears almost entirely (which is probably why Valheim doesn't show any issues).

    Try using this bit of code instead of your original:
    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MoveLight : MonoBehaviour
    6. {
    7.     [SerializeField] private float lightAngle = 30;
    8.     [SerializeField] private float lightincrement = 0.05f;
    9.     [SerializeField] private Vector3 axis = new Vector3(1f, 0.1f, 1f);
    10.  
    11.     void Update()
    12.     {
    13.         lightAngle += lightincrement * Time.deltaTime;
    14.         transform.rotation = Quaternion.AngleAxis(lightAngle, axis);
    15.     }
    16. }
     
    Seromu and AlTheSlacker like this.
  11. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Thanks @bgolus, that's really helpful and has been very informative for me. I'll have a play with some of the numbers and see where it goes.

    [Edit]
    For future reference, it seems the key to removing the judder is to ensure the light is off centre, so for example, if you are rotating the x value, then have a fixed z rotation value of 20 degrees and the problem goes away.
     
    Last edited: Apr 4, 2021
  12. agplays112

    agplays112

    Joined:
    Dec 20, 2022
    Posts:
    1
    i would use fixed update otherwise the length of the cycle is shorter/longer depending on framerate
     
  13. NickNukem

    NickNukem

    Joined:
    May 11, 2020
    Posts:
    5
    This may not even be applicable anymore...but in my project I was just rotating the directional light (sun) by a transform degrees per second and had the same issues you did. All my shadow flickering would stop if I set the sun to stationary. So I randomly wondered if I slerped (smoothed) the degrees per second if that would help. And it did, a lot. Not perfect, but so so much better:

    Quaternion fromRotation = transform.rotation;
    Quaternion toRotation = Quaternion.Euler(transform.eulerAngles + transform.right * degreesPerSecond * Time.deltaTime);
    transform.rotation = Quaternion.Slerp(fromRotation, toRotation, Time.deltaTime);