A Different Way to Understand Quaternion and Rotation
Before We Start
Quaternion is widely used in game engines to represent 3D rotation. As a game engineer you might be using quaternion explicitly or implicitly in your daily work, but do you really understand what is going on under the hood when you are calling “rotate a vector” or “combine two rotations”? Why rotating a vector \(\vec{v}\) by quaternion \(q\) is calculated by a “sandwich” multiplication: \(q\vec{v}q^{-1}\) ? Why rotating by quaternion \(q_1\) then \(q_2\) is in the reversed order: \({q_2}{q_1}\), and can you visualize the result rotation axis and angle?
Understanding quaternions also leads to more efficient use of quaternion. For example, one common situation in game development is that we need an object to face its opposite direction. What we usually would do is to get the normal or forward vector, negate it, build a rotation out of it, and assign the rotation to the object. Later in this article we will see how much calculation we need to do in this process. However with the understanding of quaternion, we only need to do \(q=(q.y,-q.x,q.w,-q.z)\), and I will show you why.
In this article, I will try to avoid touching the algebra structure of quaternion, or having to imagine a 4 dimensional hyper sphere. I will start with a special rotation operation: flip, and use that to visualize quaternion in a more accessible and geometrical way. This article will be split into 2 parts. In Part 1 we will talk about the idea of quaternion, understand and visualize how it rotates a vector and how to compose rotations. In Part 2 we will talk about how to make use of our understanding in Part 1, and how it is used in game engine versus rotation matrix and Euler angles.
I would assume you are comfortable with 3D math (vector dot product and cross product) and basic trigonometry.
Part 1. Theory
Quaternion Definition
Quaternion is a 4-tuple denoted as \(q=(x,y,z,w)\). The length of a quaternion is defined as \(\left|q\right| =\sqrt{x^{2}+y^{2}+z^{2}+w^{2}}\), just as you would expected from a 4D vector.
In order to represent 3D rotation, we have a constraint on the quaternions we use. But before that I want to introduce Euler’s rotation theorem:
Any rotation in 3D space is equivalent to a single rotation of angle \(θ\) along some axis \(\vec{v}\).
We can use quaternion to describe this angle-axis rotation : \(q=(\sin\frac{θ}{2}\vec{v}.x,\sin\frac{θ}{2}\vec{v}.y,\sin\frac{θ}{2}\vec{v}.z,\cos\frac{θ}{2})\), or in a more compact form \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\). We call this form the vector form of a quaternion, and we will use this form throughout this article. You might be thinking why we are using \(\frac{θ}{2}\) other than using \(θ\) directly. I will explain that in a later section.
It is easy to see the length of this quaternion \(\left|q\right|=\sqrt{\sin^{2}\frac{θ}{2}\left|\vec{v}\right|^{2}+\cos^{2}\frac{θ}{2}}=1\). (Remember the axis \(\vec{v}\) is a unit vector that \(\left|\vec{v}\right|=1\)). We call it a unit quaternion if the length \(\left|q\right|=1\). So we can rewrite Euler’s rotation theorem in quaternion term:
Any 3D rotation is equivalent a unit quaternion \(q\) that \(\left|q\right|=1\).
From now on, any quaternion \(q\) used in this article is by default a unit quaternion, and we will use \(q\) to describe rotations.
Rotation and Flip
Now let’s forget quaternion for a minute, and focus on the nature of rotations. This part is the key to understand quaternion calculation in an easier way.
Any 3D rotation can be composed by 2 flips along some axes.
The reason we want to break down a rotation into flips, is that flips are much easier to think and calculate than general 3D rotation. We will start from flip and build our way to understand rotation. Here is a loose proof of this idea. We define counter-clockwise as the positive direction of rotation. First consider a special case. We have a rotation \(q\), which rotates \(+90^{\circ}\) along axis Z. Now I can say this rotation is the same as 2 flips along axis \(\vec{a}\) and \(\vec{b}\), both of them are on XY plane, and the angle from \(\vec{a}\) to \(\vec{b}\) is \(+45^{\circ}\).
We demonstrate this through Figure 1. For any vector \(\vec{v}\), the result of this rotation is \(\vec{v''}\) , which is the same as flip \(\vec{v}\) along axis \(\vec{a}\) and get \(\vec{v'}\), and then flip \(\vec{v'}\) along axis \(\vec{b}\) and get \(\vec{v''}\).
It doesn’t matter where \(\vec{a}\) and \(\vec{b}\) are on the XY plane, but the order must be kept. If we choose \(\vec{b}\) by rotating \(\vec{a}\) along axis Z by \(+45^{\circ}\) with the positive direction we defined above, then we must flip along \(\vec{a}\) first then along \(\vec{b}\) to get our target rotation. The order and the sign of angle is important, as you can easily see flip along \(\vec{b}\) first then along \(\vec{a}\) will give a different result.
It’s not hard to generalize to a rotation of any angle \(θ\) along Z axis. And in this case, the angle from \(\vec{a}\) to \(\vec{b}\) is \(\frac{θ}{2}\).
What if the axis is not Z axis but any unit vector \(\vec{u}\) ? It turns out to be very straight forward. \(\vec{a}\) and \(\vec{b}\) are no longer on XY plane but on a plane cross the origin and perpendicular to \(\vec{u}\), as in Figure 2.
Now we can rewrite our flip composition rule in a more specific form:
Any 3D rotation equivalent to rotating angle \(θ\) along axis \(\vec{v}\) can be represented as a sequence of 2 flips along axis \(\vec{a}\) and \(\vec{b}\), such that \(\vec{a}·\vec{v}=0\), \(\vec{b}·\vec{v}=0\) and the angle from \(\vec{a}\) to \(\vec{b}\): \(<\vec{a},\vec{b}>=\frac{θ}{2}\).
This representation means if we fully understand flip, which is easier to visualize, we can fully understand rotation and quaternions, since any quaternion can be broken down to flips.
Quaternion and Flip
Now let’s recall the quaternion vector form \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\). With the discussion of flips above, you can almost immediately see why we are using \(\frac{θ}{2}\) here.
Think about flips again. A flip along axis \(\vec{a}\) is also a \(180^{\circ}\) rotation along axis \(\vec{a}\). So this flip can be represented in quaternion term
From now on we will use quaternion to represent flip. Actually any unit quaternion with \(q.w=0\) is a flip along axis \((q.x,q.y,q.z)\).
Flip Composition
Here we need to introduce the multiplication of general quaternion. Let \(q_1=(\vec{v_1},w_1)\), \(q_2=(\vec{v_2},w_2)\) then
Note here \(q_1\) and \(q_2\) are not necessarily unit quaternion, so even I’m using vector form, there’s no need to put \(\sin\frac{θ}{2}\) and \(\cos\frac{θ}{2}\) as we did for unit quaternions. It’s hard to explain this definition without introducing the algebra structure of quaternions, so I will skip that. If you are interesting to know how this is derived, quaternion Wiki page has a very straight forward introduction.
We are not going to use this general quaternion multiplication in Part 1. Here we only need to know a simpler form, the multiplication of flips. Let \(q_a=(\vec{a},0)\), \(q_b=(\vec{b},0)\) then
It is naturally derived from the general form, and we will be only using this multiplication in Part 1.
With flip multiplication defined, we can rewrite our flip composition rule again:
Any 3D rotation \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\) can be represented as a sequence of 2 flips \(q_a=(\vec{a},0)\) and \(q_b=(\vec{b},0)\), such that
where \(\vec{a}·\vec{v}=0\), \(\vec{b}·\vec{v}=0\) and the angle from \(\vec{a}\) to \(\vec{b}\): \(<\vec{a},\vec{b}>=\frac{θ}{2}\).
You might be thinking why it is not \(q= {q_a}{q_b}\) instead. We will show where the order and the negative sign coming from in the proof.
\(\vec{a}·\vec{b}=\cos<\vec{a},\vec{b}>\left|\vec{a}\right|\left|\vec{b}\right|=\cos\frac{θ}{2}\). Since \(\vec{a}·\vec{v}=0\), \(\vec{b}·\vec{v}=0\) and \(\left|\vec{v}\right|=1\), we have \(\vec{a}×\vec{b}=\sin<\vec{a},\vec{b}>\left|\vec{a}\right|\left|\vec{b}\right|\vec{v}=\sin\frac{θ}{2}\vec{v}\).
If you are not sure about the direction of the cross product, see Figure 2.
Here you can also clearly see why we are using \(\sin\frac{θ}{2}\) and \(\cos\frac{θ}{2}\) in quaternions.
One thing I need to mention here is the negation of a quaternion. \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\), then
Recall that \(\sinθ=\sin(π-θ)\) and \(-\cosθ=\cos(π-θ)\), then \(-\sinθ=\sin(-θ)\) and \(\cosθ=\cos(-θ)\).
It shows that \(-q\) is a rotation along axis \(\vec{v}\) of angle \(-(2π-θ)\), which is exactly the same rotation as \(q\). For example if \(θ=90^{\circ}\) then \(-(2π-θ)=-270^{\circ}\), rotate \(90^{\circ}\) along axis \(\vec{v}\) is the same as rotate \(270^{\circ}\) degree but in the opposite direction along the same axis \(\vec{v}\).
The fact that \(q\) and \(–q\) represents the same rotation is usually called double-cover. However in our calculation I don’t want you to simply think \(q\) and \(–q\) are the same. They are different in quaternion space, even though they map to the same 3D rotation. The negative sign of the flip composition needs to be there.
The order of \(q=-{q_b}{q_a}\) on the right hand side is important. It means flip along \(\vec{a}\) first and then \(\vec{b}\). Actually all unit quaternion multiplication needs to be “read” from right to left when we are thinking about the order of applying those rotations.
Flip Vector
Given a flip \(q_a=(\vec{a},0)\) and vector \(\vec{v}\), we are ready to calculate the result of the flip \(\vec{v'}\).
According to flip definition, \(\vec{v}\), \(\vec{a}\) and \(\vec{v'}\) are on the same plane, and the angle \(<\vec{v},\vec{a}>=<\vec{a},\vec{v'}>\).
If we treat \(\vec{v}\) and \(\vec{v'}\) as the axis of flip \(q_v=(\vec{v},0)\) and \(q_v'=(\vec{v'},0)\). From our flip composition rule, flipping along axis \(\vec{v}\) then \(\vec{a}\) should give us the same rotation as flipping along axis \(\vec{a}\) then \(\vec{v'}\).
We can actually calculate the result rotation. Let \(<\vec{v},\vec{a}>=<\vec{a},\vec{v'}>=\frac{θ}{2}\), \(\vec{u}=\frac{\vec{v}×\vec{a}}{\left|\vec{v}×\vec{a}\right|}=\frac{\vec{a}×\vec{v'}}{\left|\vec{a}×\vec{v'}\right|}\). Then the result rotation is of angle \(θ\) along axis \(\vec{u}\).
This gives \({q_v'}{q_a}={q_a}{q_v}\).
(Here \(\left|\vec{v}×\vec{a}\right|=\left|\vec{a}×\vec{v'}\right|=\sin\frac{θ}{2}\).If you are not sure what’s going on here, go back Flip Composition and read the proof)
Now we need to introduce the inverse of a quaternion. The inverse of \(q\) is denoted as \(q^{-1}\), such that \(qq^{-1}=q^{-1}q=(\vec{0},1)\).
\(I=(\vec{0},1)\) is called identity quaternion, means no rotation at all. You can think of \(I=(\sin0\vec{v},\cos0)\), which means rotating \(0^{\circ}\) along any axis \(\vec{v}\). We haven’t gone into quaternion multiplication or rotation composition, but it’s not hard to see for any quaternion \(q\), \(qI=Iq=q\).
In the case of unit quaternion, the idea of inversed quaternion is if you apply a rotation, then apply its inverse, the result should be no rotation at all. And it is the same if you apply an inversed rotation then apply the original one.
For any unit quaternion \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\), then \(q^{-1}=(-\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\). You can understand this in two ways, either \(q^{-1}=(\sin\frac{θ}{2}(-\vec{v}),\cos\frac{θ}{2})\) or \(q^{-1}=(\sin\frac{-θ}{2}\vec{v},\cos\frac{-θ}{2})\). \(q^{-1}\) is either a rotation of angle \(θ\) along axis \(-\vec{v}\), or a rotation of angle \(–θ\) along axis \(\vec{v}\). Either way it will cancel out the original rotation.
I will give a quick proof in the case of flip. You can try extend this proof to general unit quaternion. If \(q_a=(\vec{a},0)\), \(q_a^{-1}=(-\vec{a},0)\), we have
(Make sure you understand the difference between \(q^{-1}\) and \(–q\). Read Flip Composition about quaternion negation if you are not sure.)
We can go back to previous result of flipping vector \({q_v'}{q_a}={q_a}{q_v}\). Apply inverse flip of \(q_a\) on both side, the equation becomes
This provides us a way to calculate the result of flip. Since we only need the vector part of the result, we can denote this as
When we put a vector \(\vec{v}\) in quaternion multiplication, we are implicitly making that vector the axis of a flip to stuff it into a quaternion \((\vec{v},0)\). This is how the “sandwich” multiplication form comes from, but only in the form of flip. We will prove that our result holds the same for any rotation in the next section.
Rotate Vector
We know any 3D rotation \(q\) can be broken down into 2 flips \(q= -{q_b}{q_a}\), which means flipping along \(\vec{a}\) first and then \(\vec{b}\). So for a vector \(\vec{v}\), we apply the first flip and get
Then we apply the second flip \(\vec{v'}\) and get
So the final result is
Here you can see why \(q= -{q_b}{q_a}\) needs to be in this order.
One thing we need to prove
At this point, we fully explained how to rotate a vector using quaternion.
Rotation Composition
Given rotation \(q_1\) and \(q_2\), from the formula in the previous section, if we rotate vector \(\vec{v}\) by \(q_1\) first then by \(q_2\), we have
It is the same as apply the combined rotation \(q={q_2}{q_1}\). Be careful about the multiplication order.
Again we need to prove \({q_1^{-1}}{q_2^{-1}}=({q_2}{q_1})^{-1}\), but we will do this later. This equation is actually very easy to understand in geometric term. We have a combined rotation \(q={q_2}{q_1}\) that rotates \(q_1\) first then rotates \(q_2\). If we want to undo this rotation, which means apply the inverse \(q^{-1}=({q_2}{q_1})^{-1}\), we need to undo \(q_2\) first then undo \(q_1\), that is effectively \(q_1^{-1}q_2^{-1}\).
What does it really mean to combine 2 rotations, can we visualize the rotation axis and angle of the result? By converting rotations to flips we actually do that.
Let \(q_1=(\sin\frac{θ_1}{2}\vec{v_1},\cos\frac{θ_1}{2})\), \(q_2=(\sin\frac{θ_2}{2}\vec{v_2},\cos\frac{θ_2}{2})\), we need to choose a special flip break down, such that they share one flip: \(q_1=-{q_c}{q_a}\), \(q_2=-{q_b}{q_c}\).
Can we find such a break down? Remember the rule of flip composition requires the flip axis to be perpendicular to the rotation axis, that is \(\vec{c}·\vec{v_1}=0\), \(\vec{c}·\vec{v_2}=0\), we can choose \(\vec{c}=\frac{\vec{v_1}×\vec{v_2}}{\left|\vec{v_1}×\vec{v_2}\right|}\).
Based on \(\vec{c}\) we can find out the other two axes: rotate \(\vec{c}\) along axis \(\vec{v_1}\) by angle \(-\frac{θ_1}{2}\) results in \(\vec{a}\); rotate \(\vec{c}\) along axis \(\vec{v_2}\) by angle \(\frac{θ_2}{2}\) results in \(\vec{b}\). This process is demonstrated in Figure 4.
Now we have \(\vec{a}·\vec{v_1}=0\), \(\vec{c}·\vec{v_1}=0\), \(<\vec{a},\vec{c}>=\frac{θ_1}{2}\) and \(\vec{c}·\vec{v_2}=0\), \(\vec{b}·\vec{v_2}=0\), \(<\vec{c},\vec{b}>=\frac{θ_2}{2}\). Our break down \(q_1=-{q_c}{q_a}\), \(q_2=-{q_b}{q_c}\) is valid. The combined rotation can be written as
Here we need to prove this
It shows that the combined rotation can be composed by flip \(q_a\) and \(q_b\), which tells the combined rotation is a rotation of angle \(2<\vec{a},\vec{b}>\) along axis \(\vec{u}=\frac{\vec{a}×\vec{b}}{\left|\vec{a}×\vec{b}\right|}\).
In Figure 4, Blue plane is based on \(\vec{v_1}\) and \(\vec{v_1}\), \(\vec{c}\) is perpendicular to that plane. Orange plane is based on \(\vec{a}\) and \(\vec{b}\), the result rotation axis \(\vec{u}\) is perpendicular to that plane.
With the same method, let’s prove the thing we left out:
Summary of Part 1
In Part 1, we covered the definition of quaternion \(q=(x,y,z,w)\), the vector form of quaternion \(q=(\vec{v},w)\), unit quaternion \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\) and how it is used to represent a rotation.
We also talked about negation of quaternion \(–q\), and its double cover property; the inverse of quaternion \(q^{-1}\) and identity quaternion \(I=(\vec{0},1)\).
We use quaternion to represent flip \(q_a=(\vec{a},0)\), and derive the rule of flip composition \(q=-{q_b}{q_a}\). Based on this rule, we visualized and proved how quaternion rotates a vector by \(\vec{v'}=q\vec{v}q^{-1}\) and how rotation gets composed by \(q={q_2}{q_1}\).
We slightly touched quaternion multiplication, and we proved an important equation \({q_1^{-1}}{q_2^{-1}}=({q_2}{q_1})^{-1}\).
Hopefully you have a clear idea to think in quaternions now before we head to the application part. Although I’m not going to discuss quaternion’s algebra structure, it definitely helps deepening your understanding. If you are interested to know, quaternion Wiki page is a good resource.
It also provides a good way to visualize a quaternion in 4D here. Our idea of breaking down rotations into 2 flips essentially means all quaternions in 4D space can be generated by elements in it’s largest 3D sub-space \(\left\{q.w=0\right\}\), and all elements in this sub-space are flips.
Part 2. Application
In Part 2 we will be talking about using quaternion to solve real problems in programming. I will be using general vector form \(q=(\vec{v},w)\) even for unit quaternion instead of \(q=(\sin\frac{θ}{2}\vec{v},\cos\frac{θ}{2})\), since it is closed to the actual data format.
Recall the definition of general quaternion multiplication we mentioned in Part 1. Let \(q_1=(\vec{v_1},w_1)\), \(q_2=(\vec{v_2},w_2)\) then
We will be using this a lot in the following sections.
The coordinate system we use is Z up and right-handed.
Calculation of Vector Rotation
In this section we will derive the formula which most game engine are using to rotate a vector with quaternion. Given a rotation \(q=(\vec{v},w)\) and vector \(\vec{p}\), the rotation result is
Since we only want the vector part
Here we need to use the following equation of cross product to simplify the result
So in our case
Remember \(q\) is unit quaternion, so \(\left|\vec{v}\right|^{2}+w^{2}=1\). We have
Now we can simplify our rotation result to get rid of the dot product
World Rotation and Local Rotation
Let’s look at rotation composition again. The combined rotation \(q={q_2}{q_1}\) means rotating \(q_1\) first then \(q_2\). This right to left order only holds when \(q_2\) is a world rotation, or in another term the rotation axis \(\vec{v_2}\) of \(q_2\) is in world space. Then what if \(q_2\) is a local rotation, which means the rotation axis \(\vec{v_2}\) of \(q_2\) is in the local space after \(q_1\) rotation.
As an example of local rotation, imagine yourself lying down on the ground and facing up, now flip around to face the ground. What you just did is a \(180^{\circ}\) local rotation along Z axis. The rotation axis is not the world Z axis (which will be the up direction) but your local Z axis.
If we have an object with rotation \({q_1}=(\vec{v_1},{w_1})\), now we want to apply a local rotation \({q_{2L}}=(\vec{v_2},{w_2})\). We can convert the local rotation \(q_{2L}\) to world rotation \(q_{2W}\) by converting its rotation axis into world space. Since \(\vec{v_2}\) is in local space of \(q_1\), converting it into world space means rotating it by \(q_1\), so the world space rotation axis is \(\vec{v_{2W}}={q_1}\vec{v_2}{q_1}^{-1}\).
(Technically the rotation axis is \(\frac{\vec{v_2}}{\left|\vec{v_2}\right|}\), but since rotation angle is the same for local and world space, \(\left|\vec{v_2}\right|=\left|\vec{v_{2W}}\right|=\sin\frac{θ}{2}\), we can just use \(\vec{v_2}\) in the calculation).
This equation tells us to convert a local rotation to world rotation, we can do the same as rotating a vector by using “sandwich” multiplication \({q_{2W}}={q_1}{q_{2L}}{q_1}^{-1}\). It also makes sense in geometric term. If we undo \(q_1\), now local space and world space are the same, we can then apply \(q_{2L}\) and apply \(q_1\) again to get the world rotation we want.
One thing I need to prove here
With the world rotation \(q_{2W}\) calculated, result of combined rotation is
This means when we rotate \(q_1\) then rotate \(q_2\), if \(q_2\) is in world space, then combined rotation is \(q={q_2}{q_1}\) (right to left); if \(q_2\) is in local space of \(q_1\), the combined rotation is \(q={q_1}{q_2}\) (left to right).
Rotation along X/Y/Z Axis
We can now go back to the problem I mentioned at the very beginning: we need an object to face its opposite direction. More clearly we have an object with rotation \(q=((x,y,z),w)\), and we want to flip it along local Z axis, that is rotate it \(180^{\circ}\) along its local Z axis. This extra rotation is denoted as \(q'=((0,0,\sin\frac{180^{\circ}}{2}),\cos\frac{180^{\circ}}{2})=((0,0,1),0)\). Based on local rotation composition we proved in previous section, the result is
If we generalize the angle to \(θ\), then \(q'=((0,0,\sin\frac{θ}{2}),\cos\frac{θ}{2})\), then the result is:
If we want to flip along world Z axis instead, we just need to change the multiplication order:
We can use the same method to generalize the angle to \(θ\), and let \(q'=((0,0,\sin\frac{θ}{2}),\cos\frac{θ}{2})\),
It is easy to extend the result to X and Y axis. I list the result summary as the following.
Flip along local axis:
Rotate \(θ\) along local axis:
Flip along world axis:
Rotate \(θ\) along world axis:
Euler Angles to Quaternion
Quaternion is an instruction for rotation: rotate angle \(θ\) along axis \(\vec{v}\). Euler angles is a sequence of 3 instructions: rotate yaw angle along world axis Z, then rotate pitch angle along local axis Y, then rotate roll angle along local axis X.
It is very natural to see how Euler angles can be converted to quaternion. If we use \(Y,P,R\) for angle yaw pitch and roll, then these 3 rotations to can be denoted in quaternion \(q_Y=(0,0,\sin\frac{Y}{2},\cos\frac{Y}{2})\), \(q_P=(0,\sin\frac{P}{2},0,\cos\frac{P}{2})\), \(q_R=(\sin\frac{R}{2},0,0,\cos\frac{R}{2})\). Since pitch and roll are local rotations, the combined rotation will be
Solving this we have the conversion from Euler angles to quaternion.
Converting quaternion to Euler angles, however, is tricky. It is easier if we convert quaternion to rotation matrix first then convert the rotation matrix to Euler angles, than trying to obtain the conversion directly. We will talk about this after the next section.
Quaternion and Rotation Matrix
If we say quaternion is an instruction, Euler angles are 3 instructions, then the rotation matrix stores the rotation result directly. Remember each row of the rotation matrix is the X, Y, Z axis after this rotation, which means given a rotation \(q=(x,y,z,w)\), it’s corresponding rotation matrix is
By calculating the rotation result of the 3 axes, we get the conversion from quaternion to rotation matrix
To convert from rotation matrix to quaternion, we can sum up diagonal elements of the matrix and get
Remember as a unit quaternion \(x^{2}+y^{2}+z^{2}+w^{2}=1\),
Similarly we can obtain \(x,y,z\) by
We can avoid calculating square root 4 times, by using the element we already calculated. Say we calculate \(w=\frac{1}{2}\sqrt{M_{11}+M_{22}+M_{33}+1}\) first, then we can get \(x,y,z\) by
You need to be careful if the value of \(w\) is closed to 0 (means \(M_{11}+M_{22}+M_{33}+1\) is closed to 0, no need to do square root). In this case you want to calculate one of \(x,y,z\) instead. You can simply choose the one has the largest absolute value, and calculate the other 3 elements in a similar fashion.
Quaternion to Euler Angles
Before we try to convert quaternion to Euler angles, let’s review how Euler angles can be converted to rotation matrix. As we know Euler angles are 3 instructions, it could be viewed as 3 rotation matrix:
The result rotation matrix is
You can also derive this by converting Euler angles to quaternion, then quaternion to rotation matrix, and by applying trigonometric double-angle formula you should get the same result.
If you put this result side by side with our quaternion to rotation matrix conversion, which I put here again for reference.
You can easily spot this:
Now we can write down the conversion from quaternion to Euler angles
However we still have a problem when pitch is near \(90^{\circ}\) or \(-90^{\circ}\). This is called singularity. This issue is explained more in this website. In this case \(\cos{P}=0,\sin{P}=1\) or \(\cos{P}=0,\sin{}P=-1\), and the rotation matrix becomes:
The formula we used to calculate yaw and roll becomes \(\mathrm{atan2}(0,0)\), which will give an invalid value.
We need to go a different way, recall the conversion from Euler angles to quaternion.
If \(P=90^{\circ}\), then \(x=-z=\frac{\sqrt{2}}{2}\sin\frac{R-Y}{2}\), \(y=w=\frac{\sqrt{2}}{2}\cos\frac{R-Y}{2}\), then we have
Similarly, if \(P=-90^{\circ}\), then \(x=z=\frac{\sqrt{2}}{2}\sin\frac{R+Y}{2}\), \(-y=w=\frac{\sqrt{2}}{2}\cos\frac{R+Y}{2}\), then we have
Imagine an airplane facing straight up or down, yaw and roll basically means rotating along the same axis. We can simply let yaw be zero, and only calculate roll. So if \(P≈±90^{\circ}\), then
Finally, since \(\sin{P}=-2xz+2yw\), we only need to test \(-2xz+2yw≈±1\) to test if pitch is near \(±90^{\circ}\).
Summary of Part 2
In Part 2 we talked about different multiplication order for combining world rotations or local rotations.
We derive the formula to calculate the result of rotating a vector by a quaternion. We also find out a quick way to apply rotation along X/Y/Z axis.
We discussed conversion between quaternion, Euler angles and rotation matrix.
As you can see whenever you get or set Euler angles in the game engine, you are doing a conversion from or to quaternion, and there will be trigonometric calculation involved. Try to avoid them if you can do quaternion calculation directly.
Also some systems use left-handed or Y up coordinate, or have different Euler angles convention. Be sure you understand the system you are using, since quaternion and Euler angles conversion will be very different.
Appendix
Derive Quaternion Multiplication
We can actually derive the general quaternion multiplication from the special flip break down \(q_1=-{q_c}{q_a}\), \(q_2=-{q_b}{q_c}\), we used to visualize the result of rotation composition. That is if we define flip multiplication \({q_a}{q_b}=(\vec{a},0)(\vec{b},0)=(\vec{a}×\vec{b},-\vec{a}·\vec{b})\) directly, we can proof what general quaternion multiplication \({q_1}{q_2}=(\sin\frac{θ_1}{2}\vec{v_1},\cos\frac{θ_1}{2})(\sin\frac{θ_2}{2}\vec{v_2},\cos\frac{θ_2}{2})\) would look like. If you don’t remember this, see Rotation Composition section in Part 1.
Here are some equations we will be using:
Recall how we choose the flip break down \(\vec{c}=\frac{\vec{v_1}×\vec{v_2}}{\left|\vec{v_1}×\vec{v_2}\right|}\).
Rotate \(\vec{c}\) along axis \(\vec{v_1}\) by angle \(-\frac{θ_1}{2}\) we get
Rotate \(\vec{c}\) along axis \(\vec{v_2}\) by angle \(\frac{θ_2}{2}\) we get
And we will have
From the previous proof of rotation composition we know \(q={q_2}{q_1}=-{q_b}{q_a}\), that is
which is the definition of quaternion multiplication of \({q_1}{q_2}=(\sin\frac{θ_1}{2}\vec{v_1},\cos\frac{θ_1}{2})(\sin\frac{θ_2}{2}\vec{v_2},\cos\frac{θ_2}{2})\).