Little Trigonometry

Let's turn to trigonometry for a minute. There are two essential functions in trigonometry: cosine and sine. Each takes a single argument: an angle. We are used to specifying angles in degrees (e.g., 45° or 360°). In most math libraries, trigonometry functions expect the angle in radians, though. We can easily convert between degrees and radians with the following equations:

degreesToRadians(anglelnDegrees) = anglelnDegrees / 180 * pi radiansToDegrees(angle) = anglelnRadians / pi * 180

Here, pi is our beloved superconstant, with an approximate value of 3.14159265. pi radians equal 180 degrees, so that's how the preceding functions come to be.

So what do cosine and sine actually calculate given an angle? They calculate the x and y components of a unit-length vector relative to the origin. Figure 8-3 illustrates this.

Figure 8-3. Cosine and sine produce a unit vector with its endpoint lying on the unit circle

Given an angle, we can therefore easily create a unit-length direction vector like this: v = (cos(angle), sin(angle))

We can go the other way around as well, and calculate the angle of a vector with respect to the x-axis:

The atan2 function is actually an artificial construct. It uses the arcus tangent function (which is the inverse of the tangent function, which is another fundamental function in trigonometry) to construct an angle in the range of -180 degrees to 180 degrees (or -pi to pi, if the angle is returned in radians). The internals are a little involved and do not matter all that much for our discussion. The arguments are the y and x components of our vector. Note that the vector does not have to be a unit vector for the atan2 function to work. Also note that the y component is most often given first, and then the x component—but this depends on the math library we use. This is a common source for errors.

Let's try a few examples. Given a vector v = (cos(97°),sin(97°)), the result of atan2(sin(97°),cos(97°)) is 97°. Great, that was easy. Using a vector v = (1,-1), we get atan2(-1,1) = -45°. So if our vector's y component is negative, we'll get a negative angle in the range 0° to -180°. We can fix this by adding 360° (or 2pi) if the output of atan2 is negative. In the preceding example, we'd then get 315°.

The final operation we want to be able to apply to our vectors is rotating them by some angle. The derivation of the equations that follow are again a little involved. Luckily we can just use them as is without knowing about orthogonal base vectors (hint: that's the key phrase to search for on the Web if you want to know what's going on under the hood). Here's the magical pseudocode:

v.x' = cos(angle) * v.x - sin(angle) * v.y v.y' = sin(angle) * v.x + cos(angle) * v.y

Woah, that was less complicated then expected. This will rotate any vector counterclockwise around the origin, no matter what interpretation we have of the vector.

Together with vector addition, subtraction, and multiplication by a scalar, we can actually implement all the OpenGL matrix operations ourselves. This is one part of the solution to further increase the performance of our BobTest in the last chapter. We'll talk about this in one of the following sections. For now, let's concentrate on what we discussed and transfer it to code.

0 0