You are on page 1of 4

The way presented for doing rotations in the last tutorial wasn't really a good one.

It works just fine in two dimensions, but as soon as you want to rotate around the X or Y-axes, it becomes more difficult. Sure, it's easy to make equations that will represent a rotation on any one of those axes, but just go ahead and try to make equations that will represent changes on three axes at once. If you manage to pull that off, make sure to let us know. Meanwhile, I'll present a way to do the rotations with matrices. Matrices might seem scary, especially to someone who has never used them before. However, they really aren't too difficult to use. They're also very powerful. The first thing to note is that it is possible to use a vector to specify a point in 3d space. Basically, every point is a displacement from the origin by a certain amount, which is described by the vector. Vectors are useful for lots of other things as well, and perhaps someday I'll write about some of those. Meanwhile, we'll just use them for storing points. A vector can be multiplied by a matrix, and after the multiplication, you'll get a new vector. This may seem useless, but when you multiply the vector by the right matrix, you'll get a point that has been transformed by the matrix. This can mean rotated on any axis (including arbitrary ones! that will come later), translated, or both. You see, the thing with matrices is this: If you have one matrix representing rotation on the X axis, and another matrix representing rotation on the Y axis, you can multiply them together to get a new matrix which represents the rotation on both axes. However, in case you didn't catch this in any tutorials you read about matrices, please note that if A and B are matrices, A*B != B*A. This will cause us some problems later, but for now, just keep it in the back of your mind. I'm not going to derive these matrices that I'm about to give you here. One reason is that it's been done other places. Another reason is that it would involve me explaining a lot of things that have also been explained better elsewhere. The most important reason is because I can't. However, that doesn't matter. You don't need to be able to derive these matrices; you just need to know how to use them. You'll also need to know which coordinate system you're using: left-handed or right-handed. OpenGL uses right-handed coordinates; DirectX uses left-handed coordinates. This is also explained in detail elsewhere, so I won't go into it. If you're not using OpenGL or DirectX, either figure out what your API uses, or if you're writing your own or something, pick one and stick with it. There will be no turning back. Where (phi) represents the rotation about the X axis, (theta) represents the rotation about the Y axis, and (psi) represents the rotation about the Z axis Those really aren't as complicated as they look. And for those of you wondering why I didn't store all of those in 3*3 matrices, just hold on ;) That's coming later. For the purposes of this tutorial, I'm going to try to avoid picking a coordinate system, so that it will be equally useful for both OpenGL and DirectX programmers. We'll call the rotation matrix for the X axis matRotationX, the rotation matrix for the Y axis matRotationY, and the rotation matrix for the Z axis matRotationZ.

By multiplying the vector representing a point by one of these matrices (with the values properly filled in), you can rotate the point around any axis. However, you'll probably want to allow rotation about all

three axes. You could multiply the vector by one matrix, then multiply it by the next matrix, then multiply it by the next matrix... but that would produce some very slow code, because you would be performing far too many operations for each point. Matrices can be combined, which will save you some very valuable time in your code. We'll call the matrix which represents all your rotations matRotationTotal, and here's the way to generate it:

matRotationTotal = matRotationX * matRotationY * matRotationZ After that, you can simply transform each point with matRotationTotal, and the point will be rotated about all three axes. When you need to change the amount of rotation, rebuild matRotationX, matRotationY, and matRotationZ, and then multiply them together to get the new matRotationTotal. Pretty easy, and it gets points rotating around in three dimensions. (Note: If you don't know how to multiply matrices, or if you don't know how to multiply a vector by a matrix, consult a basic tutorial and matrix math. To give you a hint, a vector can be represented by a 1*4 matrix...).

ROTATION ABOUT ANY AXIS The 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 Yaxis

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 axis Now, 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.

You might also like