Rosario 3D

My developer blog

Monthly Archives: April 2010

Base quaternion math

Difficult: basic, let’s keep it simple.

\hat{q}=(q_v, q_w) = i q_x + j q_y + k q_z + q_w

A quaternion is a tuple of four number that can be used to represent a rotation. They are composed of number q_w for the real part and a imaginary vector q_v.

The alternatives

You can say, “I already represent rotation with Euler angles and matrix, why I need other maths to do things that I already know?“.

Well, Euler angles are very simple, they only use three numbers but they can give you headaches in some cases, also while summing two rotation is quite simple, rotate a point with Euler angle require expensive trigonometric function, the really bad part about Euler angles is that different combination of angles can give you the same final result and the final result depends on the order in witch you combine the rotation.

Matrix are very generic, a 3×3 matrix can represent rotation, scale and shearing, combining two transformation is more expensive, but rotating a point quite easy. The bad part about rotation matrix is that given a matrix is not easy understand the orientation of the object. Also they use nine numbers, sixteen if you use homogeneous matrices, this can be a problem if you have few memory (for example when you want to pass a lot of parameter to a shader).

Quaternion operation

Quaternion can save you a lot of time, the basic idea is to store a quaternion to represent the orientation of your object and then use them to compute the matrix to send to openGL or if you are using shader you can use quaternion directly.

It can be strange but rotation in 4D are linear, so you can threat quaternion as a simple polynom:

Addition:

\hat{q}+\hat{r}= (q_v+r_v, q_w+r_w) = (i(q_x+r_x)+j(q_y+r_y)+k(q_z+r_z)+q_w+r_w)

Multiplication (to solve the equation remember that i^2=j^2=k^2=-1 and ij=-ji=k, ki=-ik=j, ij=-ji=k ):

\hat{q}\hat{r}=(iq_x+jq_y+kq_z+q_w)(ir_x+jr_y+kr_z+r_w)\newline=i(q_z r_z -q_z r_y + r_w q_z + q_w r_x)\newline+j(q_z r_x -q_x r_z + r_w q_y + q_w r_y)\newline+k(q_x r_y -q_y r_x + r_w q_z + q_w r_z)\newline+ q_w r_w -q_x r_x - q_y r_y - q_z r_z\newline=(q_v\times r_v + r_w q_v + q_w r_v, q_w r_w - q_v \cdot r_v)

While adding to quaternion is not meaningful for rotation, the product of two quaternion represent the composed rotation.

We can define the conjugate like this:

\hat{q}^\star = (q_v, q_w)^\star = (-q_v, q_w)

Conjugate quaternion represent opposite rotation, rotate a point with a quaternion and then rotate again with his conjugate put back in the place.

The norm is defined like the length of the vector.

n(\hat{q}) = \sqrt{\hat{q}\hat{q}^\star} = \sqrt{\hat{q}^\star\hat{q}} = \sqrt{q_v \cdot q_v +q_w^2} = \sqrt{q_x^2 + q_y^2 + q_z^2 + q_q^2}

Now, we would like to define the inverse operator, so we can derived a rotation that multiplied by another give 1 as result. Let’s try. Remember the norm definition? n(\hat{q}) = \sqrt{\hat{q}\hat{q}^\star} I try to square elevate both sides and I get n(\hat{q})^2 = \hat{q}\hat{q}^\star so

\dfrac{\hat{q}\hat{q}^\star }{ n(\hat{q})^2 } \rightarrow \hat{q}^-1 = \dfrac{\hat{q}^\star}{n(\hat{q})^2}

With quaternion compute the inverse is easy as compute a square radix and make a division. Even better is that we will always work with normalized quaternion, so the length will always be one. In this happy case the conjugate is equivalent to the inverse.

Nothing to scare till now, I present only definition, they are quite useless if we didn’t find any practical application, going out with some friend speaking how beautiful quaternion are is pretty lame.

Well as I wrote before, quaternion represent rotation so they can be used to rotate vertexes. If you have a point p and a normalized quaternion \hat{q} you can rotate the point with:

\hat{q} p \hat{q}^-1\newline =(q_v, q_w) p (-q_v, q_w)\newline =(q_v\times p + q_w p, -q_v \cdot p) (-q_v, q_w)\newline

Using quaternions multiplications the real part became:

-q_w (p \cdot q_v) -(q_v \times p + q_w \cdot p) \cdot (-q_v)=-q_w (p \cdot q_v) +q_w (p \cdot q_v) = 0

q_v\times p\cdot q_v is zero cause q_v\times p is perpendicular to q_v

While the imaginary part became:

(q_v\times p + q_w\cdot p)\times (-q_v) + (q_w\cdot p + q_v\times p)\cdot q_v + (q_v\cdot p) q_v\newline = q_v\times (q_w P + q_v\times p)+q_w^2 p +q_w (q_v\times p) + (q_v\cdot p) q_v\newline = q_w (q_v\times p) + q_v\times (q_v\times p) + q_w^2 p + q_w (q_v\times p) + (q_v\cdot p) q_v

Lagrange’s formula say a \times (b \times c) = b (a \cdot c) - c (a \cdot b) so we can simplify:

2 q_w (q_v\times p) + q_v (q_v\cdot p) - p (q_v\cdot q_v) + q_w^2 p +  (q_v\cdot p) q_v\newline = 2 q_w (q_v\times p) + 2 q_v (q_v\cdot p) + p  (q_w^2 - q_v\cdot q_v)

There are the coordinate of the rotated point.

If you want to rotate your object by an \theta angle around an axis v you can create create your quaternion like this:

\hat{q}= (\sin\left(\dfrac{\theta}{2}\right)v, \cos\left(\dfrac{\theta}{2}\right))

So the axis is related to the imaginary part and the angle represent somewhat the real part, and you can combine multiple quaternion to set complex pose. Now that you have quaternion and we can compose them, you can find useful to convert them to a matrix. Given a quaternion \hat{q} = (w x y z) this is the matrix that represent the same rotation:

\left(\begin{array}{ccc}1-2 (y^2+z^2 )&2 (xy-wz )&2 (wy+zx )\\2 (xy+sz )&1-2 (x^2+z^2 )&2 (yz-wx )\\2 (xz-qy )&2 (qx+yz )&1-2 (x^2+y^2 )\end{array}\right)

Quaternion are very fascinating, but they look quite complex, we really need them? Well the best part of quaternion is that you can interpolate them without to much problem and you get a really smooth orientation change. There are different technique to interpolate quaternion with different result, I’ll show them on another post. Stay tuned.

Advertisements