Search Unity

Help Wanted Can't quite understand quaternion rotation (euler angles)

Discussion in 'Scripting' started by Adriano1499, Dec 14, 2020.

  1. Adriano1499

    Adriano1499

    Joined:
    May 1, 2019
    Posts:
    3
    Hi, I'm currently working on a puzzle game, the part where I'm struggling - a cog which you can rotate. It's a 3d model and upon clicking on the left side it should rotate counter-clockwise by 40 degrees, opposite on the right side. Anyway the rotation happens on the y-axis, it all works fine until the y rotation goes into negative angles (-40) in that case instead of rotating to the left it rotates back to 0. Here's the code in the Move method called by Update :
    StartCoroutine(RotateGearA(Vector3.right * 40, 1));


    And the coroutine here:

    Code (CSharp):
    1. IEnumerator RotateGearA(Vector3 byAngles, float inTime) {
    2.         isMoving = true;
    3.         var fromAngle = cogA.transform.rotation;
    4.         var toAngle = Quaternion.Euler(cogA.transform.eulerAngles + byAngles);
    5.         for(var t = 0f; t < 1; t += Time.deltaTime/inTime) {
    6.             cogA.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
    7.             yield return null;
    8.         }
    9.     }
    I'm not sure whether I should implement an if-else statement in the Move() method to handle the edge cases or if there's another approach?
     
    Last edited: Dec 14, 2020
  2. Adriano1499

    Adriano1499

    Joined:
    May 1, 2019
    Posts:
    3
    PS. If it helps that coroutine is from my previous project where the cogs were 2D sprites, it worked fine there
     
  3. Ray_Sovranti

    Ray_Sovranti

    Joined:
    Oct 28, 2020
    Posts:
    172
    Euler angles are pretty terrible to work with because it's not mathematically possible to reliably convert a Quaternion to a single set of Euler angles. So the conversion algorithm has to choose which of the possible conversions to use, and as the rotation changes this is not consistent. So you'll get random jumps here and there. Further reading.

    You can avoid these problems by either:
    A) storing your rotation as a Vector3 on your own, using Quaternion.Euler as a one-way street (i.e. never convert a Quaternion to Euler angles);
    B) use Quaternion math exclusively
    C) for something like this, don't bother with coding rotations at all; just make a rotation animation, and trigger that animation in script.
     
  4. Adriano1499

    Adriano1499

    Joined:
    May 1, 2019
    Posts:
    3
    Thanks for the info, it appears I fixed it by using the Quaternion operator *


    Code (CSharp):
    1. IEnumerator RotateGearA(Vector3 byAngles, float inTime) {
    2.         isMoving = true;
    3.         var fromAngle = cogA.transform.rotation;
    4.         // var toAngle = Quaternion.Euler(cogA.transform.eulerAngles + byAngles);
    5.         var toAngle = fromAngle * Quaternion.Euler(byAngles);
    6.         for(var t = 0f; t < 1; t += Time.deltaTime/inTime) {
    7.             cogA.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
    8.             yield return null;
    9.         }
    10.     }
    But for the future I'll stay away from these evil euler angles :confused:
     
  5. Ray_Sovranti

    Ray_Sovranti

    Joined:
    Oct 28, 2020
    Posts:
    172
    The important thing is to always avoid Quaternion -> Euler conversion, and your new code does avoid that. There's no problem converting Euler to Quaternion.
     
    Bunny83 and Adriano1499 like this.
unityunity