Unity: Gimbal Lock Again

I have to say, I have heard the word “gimbal lock” tons of time before. But recently a gimbal lock bug in Unity definitely reminded me of how naive I was about this problem. Actually, gimbal lock problem should not be seen in Unity. However, this is not always true.

What is gimbal lock?

Gimbal lock is the loss of one degree of freedom in a three-dimensional, three-gimbal mechanism that occurs when the axes of two of the three gimbals are driven into a parallel configuration, “locking” the system into rotation in a degenerate two-dimensional space.

This problem is frequently seen when we use euler angle for game object’s rotation, as one axis is set to 90 (in Unity axis order, this axis is x), then we lost one dimension. You could easily reproduce this problem in Unity Editor by set one game object’s rotation as (90, 0, 0). Then no matter how you change the value for y or z, the game object would only rotate in one dimension.

Detailed Information about Gimabl Lock

How Unity deals with euler?

Later, I checked the source code of Unity API. Here is what I found:

For transform.eulerAngles

public Vector3 eulerAngles
        return this.rotation.eulerAngles;
        this.rotation = Quaternion.Euler(value);

For transform.Rotate

public void Rotate(Vector3 eulerAngles, [DefaultValue("Space.Self")] Space relativeTo)
      Quaternion quaternion = Quaternion.Euler(eulerAngles.x, eulerAngles.y, eulerAngles.z);
      if (relativeTo == Space.Self)
        this.localRotation = this.localRotation * quaternion;
        this.rotation = this.rotation * Quaternion.Inverse(this.rotation) * quaternion * this.rotation;

It is obvious that Unity internally uses quaternion instead of euler. In fact, euler is just the data showing to users. According to resources online, people believe gimbal lock could be solved by using quaternion. But now, I have doubt about it.

We could make a simple experiment like what two bloggers did here:

Candycat1992 made this test:

transform.rotation = Quaternion.Identity;
transform.Rotate(new Vector3(0, 0, 40));  
transform.Rotate(new Vector3(0, 90, 0));  
transform.Rotate(new Vector3(80, 0, 0)); 

And Scott did this:

void Start () { 
		     newDirection = new Quaternion();
		     newDirection  = Quaternion.Euler(-90, 45, 0);
     //newDirection  = Quaternion.Euler(-90, 0, 45);
	void Update () { 
		     transform.rotation = Quaternion.Lerp(transform.rotation, newDirection, Time.deltaTime);

And gimbal lock appeared! But wait, how could quaternion fail to avoid gimbal lock?

Then I made my own test:

  • Set the rotation of the target object as (90, 0, 0)
  • Call transform.Rotate( 0, rate, 0 )
  • Call transform.Rotate( 0, 0, rate )

Gimbal lock never happens.

So what actually happened?

There are two concepts I misunderstood:

  1. Unity rotation order: In Unity, the order of rotation is ZXY. So if I set the original rotation of the object as (90, 0, 0), and then transform.Rotate(0, rate, 0) and transform.Rotate(0, 0, rate). It would not generate the gimbal lock. Because here it rotates in the order of XYZ, as rotation in X would not make any affect. But, if we call transform.Rotate( 90, y, z) directly, Unity would rotate in order of ZXY. In this way, it would generate gimbal lock.
  2. The way to use Quaternion: Quaternion could avoid gimbal lock, which is true. But remember, “could avoid” doesn’t mean always avoid. We could consider Quaternion as four dimension, comparing to three dimension of Euler, it has an extra dimension to avoid gimbal lock. However, if you rotate it the same as Euler axes, Quaternion does the same as Euler.  Therefore, we should be very careful about the way we use Quaternion.

Quaternion and gimbal lock is not easy to understand. So far I only know what went wrong, and I need to do more research about Quaternion and gimbal lock.

About Jinghui Dong

An engineer student from Cohort4 class in EAE program in University of Utah. Be passionate about the game development, game design, and still interested in art.
Bookmark the permalink.

Leave a Reply