3. How to rotate a orientation with a quaternion ( = the hard to understand quaternion multiplication)
- quatmult.png (19.1 KiB) Viewed 9846 times
We do some mappings to access vector and scalar parts from our quats individually:
- Code: Select all
sQuat q, r, qr; // we want qr = q * r
vec &qrV = (sVec3&)qr;
float &qrS = qr[3];
vec &qV = (sVec3&)q;
float &qS = q[3];
vec &rV = (sVec3&)r;
float &rS = r[3];
First (ignoring the image) we'll look at an easy special case: Both rotations have their axis at the same line, so we can treat this as an 2D-problem.
We detect that easy case by taking axis cross product and check it's length:
- Code: Select all
sVec3 qcv = qV.Cross(rV);
if (qcv.Length()<0.001)
{
It's clear that we just need to sum (or subtract) both angles,
because rotating first 20, then 5 degrees over the same axis is the same as rotating degrees 25 at once.
(If the second axis points in the opposite direction, we should end with 15 degrees.)
If we want to sum two angles, where sines and cosines are known,
we can calculate the cosine of the summed angle by:
cosSummedAngle = (cos1 * cos2) - (sin1 * sin2)
Thus the scalar part (cosine of final halfangle) is:
- Code: Select all
qrS = qS*rS - qV.Dot(rV);
Note: The dot product also includes the factor cos(angle(q.axis, r.axis)),
which in this case is either 1 or -1 and handles axis pointing in opposite directions nicely.
Further, we can calculate the sine of the summed angle by:
sinSummedAngle = (sin1 * cos2) + (cos1 * sin2)
We build the vector part (sine times axis) accordingly:
- Code: Select all
qrV = sVec3(qV*rS + rV*qS);
}
else
{
Now the general case, which we treat as a 3D Problem (now look at the image).
One dimension more means one more angle to look at:
The angle between the two rotations axis that we wanna combine.
We already have their sine and cosine in our dot and cross products,
So we'll see how to use them...
We'll use following example:
Put a cube in your hand and remember it's initial orientation.
Rotate it 90 degrees over one of its local axis, followed by another 90 degree rotation around another local axis.
To rotate it back to the initial state in one go, you need pick it at two opposite corner points and rotate 120 degrees.
How can we calculate this angle?
It turns out, the cosine factor from the dot product has another nice property:
In the example situation it zeroes the sine term,
which gives us exactly the angle we want (cos = 0,5 -> 60 degrees halfangle).
Thus the 3D case of our scalar part becomes:
cosSummedAngle = (cos1 * cos2) - (sin1 * sin2) * cos(angle(axis1, axis))
So no need to change anything about the scalar part.
- Code: Select all
qrS = qS*rS - qV.Dot(rV);
In the image you see three quaternions (red * green = blue).
I added a cube so you can see the blue axis goes through opponent cube corners to verify the example.
The orange line shows the axis result from our formula we already have.
- Code: Select all
qrV = sVec3(qV*rS + rV*qS);
We see it is at the right place on the plane formed by red and green axis,
and this is how we get the missing distance - we just add the cross produkt (yellow line):
- Code: Select all
qrV += qcv;
}
This time the sine factor in the cross product comes to our advance,
because it gives the cross product the right length and we are done.
At this point, it may seem still a bit magical,
but it is not more magical than saying: "cos(a) + sin(s) = 1"
To be true, the above code has some instructions more than the standart quaternion multiplication,
Maybe i'm in the mood to figure out what terms cancel each other out, but i reached my goal:
Understand, how quaternions work.
So please let me know what you think guys, but please don't say 'What ???'