Part Three: 3D Rotation About an Arbitrary AxisThe previous method of doing the rotations is called using Euler angles. It's probably the simplest way of doing rotations, but it has some problems. The biggest problem is called gimbal lock. You may or may not have already encountered this if you wrote code according to the last tutorial. If you encountered it and noticed it, without knowing what it was, you may have spent hours trying to figure out where you went wrong in your code, carefully comparing every line of your code to the tutorial, trying to find the difference. If that happened, I'm sorry. There is nothing wrong with your code; there is something wrong with the math. If you'll recall, I told you two very important things, which you probably didn't connect in the last tutorial. 1) Matrix multiplication is not commutative. A*B != B*A. 2) We generated matRotationTotal by doing matRotationX * matRotationY * matRotationZ. If there was nothing wrong with the math, you should have been able to do matRotationY*matRotationZ*matRotationX, or any other order, and gotten exactly the same results. But you wouldn't. This problem is the root cause of gimbal lock. Trying to visualize this might blow your mind, so if you don't understand the next paragraph, don't worry too much. Just remember that Gimbal Lock happens when one axis gets rotated before another axis, and the axes are no longer mutually perpendicular. It can be a large problem, or it can go unnoticed, depending on the application.
We multiplied our matrices in the order matRotationX * matRotationY * matRotationZ. It seemed to work, and for the most part, it did. But if you think about it carefully, you'll realize that, as you move an object in 3d space, all three axes change at once. They remain mutually perpendicular to one another. In the program, however, we're rotating the object over the X-axis first. That rotates the Y and Z-axes. Then we rotate over the Y axis, but since we've already rotated over the X-axis, the rotation on the Y-axis only changes the location of the Z-axis. The rotation of the Z-axis does not change the location of either of the other two axes. Huge problem if you need to rotate on all three axes, because one axis can literally end up on top of another axis! (Just in the math. It can't do that in real life, meaning our representation is not accurate)
Luckily for you, many math geniuses have dealt with this problem. There was a famous man named Euler, whom you'll hear mentioned in Calculus. He determined that any series of rotations in three dimensional space can be represented as a single rotation over an arbitrary axis. For this representation, called angle/axis representation, you'll need to store the arbitrary axis about which you are rotating, and the amount by which you are rotating.
Now for the cameo by Charles, who was kind enough to write the following section for me: Arbitrary axis rotation by Charles Thibault
I am going to describe the calculations I perform in order to perform rotations about an arbitrary axis. These calculations are NOT the matrix form of the rotations. Up to this point you know you can combine matrices into a single transformation. The single transformation matrix involves about 29 multiplication operations and 9 addition operations, whereas completely rotating a vector using my transformations (meaning calling my RotateVector function TWICE, once over the Y axis then once over the Strafe vector) entails about ten percent more multiplications and about twice as many addition operations (32 multiplications for two RotateVector calls, and 18 addition operations for two RotateVector calls).
How do you actually perform a rotation about an arbitrary axis? Well firstly you must understand rotations in two dimensions, because the concept stays the same on an arbitrary plane. I'm going to make this as short and sweet as possible. Instead of rotating the X and Y components of a vector, the X is really the component of the vector you are trying to rotate Perpendicular to the vector that is the normal to the plane. Likewise the Y is really the cross product between the vector you are trying to rotate about and the actual vector being rotated.
Steps to rotate a vector:
-Calculate the Perpendicular component, multiply it by the cosine of the angle you are trying to rotate through
-Calculate the cross product between the vector you are trying to rotate about and the vector you are rotating, multiply it by the sine of the angle
-Add the results together
-Add the component of the vector you are trying to rotate that is parallel to the vector you are rotating about
Note it is not totally necessary to calculate the parallel component if the vector you are rotating and the vector you are rotating about are already orthogonal. I do it in all cases anyway to avoid any mishaps and make sure it is mathematically correct, but it seems to work both ways. Plus, by leaving it in the code you can rotate vector A about vector P even if A and P are not orthogonal. (orthogonal means mutually perpendicular to one another)
The rest of this will, once again, be written by me (Confuted).
There's still the problem of performing the actual rotation about your arbitrary axis. Luckily, this can also be done with a matrix. Again, I'm not going to derive it, I'm going to spoon feed it to you. You can thank me later.
Where c = cos (theta), s = sin (theta), t = 1-cos (theta), and <X,Y,Z> is the unit vector representing the arbitrary axisNow, you can replace matRotationTotal with this matrix, and completely eliminate matRotationX, matRotationY, and matRotationZ. Of course, there is extra math involved elsewhere. But by using the axis/angle representation for your rotations, it is possible to avoid gimbal lock. However, it's also possible to still suffer from it, if you do something incorrectly. In the next tutorial, I'll talk about some of the uses for the things I've been saying, and after that, brace yourself for the exciting and strange world of quaternions. If you don't have a headache from thinking too much yet, you probably will after the quaternions.
Previous: Rotation Matrices
Next: Uses for Rotations in 3 Dimensions
Back to Graphics tutorials index