user2763462
user2763462

Reputation: 51

Maintaining rotation during Quaternion normalization

I've been studying Quaternions for an upcoming project and have come across a conceptual problem that I can't wrap my head around.

The way to normalize a quaternion is as follows:

q_mag = sqrt(q0^2+q1^2+q2^2+q3^2)
q0 = q0/q_mag  
q1 = q1/q_mag   
q2 = q2/q_mag  
q3 = q3/q_mag

Straight forward and just like normalizing any other vector. But my question is how does this normalization method retain the same rotation information. Using the definition of a quaternion representing an axis-angle representation like below,

angle = 2 * acos(q0)
x = qx / sqrt(1-q0*q0)
y = qy / sqrt(1-q0*q0)
z = qz / sqrt(1-q0*q0)

Since the normalization operation scales the x,y,z values equally, the axis around which you are rotating never changes. But the value of the angle itself changes drasticly with a normalization operation.

So wouldn't it make more sense to use a method that preserves the value of q0 and only adjusts the other points to reach normalization?

Upvotes: 5

Views: 3174

Answers (2)

Treehee
Treehee

Reputation: 127

I know this is a bit of a necro, sorry, but i think this might be useful for future readers.

Unless I'm thoroughly mistaken, it's actually preferable not to preserve the angle when normalizing to account for rounding errors (in the context of using quaternions to represent rotations, especially in games). Let me explain why:

let's say you have two quaternions (I'll refer to them as Q1 and Q2 from here on out) that are supposed to represent rotations, but are not unit due to a rounding error, and you want to multiply them (I'll call the result Q3. We also want this to be a unit quaternion). Let's suppose t1 is a variable, that, when multiplied with every component of Q1, Q1 becomes a unit quaternion (that means t1 is one divided by the euclidean length of Q1, but that really is not relevant here. t2 does the same thing for Q2. If we now multiply the quaternions post-normalizing (ie Q3 = (t1*Q1)(t2*Q2))we get the following:

Q3.w = t1*Q1.w*t2*Q2.w - t1*Q1.x*t2*Q2.x - t1*Q1.y*t2*Q2.y - t1*Q1.z*t2*Q2.z
Q3.x = t1*Q1.w*t2*Q2.x + t1*Q1.x*t2*Q2.w + t1*Q1.y*t2*Q2.z - t1*Q1.z*t2*Q2.y
Q3.y = t1*Q1.w*t2*Q2.y - t1*Q1.x*t2*Q2.z + t1*Q1.y*t2*Q2.w + t1*Q1.z*t2*Q2.x
Q3.z = t1*Q1.w*t2*Q2.z + t1*Q1.x*t2*Q2.y - t1*Q1.y*t2*Q2.x + t1*Q1.z*t2*Q2.w

which can be rewritten as

Q3.w = (t1*t2)*(Q1.w*Q2.w - Q1.x*Q2.x - Q1.y*Q2.y - Q1.z*Q2.z)
Q3.x = (t1*t2)*(Q1.w*Q2.x + Q1.x*Q2.w + Q1.y*Q2.z - Q1.z*Q2.y)
Q3.y = (t1*t2)*(Q1.w*Q2.y - Q1.x*Q2.z + Q1.y*Q2.w + Q1.z*Q2.x)
Q3.z = (t1*t2)*(Q1.w*Q2.z + Q1.x*Q2.y - Q1.y*Q2.x + Q1.z*Q2.w)

in other words, Q3=(t1*Q1)(t2*Q2)=(t1*t2)(Q1*Q2). As you can see, normalizing in this way after the multiplication results in the same quaternion as normalizing both inputs pre-multiplication. This means we only have to normalize right before we apply the rotation to a vector/mesh/point, instead of after every calculation, since it produces the same result regardless of how far the quaternion drifts from being unit.

Now let's look at the same calculation, but with an angle-preserving way of making a quaternion unit (the t variables now make the quaternion unit when multiplied with only the non-real (aka xyz) parts):

Q3.w = Q1.w*Q2.w - t1*Q1.x*t2*Q2.x - t1*Q1.y*t2*Q2.y - t1*Q1.z*t2*Q2.z
Q3.x = Q1.w*Q2.x + t1*Q1.x*Q2.w + t1*Q1.y*t2*Q2.z - t1*Q1.z*t2*Q2.y
Q3.y = Q1.w*Q2.y - t1*Q1.x*t2*Q2.z + t1*Q1.y*Q2.w + t1*Q1.z*t2*Q2.x
Q3.z = Q1.w*Q2.z + t1*Q1.x*t2*Q2.y - t1*Q1.y*t2*Q2.x + t1*Q1.z*Q2.w

notice how the non-real components of Q3 no longer have a common factor This means that normalizing Q3post-operation in this way may result in a different quaternion than the one you'd get if you normalized Q2 and Q1 in this way pre-operation.

Normalizing a quaternion is not a cheap operation, so it is preferable to use the non-angle-preserving way for stuff like games, since you'd need to use it less often, especially when compositing a large number of rotations. I'm not sure if the same holds up for other quaternion operations, but considering you'll probably be multiplying quaternions alot it is, at least in my opinion, preferable to use the non-angle-preserving way.

Upvotes: 1

marcv81
marcv81

Reputation: 876

Math answer: A unit quaternion represents a rotation in 3D space. Any other (i.e.: non-unit) quaternion does not represent a rotation, so the formula angle = 2 * acos(q0) does not apply to these quaternions. So there is no change of angle when normalising, because the quaternions that you would normalise do not represent rotations in the first place.

Programming answer: Floating point operations have accuracy issues. These issues result in small errors, which if accumulated may become large errors. When multiplying two unit quaternions, the mathematical result is another unit quaternion. However the floating point implementation of unit quaternions multiplication may result in a quaternion with a norm close to 1 but not equal 1. In this case we shall normalise the quaternion to correct the error. When we normalise we divide q0 by the norm which is very close to 1, so there is no major change in the value of q0. Because we normalise early the norm is always very close to 1 and we don't need to worry about the precision.

Late answer, but I hope it help.

Upvotes: 5

Related Questions