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

Question I'm getting back the wrong quaternion value

Discussion in 'Scripting' started by CoolJosh3k, Jun 17, 2021.

  1. CoolJosh3k

    CoolJosh3k

    Joined:
    Dec 3, 2016
    Posts:
    145
    I did write this code a few months ago, so perhaps I missed something; but I really feel like I should not be getting out a value of -4.371139e-08 instead of 0.


    void OnDrawGizmosSelected() {
    if (EditorGUI.actionKey) {
    var e = transform.localEulerAngles;

    //e.z = Methods.RoundToNearest(e.z, 90f);
    e.z = Mathf.Round(e.z / 90f) * 90f;

    e.z %= 360f;

    transform.localEulerAngles = e;
    }
    }


    The quaternion I expect is (0, 0, 1, 0), but what I actually get is (0, 0, 1, -4.371139e-08)!

    Better code to achieve my goal is great, but what I'd love even more is understanding of why this happens.

    Any help is appreciated.
     
  2. bobisgod234

    bobisgod234

    Joined:
    Nov 15, 2016
    Posts:
    1,042
  3. CoolJosh3k

    CoolJosh3k

    Joined:
    Dec 3, 2016
    Posts:
    145
    I have a gameobject set to the quaternion of (0, 0, 1, 0), but when I move it around in the scene with the "action key" (ctrl on Windows) held down it results in the wrong quaternion values. I can see this using the debug mode in the inspector window.

    I am unsure of how my code is changing that input to such.
     
  4. bobisgod234

    bobisgod234

    Joined:
    Nov 15, 2016
    Posts:
    1,042
    But the "wrong" quaternion value you posted is the same as the expected quaternion value, I explained that.

    I don't understand what is wrong about the quaternion you are getting.
     
  5. Zelacks

    Zelacks

    Joined:
    Jul 23, 2019
    Posts:
    2
    The small amount of error is due to "floating point imprecision". When you do math with floats, they will be off by a small amount.

    The unity inspector formats the value so it is readable. The value shown in the inspector is just a "display value", which is different from the real value actually stored. When you turn on debug mode, the quaternion shown is the raw value, which is off by a very small amount (from both the math you did and the math used to create the quaternion from euler angles).

    I made an example (using your code so its easy to just plug in and test), when you press control, in the console, you should see the real value:

    Code (CSharp):
    1.  
    2. void OnDrawGizmosSelected()
    3. {
    4.     if (EditorGUI.actionKey)
    5.     {
    6.         float z = 90.01f-90f;
    7.         Debug.Log(z);
    8.     }
    9. }
    10.  
    This code prints "0.01000214" to the console which is to be expected because of how floats work.

    So your code is fully functional, the small offset is not avoidable.
     
    CoolJosh3k likes this.
  6. CoolJosh3k

    CoolJosh3k

    Joined:
    Dec 3, 2016
    Posts:
    145
    Well...

    I am taking the euler angles (0, 0, 180), then only adjusting the z value:

    180 / 90 = 2
    2 rounded to the nearest integer is 2
    2 * 90 = 180

    A result of (0, 0, 180).

    In this particular case, it ends up the same exact euler angles, but I am looking for the quaternions so...

    cx = cos(0 /2) = 1
    sx = sin(0 /2) = 0
    cy = cos(0 /2) = 1
    sy = sin(0 /2) = 0
    cz = cos(pi /2) = 0
    sz = sin(pi /2) = 1

    then finally

    w = (cx * cy * cz) + (sx * sy * sz) = (1 * 1 * 0) + (0 * 0 * 1) = 0 + 0 = 0

    In the meantime I had a thought about how it might be due to floating point error being too large.

    I tested Mathf.Cos(Mathf.PI/2) and found the issue. It does not give me the 0 I expect. I'll need to write thing differently to account for this.
     
  7. CoolJosh3k

    CoolJosh3k

    Joined:
    Dec 3, 2016
    Posts:
    145
    Thanks. I forgot that it would be calculated using radians and not degrees, so a large enough error could occur.
     
  8. CoolJosh3k

    CoolJosh3k

    Joined:
    Dec 3, 2016
    Posts:
    145
    For those coming here in the future, here was my quick fix:

    Code (CSharp):
    1. var q = transform.rotation;
    2. for (int i = 0; i < 4; i++) {
    3.     if (Methods.FastRangeCheck(-0.001f, 0.001f, q[i]) > 0) {
    4.         q[i] = 0;
    5.     }
    6.  
    7.     if (Methods.FastRangeCheck(0.999f, 1.001f, q[i]) > 0) {
    8.         q[i] = 1f;
    9.     }
    10.  
    11.     if (Methods.FastRangeCheck(-1.001f, -0.999f, q[i]) > 0) {
    12.         q[i] = -1f;
    13.     }
    14.  
    15.     if (Methods.FastRangeCheck(SQRT_OF_TWO_RECIPROCAL - 0.001f, SQRT_OF_TWO_RECIPROCAL + 0.001f, q[i]) > 0) {
    16.         q[i] = SQRT_OF_TWO_RECIPROCAL;
    17.     }
    18.  
    19.     if (Methods.FastRangeCheck(NEG_SQRT_OF_TWO_RECIPROCAL - 0.001f, NEG_SQRT_OF_TWO_RECIPROCAL + 0.001f, q[i]) > 0) {
    20.         q[i] = NEG_SQRT_OF_TWO_RECIPROCAL;
    21.     }
    22. }
    23. transform.rotation = q;
    Code (CSharp):
    1. [ReadOnly] public const float SQRT_OF_TWO = 1.41421356237f;
    2. [ReadOnly] public const float SQRT_OF_TWO_RECIPROCAL = 1f / SQRT_OF_TWO;
    3. [ReadOnly] public const float NEG_SQRT_OF_TWO_RECIPROCAL = -SQRT_OF_TWO_RECIPROCAL;
    Code (CSharp):
    1. public static float FastRangeCheck(float min, float max, float value) {
    2.     var result = (value - min) * (max - value);
    3.     result /= Mathf.Abs(result);
    4.     return result;
    5. }
    Far from perfect or elegant, but it works for the occasional use in the editor.
     
  9. HellGate94

    HellGate94

    Joined:
    Sep 21, 2017
    Posts:
    132
  10. CoolJosh3k

    CoolJosh3k

    Joined:
    Dec 3, 2016
    Posts:
    145