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

Mathf.SmoothDamp assigns NaN...

Discussion in 'Scripting' started by ToreTank, Aug 26, 2008.

  1. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    ...to the velocity variable if the current value and the target value is the same, and the deltatime turns out to be 0. Just found out the hard way, and thought I´d share.

    Code (csharp):
    1.  
    2. var vel = 0.0;
    3. Mathf.SmoothDamp(100.0, 100.0, vel, 0.3, Mathf.Infinity, 0);
    4.    
    5. Debug.Log("vel: " + vel);
    6.  
    Yes, I know sending 0 for deltatime is kind of pointless (I assume my problem was caused by a timescale set to 0), but I still suspect the behaviour isn´t intentional...?
     
  2. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    I had exactly the same problem a few weeks ago. Total pain to track down, as the NaN was being fed (successfully) through all sorts of functions in a modified version of SmoothFollowCamera.
     
  3. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    Yeah, exactly, SmoothFollowCamera was where I had problems as well. After going through debugging hell and tons of Debug.Logs, I ended up only running the smooth-function if the current value had not reached the target value...
     
  4. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    97
    Over 14 years later, this bug was still alive in 2021.3.16f1. Spent hours debugging it as it was hard to reproduce until one player managed to find repro steps.

    I made a bug report, too, so with some luck, maybe it will be fixed in coming decades!
     
  5. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,593
    Well, isn't it what you'd expect? Velocity is distance/time, and if you set time to 0, you're dividing by 0: the resulting NaN.
     
  6. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    97
    From the documentation of Mathf.SmoothDamp:

    Since this function is supposed to be used so that you keep using the previous version of the velocity you received when you called the function last time, I definitely expect it to never become invalid so that all next calls will start returning NaN for the return value, too. There is no mention in the documentation that if you give it certain values, this would happen.

    Since this and Vector3.SmoothDamp are regularly used to smooth cameras, it is not a super-exceptional situation that the camera is already where it wants to go, and that the game is temporarily paused so that deltaTime is 0.

    Also, if the value is already at its target, you would definitely expect the velocity to become 0 as the description says it will never overshoot. There is no reason for the velocity to be undefined in that situation. Or alternatively it could just not modify the velocity at all. Both would be infinitely better than returning NaN and invalidating all future calls, too.
     
  7. ElXill

    ElXill

    Joined:
    Jun 2, 2017
    Posts:
    43
    I was having this error too, then tried deleting library files. Now velecity changes once and locks in a very small value and function gets stuck at that value.

    Anyone found a way to fix this?
     
  8. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    97
    Either make your own SmoothDamp function or make sure you never call it with values that might return NaN.

    I submitted a bug report but I don't expect any quick fixes. But maybe in 2038 or something.
     
  9. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,863
    In cases like this, it's better for the function to simply generate a NaN and move on.

    What should the output be if time is stopped? 0? 1? The first argument? It's not defined. If every function that used division had to carefully tiptoe around the possibility of division by zero, it would slow things down and there is not always a reasonable default output in those cases.

    Whenever you set the time scale to zero, it's up to you to protect all your routines from that possibility.
     
    orionsyndrome likes this.
  10. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,509
    I was going to agree, but in this case while the smoothing function is undefined, I think that the range of potential outputs and their broad behaviour is well defined. Am I missing anything?
    The return value must be between 'current' and 'target'. If the time delta is zero then there can have been no change from the former towards the latter, so the return value must be the former.

    The externally provided 'currentVelocity' similarly can not have changed, because there has been no time in which for it to change.

    Avoiding branches is good for CPU performance, and it's possible for code to re-use that 'currentVelocity' value and require certain behaviour of it, so I completely understand why there isn't a built-in check for zero when it's going to be pretty rare. But I'd at least reflect that in the documentation, and if it were my library I'd probably provide two versions of the function - one with and one without the zero-check.
     
    Kurt-Dekker likes this.
  11. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    97
    If there is some possibility that the function becomes unstable, there should at least be big bold letters in the documentation which of the input values are invalid. I am just copy'n'pasting my previous answer here again:

    "Since this function is supposed to be used so that you keep using the previous version of the velocity you received when you called the function last time, I definitely expect it to never become invalid so that all next calls will start returning NaN for the return value, too. There is no mention in the documentation that if you give it certain values, this would happen.

    Since this and Vector3.SmoothDamp are regularly used to smooth cameras, it is not a super-exceptional situation that the camera is already where it wants to go, and that the game is temporarily paused so that deltaTime is 0.

    Also, if the value is already at its target, you would definitely expect the velocity to become 0 as the description says it will never overshoot. There is no reason for the velocity to be undefined in that situation. Or alternatively it could just not modify the velocity at all. Both would be infinitely better than returning NaN and invalidating all future calls, too."
     
  12. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    717
    I ran into this a few weeks ago. It was annoying!

    I'd expect calling this function with a delta-time of zero to be a no-op, just like how it would be if you called
    Mathf.MoveTowards(from, to, 0);