# Vector Tutorial

Mar 28, 2010

—## What's a vector?

A vector is a set of two or more numbers, often used to indicate a spatial position or a direction. A two-component vector can be used to for two-dimensional space, a three-component vector can be used for three-dimensional space, and so on. Some parts of this tutorial only apply to two-dimensional vectors, while some parts only apply to three-dimensional vectors, as specified in each section. The following struct will be used throughout this tutorial to represent a vector. In the sections that focus on two-dimensional space, the z component will be assumed to be zero.
1 2 3 4 5 6 |
struct Vector { float x; float y; float z; }; typedef struct Vector Vector; |

## Expressing positions with vectors

When a vector is used to represent a spatial position, each component stores an offset in homogenous units, one for each axis. The units stored could be pixels, inches, miles, or anything else; it depends on the coordinate system you use in your game. The origin in a coordinate system is the position represented by the vector {0, 0, 0}; world coordinates are measured relative to the origin. You will sometimes also work in local coordinates, which are measured relative to a position that could be different from the origin.In the coordinate system used throughout this tutorial, the X axis goes from left to right, the Y axis goes from bottom to top, and the Z axis goes from far to near. This corresponds to the coordinate system most commonly used for three-dimensional OpenGL projections.

## Expressing directions with vectors

A vector can also be used to represent a direction. A direction vector is no different from a vector used to represent a position - the only difference is in how you use it. If you draw a line between the origin and the position represented by a vector, that's the direction the vector represents. The magnitude of a vector, also known as its length, is its distance from the origin. Vectors of equal magnitude can be visualized as points on the outside of a sphere (3D) or a circle (2D) with a radius equal to the vector's magnitude. You can normalize a vector, making its magnitude equal to 1. This is useful for a number of things. Example: Let's say you're writing a game in which the player flies a spaceship. You want to be able to move the spaceship not only left, right, up, and down, but also diagonally. When you're moving right, the spaceship goes one unit along the X axis; when moving up, it goes one unit along the Y axis. But what if you're moving both right and up at the same time? To move diagonally, you can't simply move one unit to the right and one unit up, since that's a further distance (approximately 1.4 times as far) than moving one unit on only one axis. And what if you want to move the spaceship at a steeper or shallower angle than 45 degrees?This problem can be easily solved by using a normalized direction vector. The vector points in the direction the spaceship is facing; when you move the spaceship, you use the vector to calculate the change in position. For example:

1 2 3 4 5 |
#define SPACESHIP_MOVE_SPEED 0.2f /* Arbitrary value; distance the spaceship moves per frame */ spaceship.position.x += (SPACESHIP_MOVE_SPEED * spaceship.direction.x); spaceship.position.y += (SPACESHIP_MOVE_SPEED * spaceship.direction.y); spaceship.position.z += (SPACESHIP_MOVE_SPEED * spaceship.direction.z); |

Using a normalized vector, the spaceship moves the same distance regardless of which way it's facing. This certainly isn't the only way; you could accomplish the same thing by storing the ship's direction as an angle, and using the trigonometric functions sin() and cos(). Vectors are just a convenience in this case. More on this later.

## Constructing a vector

There are many different ways to construct a vector. The simplest way is to assign each component directly. The vector {1, 0, 0} points straight to the right; {-1, 0, 0} points straight to the left; {0, 1, 0} points straight up, etc. For values that don't point directly up or down one axis, you may want to compute them using the cos() and sin() functions. These functions, given an angle in radians, will return numbers you can use to construct a normalized direction vector. This only works for two out of three axes, though; the third must be set to zero.
1 2 3 4 5 |
float angle = (M_PI / 4.0); /* 45 degrees */ vector.x = cos(angle); vector.y = sin(angle); vector.z = 0.0; |

If you want to construct a vector in local coordinates (from point A, how far and in what direction is point B?), you can do it by subtracting each component in point B from the corresponding component in point A. (If you only want the direction, and not the distance, you'll need to normalize the vector afterward):

1 2 3 |
vector.x = (pointB.x - pointA.x); vector.y = (pointB.y - pointA.y); vector.z = (pointB.z - pointA.z); |

## Normalizing a vector

A normalized vector has a magnitude of 1. Normalized vectors pointing in any direction are of equal distance from the origin, as though constrained to an imaginary sphere or circle. Vector normalization is done like this:
1 2 3 4 5 6 7 8 9 10 |
void Vector_normalize(Vector * vector) { float magnitude; magnitude = sqrt((vector->x * vector->x) + (vector->y * vector->y) + (vector->z * vector->z)); vector->x /= magnitude; vector->y /= magnitude; vector->z /= magnitude; } |

What are we doing here? First, we use the distance formula to calculate the length, or magnitude, of the vector. For a vector that's already normalized, this will be approximately equal to 1. (I say "approximately" because floating point numbers have limited precision, and rounding errors can cause things not to add up exactly to the number you would expect.) Once we have the magnitude, we divide each component of the vector by it.

Note that if you attempt to normalize a vector with a magnitude of zero, you'll end up with a vector full of NaNs. (NaN stands for "Not a Number"; it's a special value returned from illegal operations such as a divide by zero. Languages other than C may behave differently.)## Rotating a vector

Rotating a vector can be accomplished a few different ways. For two-dimensional rotation, one way to do it is by using atan2() to compute the angle of the vector, and using sin() and cos() to compute a new angle. For three-dimensional rotation, you'll need to multiply the vector by a quaternion or a rotation matrix; see the Quaternion tutorial and the Matrix tutorial for more details. For two-dimensional rotation, you might do something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#define SHIP_ROTATION_SPEED (M_PI / 100.0) void rotateShip(Spaceship * ship, float rotationAngle) { float angle; angle = atan2(ship->direction.y, ship->direction.x); angle += rotationAngle; ship->direction.x = cos(angle); ship->direction.y = sin(angle); } void leftArrowKey(Spaceship * ship) { rotateShip(ship, -SHIP_ROTATION_SPEED); } void rightArrowKey(Spaceship * ship) { rotateShip(ship, SHIP_ROTATION_SPEED); } |

Next, we add in the rotationAngle that was passed to the function. A new direction vector is then computed from the angle using sin() and cos(). The ship is now facing a new direction.

## Dot product

Dot product is a vector operation that can be used to compute the angle between two vectors:

1 2 3 4 5 |
float Vector_dot(Vector vector1, Vector vector2) { return ((vector1.x * vector2.x) + (vector1.y * vector2.y) + (vector1.z * vector2.z)); } |

## Cross product

Cross product is a vector operation that can be used to compute a vector perpendicular to the plane on which two vectors lie:
1 2 3 4 5 6 7 8 9 |
Vector Vector_cross(Vector vector1, Vector vector2) { Vector result; result.x = ((vector1.y * vector2.z) - (vector1.z * vector2.y)); result.y = ((vector1.z * vector2.x) - (vector1.x * vector2.z)); result.z = ((vector1.x * vector2.y) - (vector1.y * vector2.x)); return result; } |

- Vector_cross(right, up) = front
- Vector_cross(front, right) = up
- Vector_cross(up, front) = right
- Vector_cross(up, right) = back
- Vector_cross(right, front) = down
- Vector_cross(front, up) = left

That's it! You should now be well on your way to using vectors effectively. If you have any questions, feel free to contact me directly, or ask on the message board. Happy coding!

## Code Implemenation

Vector.h : Download (1.5 KB)

Vector.c : Download (2.4 KB)