1
votes

I have been using the guide at www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/ for learning OpenGL. This guide says that...

glm::quat q;

...creates an identity quaternion (no rotation).

Experimentation shows that q = [0, 0, 0, 0]. Using this as the parent orientation of the root bone causes none of the bones to rotate at all. They lose all rotation.

The guide says that...

A quaternion is a set of 4 numbers, [x y z w], which represents rotations the following way:

// RotationAngle is in radians

x = RotationAxis.x * sin(RotationAngle / 2)

y = RotationAxis.y * sin(RotationAngle / 2)

z = RotationAxis.z * sin(RotationAngle / 2)

w = cos(RotationAngle / 2)

... and ...

[0 0 0 1] (w=1) means that angle = 2*acos(1) = 0, so this is a unit quaternion, which makes no rotation at all.

I have been experimenting with a skeleton system where each bone inherits its parents' orientation before applying its own rotations on top of that.

If I use an "identity" quaternion as the "parent" orientation for the root bone, then none of the bones are rotated at all. If I use the "unit" rotation all is well.

When I set a bone's initial orientation to either the "identity" or "unit" quaternion it displays as I want to. However when I convert user entered Euler angles to an orientation I get a 180 degree rotation. The conversion I did was:

        glm::vec3 eulers(glm::radians(pose.lng_rotate),
                         glm::radians(pose.lat_rotate),
                         glm::radians(pose.att_rotate));

        pose.orientation = glm::quat(eulers);

Note: I use "lng", "lat", and "att" rotate here because by the time a bone has inherited a parent rotation the "x" axis is probably no longer the "x" axis any more.

The last weird thing I noticed was that I used glm::mat4_cast on each type of quaternion and then multiplied by an identity glm::vec4. The "identity" quaternion left the vector unrotated, but the "unit" quaternion caused the vector to invert (multiply by -1) the x and y components of the vector.

I want to understand quaternions better, especially with respect to their use in code.

Conceptually, how is a "unit" quaternion different to an "identity" quaternion?

Where should I use a "unit" quaternion and where should I use an "identity" quaternion?

Am I just being confused by a badly written guide?

2
"Experimentation shows that q = [0, 0, 0, 0]." Prove it. A quaternion of all zeros is not "an identity quaternion". I don't think GLM is that badly coded to have such a mistake.Nicol Bolas
@Nicol I simply did glm::quat q; printf("%s, %s, %s, %s\n", std::to_string(q.x).c_str(), std::to_string(q.y).c_str(), std::to_string(q.z).c_str(), std::to_string(q.w).c_str()); The reason I use the string conversions is because there is something weird about the underlying type and using %f or %lf causes weird values to be displayed. I am lazy to figure out why.AlastairG
I did some more experimentation and found that glm::quat(1.0, 0.0, 0.0, 0.0) works perfectly. I failed to notice that although the guide expresses a quaternion as [x, y, z, w] it states that you initialise it explicitly as glm::quat(w,x,y,z).AlastairG
The title of this question is the ideal title. It requires no further reading to understand. It should be upvoted for that property alone.Matt Kleinsmith

2 Answers

7
votes

A unit quaternion is NOT the same as an identity quaternion. A quaternion is just any number in 'quaternion space', like 3 + 2i - 7j + 6k.

When we are using quaternions to calculate rotations we are always talking about unit quaternions and always have a length of 1, just like a unit vector. Multiplying unit quaternions is a very efficient way of calculating a rotation, but the length must stay the same, 1.

An identity quaternion is a quaternion that doesn't change any quaternion it is multiplied with, thus 1 + 0i + 0j + 0k or 1. An identity quaternion is thus a rotation of nothing.

2
votes

Unit and identity quaternions are the same thing. The guide is badly written and confusing.

glm::quat q; does NOT create an identity quaternion. It creates an invalid quaternion. The best way to create an identity quaternion is either by glm::quat q(glm::vec3(0.0, 0.0, 0.0)); or by glm::quat q(1.0, 0.0, 0.0, 0.0);. The first generates the quaternion based on a vector of all zero Euler rotations. The second explicitly initialises it to the identity quaternion.

Note that although quaternions are often described as [x y z w], they are stored and initialised as (w, x, y, z).