In the previous post, Euler angles and Quaternions were compared and some important reasons which causes the unit Quaternions to become the dominant rotation system in graphics and game engines were studied. Now we know that we can't run away from quaternions if we want to become an animation programmer, gameplay programmer or graphics programmer, so lets check out two important feature of quaternions.

First lets check out the multiplication of a quaternion to a vector. One vector can be transformed by being multiplied to a quaternion. This multiplication can both scale and rotate the vector. If we multiply an unit quaternion to a vector, it just rotates it and no scale occurs. This is why all the graphics and game engines normalize quaternions before multiplying it to a vector. So after normalizing a quaternion, a vector can be rotated with this equation:

Result = q * v * inverse(q);

Where q is an unit quaternion and v is our vector which we want it to be rotated and Result is the vector v after being rotated by q. One most important feature of quaternion multiplication is that it's not commutative. So q1*q2 is not equal to q2*q1. This order of multiplication is really important for many animation algorithms like animation blending techniques. For example you can seek the importance of this rule in additive animations. Additive animations are one type of animation which are the difference of at least two animations. Mostly they are used for asynchronous events. For example you can create a breathing additive animation in which only character's spine bone is rotating in and out and other bones have no transformation. This additive animation can be added to any animation like idle aiming, running and many more. Now if we want to add an additive animation to an existing one, we should notice about the order of quaternion multiplication. First the main animation should be calculated, then the additive animation comes up on it so the rotations should be calculated in this order.

Now let's consider a simple example in which q1 is the rotation of main animation and q2 is the rotation of additive animation. the order of additive animation blending should be like this:

1- First apply q1 to the current vector (v) :

Result1 = q1 * v * inverse(q1)

2- Second apply q2 to the Result1:

Result2 = q2 * Result1 * inverse (q2) = q2 * q1 * v * inverse(q1) * inverse(q2)

So you can see if you want to add an animation to another you have to multiply them in reverse order like:

qn*....q2*q1*v*inverse(q1)*inverse(q2)*....*inverse(qn).

This means your vector first rotates by q1 and then q2, q3 ..., qn

Just note that most of the graphics and game engines overload the quaternion-vector multiplication with operator '*', so you can replace the 'q * v * inverse(q)' with just 'q * v'. If you are using an engine or API which has overloaded quaternion-vector multiplication then you can apply the multiplication order mentioned above, like this:

qn*....q2*q1

Now lets consider another important feature of unit quaternions. You can consider the imaginary vector part of a unit quaternion as the axis which your vector wants to rotate around and the scalar part is some value shows the amount of rotation around that axis. The imaginary vector part has a great feature and that is, its magnitude is equal to sin(a/2) where a is the rotation degree or radian which you want your vector to rotate around the imaginary vector part of your unit quaternion. Also there is another important feature for unit quaternions and that is the the scalar part is equal to cos(a/2). So whenever you want to create an unit quaternion which can rotate your object around an axis [x,y,z] with a degree equal to 'a', you can follow these steps in order:

1- First normalize your rotation axis:

[x,y,z]/ length( [x,y,z] )

2- Multiply the normalized rotation axis to sin(a/2) and use the result as your imaginary vector part.

3- Use cos(a/2) as your quaternion scalar part.

Now for a better understanding, lets consider an example in which you want to rotate your object around y-axis with 90 degrees. First you have to normalize your rotation axis which is [0, 1, 0]. In this example, our rotation axis is already normalized so we should not normalized it again. Second, we should create our imaginary vector part by multiplying the rotation axis to sin( 90/2 ):

sin (90/2) = sin (45) = 0.7071

Imaginary vector part = [0, 1, 0] *0.7071 = [0, 0.7071, 0]

At the third step, we should calculate the scalar part of our quaternion which is equal to cos (90/2):

w = cos (45) = 0.7071

The final quaternion should be like this:

[ 0.7071, 0, 0.7071, 0]

You can write it as its mathematical form:

0.7071 + 0i + 0.7071j + 0k = 0.7071 + 0.7071j

This can be considered inversely, for the times you have an unit quaternion and you want to know how much it can rotates your vector. In this situation, for finding the desired degree you can do this:

DesiredDegree = 2 * ArcCos(w)

Don't forget that a unit quaternion can just rotate an object between 0 and 180 degrees because it uses ArcCosine function to represent rotations. So if you want to rotate an object more than 180 degrees through time, you have to do it with more than one rotation. For example if you want to rotate your object with 240 degrees linearly through time, you can first Slerp it it with 120 degrees at t/2 and after that, Slerp it again with another 120 degrees at next t/2.

Conclusion

Most of the game and graphics engines use unit quaternions for rotations. Learning to work with them is very important. Some people prefer to use Euler angles for rotations because they are most understandable but the fact is that the used graphics or game engine converts Euler angles to an unit quaternion because of the reasons i mentioned in this post. So by working directly with unit quaternions the conversion step of an Euler angles rotation to unit quaternions can be omitted.

In this post two important feature of quaternions and unit quaternions were considered. These two important features are using frequently in Animation, Gameplay or Graphics programming so its good to keep them in mind.

## No comments:

## Post a Comment