View Matrix from Quaternion
Asked Answered
T

4

9

I'm currently building my own quaternion camera. As far as I know, you only need one quaternion to fully specify the camera's orientation (correct me if I'm wrong). So, how would I go about creating the view matrix? I'm using C++ as a programming language by the way.

Any help would be appreciated.

Tb answered 8/10, 2012 at 8:12 Comment(0)
I
15

First some caveats. You'll see lots of apparently conflicting formulae on the 'net and in literature on this subject. Most of the conflicts are apparent only. A few are real conflicts, but that's because somebody got the math wrong. The problem is that there is no single right way to do it. You need to know how you are using quaternions and matrices, how the source is using them, and how to rectify those apparent discrepancies.

Rotation versus transformation
Your camera has a reference frame associated with it, as does the underlying space. Does your matrix represent the physical rotation of the camera from the underlying space to the camera's orientation or the matrix that transforms vectors as represented in the underlying space to the frame of the camera? (Or something else; there are four choices here.) These choices are related; the transformation matrix is the transpose of the rotation matrix. Transformation and rotation are conjugate operations. The same concept applies to quaternions. Are you using transformation quaternions or rotation quaternions? These are once again related concepts; one is the conjugate of the other.

Left versus right quaternions
Given a unit quaternion q to transform or rotate a vector v, some use qvq* to transform/rotate the vector, others use q*vq. Which form is correct? Both are. The two forms differ only in whether the unconjugated quaternion is to the left (qvq*) or to the right (q*vq) of the vector to be transformed/rotated.

Column versus row vectors
Most people use column vectors, but some do use row vectors. Here you run into a left versus right issue with matrices. Column vectors transform/rotate via Mv, with the matrix to the left of the vectors; row vectors via vM, with the matrix on the right.

Impact
You have to be careful in reading the literature. With regard to forming a matrix from a quaternion you need to watch out for sign changes in constructing the off-diagonal elements of the matrix. One formulation's addition/subtraction may change to subtraction/addition in another formulation.

Left transformation quaternions to row vector transformation matrices
I use left transformation quaternions and transformation matrices, and I represent vectors as row vectors. I also represent a quaternion q as comprising a real scalar part qs and a vectorial imaginary part qv. Given these representations, the computations to generate a matrix from a quaternion are (pseudocode):

// Compute the cosine of the rotation angle.
cost = 2.0*qs*qs - 1.0;

// Construct the diagonal of the matrix:
// T_ii = cost + 2qv_i^2
for (i = 0; i < 3; ++i) {
   T[i][i] = cost + 2.0*qv[i]*qv[i];
}

// Construct off-diagonal transformation matrix elements:
//   T_ij = 2 (qv_i qv_j - eps_ijk qs qv_k), where eps is the Levi-Civita symbol
for (k = 0; k < 3; ++k) {
   i = (k+1)%3;
   j = (i+1)%3;
   T[i][j] = 2.0*(qv[i]*qv[j] - qs*qv[k]);
   T[j][i] = 2.0*(qv[i]*qv[j] + qs*qv[k]);
}

You might want to expand those loops out. The first loop expands into three statements, the latter, six. You don't need to compute i and j in the expansion of the latter loop; the expansion of the loop makes them fixed quantities.

Alternate representations
Those caveats above aren't as bad as they seem. You need to make sure my representation is consistent with yours. Odds are 50-50 that it isn't. If it isn't, simply swap the assignments to the off-diagonal elements. Use the computation of T[i][j] for T[j][i], and vice versa. How to tell:

  • Start with s=1.
  • Multiply s by -1 if you use rotation quaternions instead of transformation quaternions.
  • Multiply s by -1 if you use right quaternions instead of left quaternions.
  • Multiply s by -1 if you use rotation matrices instead of transformation matrices.
  • Multiply s by -1 if you use row vectors instead of column vectors.

Use my formulation if the final value of s is 1. If it's -1, simply swap the assignments to T[i][j] and T[j][i]. Or you could change the addition to subtraction, the subtraction to addition.

One last gotcha
The above calculation applies when the scalar part is not close to zero. It would be valid everywhere if we had infinite precision arithmetic. You might want to use a separate calculation for rotations that are very close to zero or 180 degrees.

Ibis answered 8/10, 2012 at 13:19 Comment(7)
The common theme for most of the above points is: you need to know what conventions your system follows. It sounds like you're building your own math library, so some conventions (like left vs. right quaternions) are your own choice -- but I'd guess others (like exactly how the resulting view matrix is used) will be determined by whatever graphics library you use. So, your first task is to look up and understand the latter...Solvable
@Solvable - Yep. Knowing conventions is important, particularly when you need to exchange quaternions with someone else, or when you read some journal article that uses quaternions in some inventive way and try to incorporate their math into your package. I've have had to mediate far too many "you're doing it wrong!" arguments when both are doing it "right", but neither side knows that there's more than one way to do it right.Ibis
Hmm... let's see... I'll go through your points one by one. I'm using DirectX so I think the underlying frame would be left-handed. Also, I tend to translate everything in my world to fit my camera so it's going to be a transformation quaternion. Lastly, I use a column major matrix layout. So that means I only need to switch the matrix indices! Thanks a lot for the answer, David, I really appreciate all the time you took to write it. It cleared up all of my questions, plus some more that I was going to ask! Thanks again, I really appreciate it. +1 and accepted as answer!Tb
By the way, I'm just interested. Where did all of you learn quaternion calculus? Did I miss too many high school math classes?Tb
Left handed coordinate system? You might want to rethink that. It will get you in trouble. Quaternions are explicitly based on a right-handed system. Our cross product is equivalent to the quaternion product of two pure imaginary quaternions -- but only if you're working with right handed coordinates. Note that I left "handed" out when I said left quaternions and right quaternions. They're not left-handed / right-handed. They're left and right operators.Ibis
Well... I have a positive x that goes right, positive y that goes up, and a positive z that goes into the screen. I looked up right/left handedness of a coordinates system and it doesn't seem to fit into either. I don't really understand all these handedness though. If the result comes out flipped, I simply reverse the sign of the wrong axis. However, after implementing your code, though, everything is working fine... even though quaternions are supposedly working only for right-handed coordinate systems.Tb
That's a left-handed system. Right hand rule: Curl the last two fingers of your right hand into your fist, and spread the thumb, index finger, and middle finger wide. Orient your hand so the thumb points along the screen to the right, your index finger points up. Your middle finger is pointing out of the screen, not into the screen. That quaternions work with a left handed coordinate system is undefined behavior. Look at it this way: This code "works": char* str = new char[6]; strcpy (str, "Hello"); delete[] str; std::cout << str; It works until it blows up, that is. It's undefined behavior.Ibis
S
3

Wikipedia knows it: Quaternions and spatial rotation

Storytelling answered 8/10, 2012 at 8:47 Comment(4)
Erm... but this doesn't help me get the view matrix. I need the facing vector, up vector, etc.Tb
Wikipedia knows it, but not there. The linked article is about matrix representations of a quaternion. It has nothing to do with the question at hand.Ibis
Actually I'm really sorry for posting the wrong link, corrected now.Storytelling
Much better. Note that that link uses left quaternions (qvq*).Ibis
D
2

I would recommend using the Eigen C++ library to represent your quaternions and matrices. When you have a quaternion object, you can simply call .toRotationMatrix() on it to get a 3x3 matrix.

Another library that would probably work is glm.

Danita answered 8/10, 2012 at 16:13 Comment(1)
Thank you all for the math library recommendations. I will certainly look into how they implement the operations. However, I'm trying to write my own math library because I believe it will help me understand what's really going on behind the scenes. And, I think writing my own math library for my own game is much more exciting than sitting in a classroom hearing a lecture about matrices and quaternions! :)Tb
A
1

The Configurable Math Library ( http://cmldev.net/ ) is a very lightweight lib that could do the computation for you. It is a header library, so integration into your code shouldn't be a problem. This function ( http://cmldev.net/?p=196 ) might help you as well.

Alula answered 8/10, 2012 at 16:2 Comment(4)
This package and the Eigen package referenced by David Grayson nicely illustrate my point. CML apparently uses right quaternions while eigen uses left quaternions; they have the additions and subtractions on the off-diagonal elements reversed. Neither package says what they mean by "quaternion". Stay completely within one package and you're probably fine (assuming they have the math right). But exchange data with someone else (who inevitable uses a different convention; the odds highly favor Murphy's law here), or try to mix and match packages and you're in trouble.Ibis
Thank you all for the math library recommendations. I will certainly look into how they implement the operations. However, I'm trying to write my own math library because I believe it will help me understand what's really going on behind the scenes. And, I think writing my own math library for my own game is much more exciting than sitting in a classroom hearing a lecture about matrices and quaternions! :)Tb
@DavidHammen AFAIK the CML is configurable, meaning you can choose the kind of quaternion you want to haveAlula
There's only one matrix_rotation_quaternion; here it is: cmldev.sourceforge.net/cml1-doc/dd/d60/… . The algorithm is fixed. There is no configuration.Ibis

© 2022 - 2024 — McMap. All rights reserved.