# Rotation matrix derived from quaternion is opposite of expected direction

When I calculate a rotation matrix from a quaternion, it seems to be in the opposite direction. For instance:

For a rotation of +45 degrees about the Y-axis, I would expect to get the following matrix:

# Pesudo Code
m1 = Matrix()
m1.RotateEulerY(45)
m1 =
| 0.71  0.00 0.71 0.00  |
| 0.00  1.00 0.00 0.00  |
| -0.71 0.00 0.71 0.00  |
| 0.00  0.00 0.00 1.00  |


However the rotation matrix calculated from a quaternion with the same rotation is

# Pesudo Code
axis_angle = AxisAngle((0,1,0), 45)
quat = Quaternion(axis_angle)
quat = { 0.0,0.375,0.0,0.927 }

rotate_matrix = quat.ToRotationMatrix()
rotate_matrix =
| 0.72 0.00 -0.69 0.00 |
| 0.00 1.00 0.00  0.00 |
| 0.69 0.00 0.72  0.00 |
| 0.00 0.00 0.00  1.00 |


Which happens to be a rotation of -45 about the Y-axis. I have tried to get the rotation matrix from the angle axis and it the same as the expected result.

Is this the expected behaviour or have I made a mistake/assumption somewhere? (Yes, the answers are not exactly the same; for now I am assuming it is a rounding error since the answers are so close).

Background info: I am using column major matrix, i.e. OpenGL style. The algorithms used to calculate the rotation matrix from the quaternion comes from http://www.j3d.org/matrix_faq/matrfaq_latest.html, Q54.

UPDATE #1

As teodron suggested, , I have tried to do a Quaternion(q) to Rotation Matrix(M) and back to Quaternion combination (i.e. q->M->q'). I also did a M->q->M' conversion for sanity check.

While q == q' and M == M', the conversion between q and M is wrong!

The rotation used in the example is the same as before, a rotation of +45 around the Y-axis. The matrix is right hand orientated, using column major vector, a.k.a openGL conformance. Matrix and Quaternion format is shown below:

#       | 0 4 8  12 |
# M =   | 1 5 9  13 |
#       | 2 6 10 14 |
#       | 3 7 11 15 |
#
# q =   {i,j,k,w}


First convert M to q then back to q.

#M->q->M'

# I am confident M is the correct representation for the rotation.
M =
| 0.71 0.00 0.71 0.00 |
| 0.00 1.00 0.00 0.00 |
| -0.71 0.00 0.71 0.00 |
| 0.00 0.00 0.00 1.00 |

# Here I would expect the quaternion to be all positive, but the
# j component is negative!

q =
{ 0.00, -0.38,0.00, 0.92}

# M' == M
M' =
| 0.71 0.00 0.71 0.00 |
| -0.00 1.00 0.00 0.00 |
| -0.71 -0.00 0.71 0.00 |
| 0.00 0.00 0.00 1.00 |


second part: from q to M to q'

#q->M->q'

# I have created the quaternion from both an axis angle and euler angle
# and both approaches give me the same answer
q =
{ 0.00, 0.37,0.00, 0.93}

# Here M is different from the Matrix in the first part
M =
| 0.72 0.00 -0.69 0.00 |
| 0.00 1.00 0.00 0.00 |
| 0.69 0.00 0.72 0.00 |
| 0.00 0.00 0.00 1.00 |

# but q' == q!
q' =
{ 0.00, 0.37,0.00, 0.93}


Since the q<->M is consistently wrong, I thought I would focus on q->M for now.

I had check the formula to convert a quaternion to matrix across different sources and they are all consistent with one another. Basically the normal maths style, row-major matrix is as follows: (taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm)

| 1 - 2(kk + jj)    2(ij - kw)       2(jw + ik)    |
| 2(ij + kw)        1 - 2(ii + kk)   2(jk - iw)    |
| 2(ik - jw)        2(jk + iw)       1- 2(jj + ii) |


Hence the openGL column major matrix equivalent should be

| 1 - 2(kk + jj)    2(ij + kw)      2(ik - jw)      |
| 2(ij - kw)        1 - 2(ii + kk)  2(jk + iw)      |
| 2(jw + ik)        2(jk - iw)      1- 2(jj + ii)   |


Comparing this with the column major rotation matrix as generated via a rotation of angle A around Y axis.

| cos(A)    0   sinA    |
| 0         1   0       |
| -sinA     0   cosA    |


Now the problem is more obvious to me: Looking at M[2] for both matrices, the quaternion matrix ,(2(jw + ik)), will produce a positive while the rotation matrix, -sinA, will produce a negative value!

I am at a loss here; I cannot think of a reason why these two matrices differ and I don't know what should I investigate next.Any ideas?

UPDATE #2

This is an update to explain the solution to the problem. Basically it boils down to how I ordered the elements in the matrices. For my case I did not need to transpose the original quaternion to matrix formula; some websites do perform the transpose because they have ordered it differently.

• Check this out as well gamedev.stackexchange.com/questions/33099/… – teodron Aug 18 '12 at 14:35
• I did look at that question but thought that my problem was not related to inverting the matrix/quaternion. Is there an implicit inversion going on when doing the conversion? – wschang Aug 18 '12 at 20:01
• The basic moral of that question is this: when converting a matrix to a quaternion, there's an ambiguity caused by the fact that two different quaternions, q and -q, represent the same rotation as the matrix. What happened in that question was that the transformation chain quat->Matrix, Matrix->quat was fed a certain input quaternion and the resulting matrix wasn't converted to the original quaternion, but to the opposite (minus) of the initial quaternion. In your case, it seems you're getting the conjugate of the quaternion, which is indeed different..and quite inconsistent! – teodron Aug 18 '12 at 20:19
• Test this: start with a quat q1. Execute this chain: q1->M1, M1->q2. Is q1 == q2 or q1 == -q2? (approximately). If yes, the conversion routines are ok. Alternatively, start with a rotation matrix: M -> q -> M'. M and M' should be equal (again, neglecting numerical inaccuracies). – teodron Aug 18 '12 at 20:30
• @teodron I have just updated my question with the results and so far no luck in detecting what went wrong :-( – wschang Aug 19 '12 at 3:26

You're getting the transpose of the matrix you wanted, so you probably just have a row-vector vs. column-vector issue; that is, you're using row vectors and the source where you found the quat-to-matrix conversion formula was using column vectors, or vice versa.

• Yes, that was what I thought as well, but so far I can't see anything obviously wrong.I have just updated my question with an example of the formulas I have used, so please let me know if you spot anything wrong with it! – wschang Aug 19 '12 at 3:25
• @gilamesh You wrote: "the normal maths style, row-major matrix is as follows" - actually the "normal maths style" uses column vectors. Indeed if you scroll down to the derivation section on that page you can see that he writes P2 = [M] P1, indicating column vector convention. So you should use his matrix just as written, and not transpose it. I presume a similar issue affects the matrix-to-quat conversion. This should resolve your issues. :) – Nathan Reed Aug 19 '12 at 5:38
• @gilamesh BTW, a bit of a nitpick, but don't confuse "row-major" and "column-major" with row vectors and column vectors. The former has to do with the storage of matrices in memory, the latter has to do with multiplication order and math notation. They are two distinct choices of convention. (OpenGL uses column-major layout and column vectors, but most math libraries use row-major layout, whether they use row vectors or column vectors.) – Nathan Reed Aug 19 '12 at 5:46
• No, you are right in pointing the difference; I was confused! To clarify, "column vector" is another name for "post multiply" (V' = MV) and "row vector" is the same as "pre multiply" (V' = VM)? But even if the derivation is based on column vector, wouldn't I still need to transpose the matrix because OpenGL uses column major layout? – wschang Aug 19 '12 at 7:33
• Actually now that I think about it, I am getting confused on matrix multiplication. For column vectors, if C = AB, I would take the row of A and multiply it with the column of B. However since OpenGL is column is column major, wouldn't that mean I should take the column of A and multiply with the row of B instead? – wschang Aug 19 '12 at 8:05

Quaternions, when converting to rotation matrices, can be treated as either left-handed or right handed. One rotates in one direction, and obviously the other in the opposite direction. If you mix formulas from different sources you will often find the results don't always line up -- though one would hope if using only equations from one source it'd be consistent.

So in short, this is a typical issue that arises. It is a matter of interpretation and neither result is more correct, just perhaps not consistent in your system. Either take the time to make all your formulas line up (which is often non-trivial), or simply negate the angle if you want something quick.

• Quaternions do not have handedness embedded in them, only matrices that are derived from one vector basis or another do. The op should convert a quat to a matrix then the matrix back to the quat. If the dot product of the initial quat and the resulting quat, in absolute value, is far from 1.0, then there's something wrong with the conversion functions: one might be using the LHS logic and the other RHS. – teodron Aug 18 '12 at 14:44
• To be pedantic: I believe you're talking about row-vectors vs. column-vectors, not right-handed vs. left-handed. – John Calsbeek Aug 18 '12 at 15:17
• @JohnCalsbeek, no, but I think my summary is perhaps not clear enough (I'm by no means an expert here, just hoping to provide direction). THe last time I worked with Quaternions I recall having LHS vs RHS issues when combining equations from multiple locations. – edA-qa mort-ora-y Aug 18 '12 at 16:03
• Multiplying on the left or multiplying on the right is not usually called "handedness." Left-handed vs. right-handed usually refer to a property of the coordinate system. When talking about quaternions, you have two potential sources of confusion: first, that quaternions are non-commutative (this shouldn't be a problem, though, because everyone multiplies on the same side), and second, that the matrix equivalent looks different depending on whether you're using the matrix to transform row vectors or column vectors. – John Calsbeek Aug 18 '12 at 16:46
• @everyone just to disambiguate my comment: LHS = left handed system and not left hand side as used in other sources (ibidem for RHS) – teodron Aug 18 '12 at 16:59