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

Is Quaternion really do not suffer from Gimbal Lock??

Discussion in 'General Graphics' started by hellengoodd, Sep 15, 2018.

  1. hellengoodd

    hellengoodd

    Joined:
    May 31, 2017
    Posts:
    51
    As Unity said:
    https://docs.unity3d.com/Manual/QuaternionAndEulerRotationsInUnity.htmlhttps://docs.unity3d.com/ScriptReference/Quaternion.html
    Benefit: Quaternion rotations do not suffer from Gimbal Lock.
    Quaternions are used to represent rotations.
    They are compact, don't suffer from gimbal lock and can easily be interpolated. Unity internally uses Quaternions to represent all rotations.

    But I think quaternion also suffer from Gimbal Lock.

    Forexample:
    I have an airplane model, it is vertical, I want it to flip over (X-axis = 90 degrees), and then play an animation of the wing up and down (that is, the Y-axis is repeat between 20 degrees and -20 degrees), how to achieve this rotation with quaternions?

    The following quaternion code will have a gimbal lock problem.
    Code (CSharp):
    1.  
    2. private void Update() { transform.rotation = Quaternion.Euler(new Vector3(90, 0, animationRote))//animationRote is a repeate float between -20 to 20 }
    Note:
    Use "Only The Quaternion" to solve this and "Not Use Other Method Such As Create An Empty Parent Object"

    Who can Use "Only The Quaternion" to solve this gimbal lock problem so that i can understand why Quaternion rotations do not suffer from Gimbal Lock.

    Thank you all!
     
  2. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,367
    You're using the
    .Euler
    function to define the rotation, which is based on Euler angles, which definitely has a gimbal lock problem. The problem isn't with the concept of Quaternions, it's how you're trying to use Euler angles to construct a Quaternion. (I think the documentation really needs to do more to help people understand this distinction.)

    Because of your single screenshot, I can't really make out what the "wings" are, or which way you want them to move. I think I understand the "nose" has rotated downward? Are you wanting the whole body to sway -20 to +20 while keeping the nose downward? If I have misunderstood your model, can you expand on what you want? Show two or more screenshots, with the vehicle in its natural position, and in the position(s) you want to see it rotate.
     
    hellengoodd likes this.
  3. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,367



    I hope the comments in this code snippet are along the lines you're intending. Again, if not, explain with more diagrams.

    Code (CSharp):
    1.     void Update()
    2.     {
    3.         // We want a combination of three distinct rotations:
    4.         //
    5.         //   (1) the ship has oriented to face a given heading,
    6.         //       in this case, northeast
    7.         //
    8.         float yaw = 45f;
    9.         Quaternion heading = Quaternion.AngleAxis(yaw, Vector3.up);
    10.      
    11.         //   (2) the ship's attitude is slowly going into a nosedive,
    12.         //       rotating around an axis that would go left-to-right
    13.         //       through the ship, ignoring any wing or roll motion
    14.         //
    15.         float pitch = Mathf.Clamp(Time.time * 5f, 0f, 90f);
    16.         Quaternion nose_dive = Quaternion.AngleAxis(pitch, Vector3.right);
    17.      
    18.         //   (3) the ship is rolling left and right, wagging the wings
    19.         //       alternately about 20 degrees either way, without
    20.         //       any influence on the nosedive motion
    21.         float roll = Mathf.Sin(Time.time * 5f) * 20f;
    22.         Quaternion wing_wave = Quaternion.AngleAxis(roll, Vector3.forward);
    23.      
    24.         transform.rotation = heading * nose_dive * wing_wave;
    25.  
    26.         // The Euler() function also applies three independent rotations.
    27.         // There would be a natural expectation that you could use the Euler
    28.         // angles to specify such a straightforward rotation.  However,
    29.         // the order of rotations hardwired into Unity's function will cause
    30.         // a gimbal lock situation and much confusion for the rotations.
    31.         // The built-in Unity ordering for Quaternion.Euler() is Z, X, Y.
    32.         // We want Y, X, Z.
    33.         //
    34.         /////  transform.rotation = Quaternion.Euler(pitch, yaw, roll);
    35.  
    36.     }
    37.  
     
    Aksoq and hellengoodd like this.
  4. hellengoodd

    hellengoodd

    Joined:
    May 31, 2017
    Posts:
    51
    Thank you for your answer!
    This is What I want them to move.
    GIF.gif
    The nose of the airplane model starts downwards.
    So I need to flip the X axis 90 degrees to make it level with the ground.

    I implemented the animation I wanted through your code below, but I still don't think the gimbal lock problem is solved by the quaternion. I will give a detailed question in the reply below.
     
  5. hellengoodd

    hellengoodd

    Joined:
    May 31, 2017
    Posts:
    51
    This code is very helpful to me!
    But I still have some question.
    Does this code solve the problem of the gimbal lock by quaternion or solve the problem by changing the order of Euler angles?
    Because I can use Quaternion.Euler() to sovle it too.
    Code (CSharp):
    1.         float yaw = Mathf.Sin(Time.time * 5f) * 20f;
    2.         Quaternion heading = Quaternion.Euler(0,yaw,0);//Quaternion.AngleAxis(yaw, Vector3.up);//Y
    3.         float pitch = 90;//Mathf.Clamp(Time.time * 5f, 0f, 90f);
    4.         Quaternion nose_dive = Quaternion.Euler(pitch, 0, 0);//Quaternion.AngleAxis(pitch, Vector3.right);//X
    5.         float roll = 0;// Mathf.Sin(Time.time * 5f) * 20f;
    6.         Quaternion wing_wave = Quaternion.Euler(0, 0, roll);////Quaternion.AngleAxis(roll, Vector3.forward);//Z
    7.         transform.rotation = nose_dive *heading * wing_wave;
    This code is what I imitate you to solve my airplane gimbal lock problem.the order I want is X, Y, Z (local).

    Since the Euler angle rotation is obtained by multiplying three ordered matrices, can the Euler angle solve the gimbal problem by changing the order of the matrices, or the quaternion is only a part of the Euler angle matrix. However, why does the quaternion say that it can solve the problem of universal lock?


    Is there any code to show the use of Euler angles to suffer from the gimbal lock problem,
    then replace it with quaternion, and then solve the problem.
     
  6. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,367
    Sure, you created three quaternions from Euler separately as i did. You did not have a gimbal lock problem because you chose which axis had to be applied first, something the Euler function can't do in one call.

    Any number of quaternion transforms can be stacked, in any order you like. Any rotation can be achieved, and you can interpolate between any two rotations with a single quaternion.

    How will you express the combination of rotations from hip-bone to fingertip, through all the joints between, if for every joint you also must specify "rotate around X and then around Z" for one and "rotate around Y and then around X" for another? With quats, it's just the product of all joints, easily handed to a GPU.
     
    hellengoodd likes this.
  7. hellengoodd

    hellengoodd

    Joined:
    May 31, 2017
    Posts:
    51
    Sorry, I have just experienced a 17th-level typhoon here, so the reply is late.
    I still have some confusion about the above problem.

    Euler:
    1:It must have three rotation matrices,so it runs slower;
    2:It can only be rotated around three fixed basic axes(XYZ),It can't rotate around any axis directly;
    3:The order of the three rotation matrices has been fixed in unity, so we can only change the order of them by superposition.For example, if i need [XYZ],but unity is [ZXY],so i must [0X0]*[00Y]*[Z00],otherwise the gimbal lock problem may occur,so it runs more slower then 1;

    Quaternions:
    It can rotate around any axis,so it will be faster than the Euler angle.For example, I can change the above code to this so that Quaternion.AngleAxis num changes from three to two.
    Code (CSharp):
    1.  
    2. ag = 91.72794f;
    3.         ax = new Vector3(0.9702876f, 0.1710879f, 0.1710879f);
    4.         ax2 = new Vector3(0.9702876f, -0.1710879f, -0.1710879f);
    5.         //transform.rotation.ToAngleAxis(out ag, out ax);
    6.         transform.rotation = Quaternion.Lerp(Quaternion.AngleAxis(ag, ax), Quaternion.AngleAxis(ag, ax2), Mathf.Sin(Time.time * 5f));
    "ag" and "ax" and "ax2" is get from Quaternion.ToAngleAxis


    In summary,I think Quaternion.AngleAxis is the key, It can rotate around any axis so have no gimbal lock problem.
    But I still have two questions:
    1:In order to avoid the problem of gimbal lock.
    we can use Quaternion.ToAngleAxis to get the angel and axis of result from Euler.Then we can use only one Quaternion.AngleAxis.
    Or we can use three Quaternion.ToAngleAxis,but we must know the correct order.
    These two ways are unfriendly to many people, many of them are directly use Quaternion.Euler().
    Is this a bit complicated, or am I getting it wrong?

    2:Why don't we build a matrix that rotates around any axis and use quaternions?
    kkk.png
    This one matrix can do things that Quaternion.AngleAxis can do.
    Why do we need those three matrices or quaternion?
     
    halley likes this.
  8. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,367
    1. Quaternions are way easier/faster to create than the above matrix; transcendental math is some of the slowest you can do, behind logarithmic/roots, and you have lots of other 1-x and multiplication steps in there.

    2. Once they're created, quaternion products are faster to calculate than matrix products.

    3. GPU hardware is insanely optimized to do 4x4 matrix products, and quaternion products, but not 3x3 matrix products.

    Again, you want to feed whole stacks of transforms to an engine without special handling at each stage. Quats and 4x4 matrices opened the floodgates to high-performance computer graphics in the mid-90s, and it's what allows you to develop skinned meshes with tens of thousands of points on skeletons with hundreds of bones, all in real-time.
     
    hellengoodd likes this.
  9. hellengoodd

    hellengoodd

    Joined:
    May 31, 2017
    Posts:
    51
    Thank you for your reply, I understand!
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    GPUs have no specialized optimizations for quaternions. Really they don't have any specialized optimizations for matrices either, but matrix math tend to be just a lot of dot products, and GPUs are very good at that. Also, depending on the hardware, a 3x3 matrix will either be identical to a 4x4 matrix, or much faster. Certainly faster than a quaternion, at least for rotating vectors.

    The product of two 3x3 matrices is slower than the product of two quaternions, but usually you want to apply a 3x3 matrix to a vector, not to each other.

    matrix * (matrix * vector)
    is faster than
    quat * (quat * vector)
    is faster than
    (quat * quat) * vector
    is faster than
    (matrix * matrix) * vector
     
  11. hellengoodd

    hellengoodd

    Joined:
    May 31, 2017
    Posts:
    51
    I am a bit confused, will it be different from different GPU practices?
     
  12. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    For the purposes of the original topic of this thread, chaining rotations done by quaternions or matrices (3x3 or 4x4) work equally well in terms of the end result. The difference is rotating an orientation by another orientation, or blending between orientations, quaternions are much cheaper and consistent, and unlike euler doesn't suffer from gimbal lock. That's kind of the jist of this thread so far. Technically you can do it all with matrices as well, but it's more expensive.

    However when it comes to GPUs specifically, they are designed to be especially efficient at certain kinds of vector math. Matrix transforms in particular being one of those things GPUs do very well. A single quaternion rotation of a vector is slower on a GPU than a matrix (3x3 or 4x4) rotation, and is faster than a quaternion rotation of a quaternion. This is different than a CPU where the quaternion math is likely faster as there isn't always the same optimizations.

    As for why 4x4 and 3x3 are either the same, or the 3x3 is faster, some GPUs are designed to do all it's matrix math assuming 4x4 and float4 multiplication. When doing 3x3 or even 2x2 against float3 or float2, it may in fact internally be doing a full 4x4 with a lot of zeroed values, so in that case they're identical. On most newer GPUs however, it'll actually do just a 3x3, but still have the additional optimizations for doing so over a CPU.