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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Simple Fix For "Look Rotation Viewing Vector Is Zero"

Discussion in 'Scripting' started by Simplified, Jun 17, 2016.

  1. Simplified

    Simplified

    Joined:
    May 28, 2016
    Posts:
    19
    I saw this one all over the web, but I couldn't find the solution for my specific problem. This is to help any other new people having this problem. What there isn't a fix for(I couldn't find it) is getting rid of the error message in the console. The reason for getting rid of the error message in the console is due to performance(I was losing about 600+ FPS(yes, that much) when it was checking for the error). Debugging always gives a performance hit, so here is how to get rid of it to gain that performance back.

    Code (CSharp):
    1. // Script isn't perfect. For example purposes.
    2.  
    3. void Movement()
    4.     {
    5.  
    6.         float axisX = Input.GetAxis("Horizontal");
    7.         float axisY = Input.GetAxis("Vertical");
    8.         float axisCombined = axisY / axisX;
    9.  
    10.         float speed = 5f;
    11.  
    12.  
    13.         // The fix is here. Just add a very small value to the float
    14.         // to get rig of the error. In this case, it's axisX
    15.  
    16.  
    17.         Vector3 movement = new Vector3(axisX + 0.001f, 0.0f, axisY);
    18.  
    19.         rbody.AddForce(movement * speed, ForceMode.Acceleration);
    20.  
    21.         Quaternion newRotation = Quaternion.LookRotation(movement);
    22.  
    23.  
    24.         if(axisCombined >= 0.1f || axisCombined <= 0.1f)
    25.         {
    26.  
    27.             transform.rotation = Quaternion.Slerp
    28.                 (transform.rotation, newRotation, 20 * Time.deltaTime);
    29.  
    30.         }
    31.     }
     
    FROST6, sokinooo and shivamsingh22 like this.
  2. MathiasDG

    MathiasDG

    Joined:
    Jul 1, 2014
    Posts:
    114
    This error message pops when you try to call a rotation method towards a vector zero (0,0,0).
    You can easily fix this using an if statement before calling the quaternion methods that pop this error.
    Code (CSharp):
    1. if (movement != Vector3.Zero) {
    2.     // Do the rotation here
    3. }
    or

    Code (CSharp):
    1. if (movement.Magnitude > EPSILON) {    // Where EPSILON is a very small number
    2.     // Do the rotation here
    3. }
     
  3. craig4android

    craig4android

    Joined:
    May 8, 2019
    Posts:
    124
    wouldn't use Magnitude, use SqrMagnitude it's faster. But still is there a better solution?
     
    anycolourulike likes this.
  4. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,876
    Thread is three years old, by the way.

    I agree you should not use
    Vector3.magnitude
    unless you need an important distance calculation, as it computes the square root, a costly calculation. If you're just comparing which of two things is farther, you would want to use
    Vector3.sqrMagnitude
    instead.

    It doesn't seem to be common knowledge, but the Vector3 operator for comparing equality (
    ==
    ) automatically includes an epsilon-based comparison, and if you want to be more explicit, you can use
    Vector3.Equals()
    . So saying
    velocity == Vector3.zero
    is already saying "it is effectively stopped."

    https://docs.unity3d.com/ScriptReference/Vector3.Equals.html
     
    Westland, lclemens and DonLoquacious like this.
  5. shivamsingh22

    shivamsingh22

    Joined:
    Aug 30, 2018
    Posts:
    1
    thanks it worked for me...
     
    Ex6tra and Danebulus like this.
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    That isn't a real solution to the problem, as it only shifts the error (and in this particular case, it has the slight advantage of decreasing the probability of the error popping up, as the input will rarely be equal to the small constant value that you add).

    Suppose F(x) where x = 0 causes an error, i.e F(0) => error
    You cannot fix it by adding a constant, as in F(x + c), because it fails when x = - c, as in F(-c + c) = F(0).

    You must either avoid the call when x=0, or only add a small value when x=0, so that 0 is never passed.

    The same applies when Vector.Zero causes an error.
     
    Bunny83 and Westland like this.
  7. BlakeMathes2003

    BlakeMathes2003

    Joined:
    Nov 21, 2019
    Posts:
    1
    I'm new to unity, would i put it in the start or update method ?
     
  8. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,742
    You put it around whatever code you have that is causing the error message, no matter where that code is.
     
  9. tcz8

    tcz8

    Joined:
    Aug 20, 2015
    Posts:
    504
    Why doesn't it just not rotate when the resulting rotation is ZERO. Is the performance cost worth having us check the sqrMagnitude to avoid computing the look rotation?
     
    MaxLohMusic and mannyhams like this.
  10. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,742
    It definitely does "just not rotate", but if you call Quaternion.LookRotation(Vector3.zero), then there's probably a problem with whatever code leads up to that so the engine prints out that warning to let you know there's an issue. Checking if a vector is != zero is essentially zero performance cost.
     
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,538
    The resulting rotation is not "zero". You simply can't construct a valid quaternion / rotation when the direction vector is zero. The code behind LookRotation is similar to what is shown in this answer. You can not normalize the zero vector as it doesn't represent any direction.
     
  12. tcz8

    tcz8

    Joined:
    Aug 20, 2015
    Posts:
    504
    So It's not that the resulting look rotation was zero but that 0,0,0 is not a valid direction vector to feed LookRotation as a parameter?

    That makes more sense.

    Thanks guys!
     
    Last edited: Sep 19, 2020
    MaxLohMusic and Bunny83 like this.
  13. rogodoy

    rogodoy

    Joined:
    Jan 24, 2013
    Posts:
    21
    I've got this erro using Vector3.zero, I changed by Vector3.one; and the error is gone. Because there are no vector3.zero rotation, you must use a number.

    Code (CSharp):
    1. gunHitPointFlash, hit.point, Quaternion.LookRotation(Vector3.zero); //old not fixed.
    2.  
    3. gunHitPointFlash, hit.point, Quaternion.LookRotation(Vector3.one); ///new fixed
     
  14. mannyhams

    mannyhams

    Joined:
    Feb 6, 2015
    Posts:
    34
    FYI there is a
    Quaternion.identity
    value which represents the concept of "no rotation", which is somewhat analogous to
    Vector3.zero
    for vectors. This may be the appropriate value to use for code which is expected to generate a
    Quaternion
    in all cases:

    Code (CSharp):
    1. Quaternion rotation = vector == Vector3.zero
    2.                                   ? Quaternion.identity
    3.                                   : Quaternion.LookRotation(vector);
     
    Gzerg, DevinDazzlr and swingingtom like this.
  15. tcz8

    tcz8

    Joined:
    Aug 20, 2015
    Posts:
    504
    @StarManta I'm saying it should just default to Quaternion.Indentity when it sees a Vector3.zero instead of complaining about it. Now their code tests for it and my code test for it to avoid the error. What other intention than Quaternion.Identity would anyone feeding it a value of 0,0,0 have?
     
    mannyhams likes this.
  16. mannyhams

    mannyhams

    Joined:
    Feb 6, 2015
    Posts:
    34
    It's inconvenient but I guess I can see why there's an error.
    Quaternion.LookRotation(Vector3.zero)
    asks for a look rotation to nowhere, which is sort of nonsensical. I think it's reasonable for the API to require the programmer to write sensible instructions - instead of asking
    LookRotation
    for a rotation to nowhere, you can just yield
    Quaternion.identity
    instead to clarify your intent. I guess the API designer's assumption was that if programmers are asking for a look rotation to nowhere, they've likely done something wrong.

    On the other hand, it looks like
    Quaternion.identity
    exists specifically to represent the concept of "rotation to nowhere"... so I see where you're coming from, too.

    In any case if it's very bothersome, a utility function which implements my snippet from above solves the issue.
     
  17. MallNinjaMax

    MallNinjaMax

    Joined:
    Apr 17, 2017
    Posts:
    25
    So what do you do when Unity's own code triggers this warning?

    Cinemachine3rdPersonFollow.cs: 205

    Called by the first person controller Starter Asset. Tried fixing it from the code I could edit, but nothing.
     
    Last edited: Oct 24, 2021
    ROBYER1 likes this.
  18. tcz8

    tcz8

    Joined:
    Aug 20, 2015
    Posts:
    504
    You report the bug. Try the Cinemachine forum first.
     
  19. AllFatherGray

    AllFatherGray

    Joined:
    Nov 29, 2014
    Posts:
    14
    2022 it's still here.
     
  20. unity_3KAIcHNkHzTZvw

    unity_3KAIcHNkHzTZvw

    Joined:
    Oct 5, 2020
    Posts:
    6
    I think it's more like '2022 and some folk still can't tell a bug from a feature'. You can't get a rotation from zero - there is nowhere to face, and nothing for the code to conjure a Quaternion from as the only reference point you give it is the relevant direction - which is somehow where the observer is stood. Try and look in the direction of the focal point of your own eyeball and tell me which way you're facing; I can't manage it but something tells me it's tricky.

    Either live with the performance cost of the console error (which is massive, don't do this), or go through the mild inconvenience of writing a wrapper for LookRotation that includes checking for Vector3.zero and decides what to do about it in a way appropriate to your use-case. Local functions are good for this, as the use-cases are usually highly specific.
     
  21. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,538
    Exactly. Funny enough that if you actually look at the OPs solution, it's not really about fixing "the error" but to provide a resting direction and as we can see, it's not the identity rotation but he wants to face to the right.

    This condition btw looks like it makes no sense:

    Code (CSharp):
    1.  if(axisCombined >= 0.1f || axisCombined <= 0.1f)
    and yes, under normal circumstances this makes absolutely no sense. However it's an implicit NaN check. So this is essentially a hacky solution to exclude the case where both input axis are 0 (because he does
    axisCombined = axisY / axisX;
    ). That's really an ugly and obfuscated solution which I would never want to use.

    What exactly makes the identity rotation the right return value? Keep in mind this rotation is used as an absolute rotation. So just using identity could be a solution, but it won't necessarily fit every problem. Actually it rarely would. As I just said, it wouldn't even be a solution in the original post.

    Errors and warnings are your friends. The compiler / CPU / computer does not know your intention and what you need that value for. However if you give it an impossible task, he should complain about it and not make up some answer as it sees fits.

    Note in case of Vector3.Normalize which returns Vector3.zero if the vector is too small to normalize, this makes more sense for two reasons: Checking if an error occured can still be done because properly normalized vectors are never 0. So the "error state" is preserved and proper context specific error handling can be done afterwards. Also in case of normalization, when the input vector is almost 0 and in essence doesn't have a direction that is to be preserved, it makes sense to just "round" it to 0 because the information is already / or about to get lost.

    By returning the identity rotation you could not distinguish between a valid rotation or an error afterwards without looking at the input. When you suddenly return the identity rotation the orientation would most likely snap to a completely different direction unless you happened to look into the identity oritentation by accident. Computers should communicate user errors properly and the user should avoid them. That's why System.Math.Acos returns an error (NaN) when you pass it a value that is outside the range -1 to 1. You could say it should just clamp the input so it always returns a valid angle, but the function simply is not defined outside the range and such a result would just be wrong.
     
    unity_3KAIcHNkHzTZvw likes this.
  22. AllFatherGray

    AllFatherGray

    Joined:
    Nov 29, 2014
    Posts:
    14
    The method is in the unity dll so I can't rewrite it and add a wrapper. Also, no, I don't mind "mild inconveniences, I do this full-time. It'd just be nice if I could select to disable the logs.
     
  23. unity_3KAIcHNkHzTZvw

    unity_3KAIcHNkHzTZvw

    Joined:
    Oct 5, 2020
    Posts:
    6
    An accessible method that takes the same inputs, provides the same outputs, and has a catch for look direction of zero - that's as difficult as this needs to be; but it does NEED to be that difficult because it is impossible to find any angle between two points when those points are the same.

    Code (CSharp):
    1. public static Quaternion LookRotation( Vector3 fwd, Vector3 up ) { return fwd == Vector3.zero ? Quaternion.identity : Quaternion.LookRotation(fwd,up); }
     
  24. jitterware

    jitterware

    Joined:
    Mar 31, 2018
    Posts:
    4
    I have tried to use the following code:

    Code (CSharp):
    1. rot = (vectorChange.Equals(Vector3.zero)) ? Quaternion.identity : Quaternion.LookRotation(vectorChange, Vector3.up);
    But I still got the error. So I changed the code to the following and the error went away:

    Code (CSharp):
    1. rot = (vectorChange.sqrMagnitude < GlobalDef.EPSILON_SQR) ? Quaternion.identity : Quaternion.LookRotation(vectorChange, Vector3.up);
    In case you're wondering, the value
    Code (CSharp):
    1. GlobalDef.EPSILON_SQR = 0.0001f;
     
  25. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,876
    From the docs: https://docs.unity3d.com/ScriptReference/Vector3.Equals.html

    So using
    vectorChange == Vector3.zero
    is closer to your intent than .Equals(). Personally, I find a hidden epsilon to be repugnant and overloading == to gloss over the concept of floating point error to be one of Unity's most annoying code smells. Your approach to use an explicit epsilon is the right way to go.