Higher-Order Fun

Game Design & Game Programming

Month: February, 2010

Math for Game Programmers 04 – Operations on vectors

Last time, we introduced vectors, and hopefully that introduction alone would be compelling reason to use vectors where it makes sense to. This time, we’ll discuss common operations associated with vectors, and their many uses. All of these operations are commonly found in vector operation libraries.

Length

Like we’ve discussed on the previous post, the length (or magnitude) of a vector is the square root of the sum of the squares of its components. So, if you have a 3D vector, its length is sqrt(x²+y²+z²). It is often represented by writing the vector inside ||s, that is, the length of vector v is said to be |v|.

For example, if we have the vector (4,2,4), we have:

length((4,2,4)) = |(4,2,4)| = sqrt(4²+2²+4²) = sqrt(36) = 6

Application example: If you have two points, you can find the vector between them and take its length to find the distance between the points.

Multiplication by scalar

You can multiply a vector by a scalar number (that is, a real number), which results in multiplying each component of the vector by that number. For example:

(0,-2,5) * 2 = (0,-4,10)

When you multiply a vector by a scalar, its direction is unchanged, but its length is multiplied by the scalar – for that reason, this operation is also called “scaling” the vector.

Application example: If you have an object moving with a vector representing its speed, you can adjust the speed without adjusting the direction by scaling the vector.

Normalization

By combining the two previous operations, we can “normalize” a vector. A vector is said to be normalized when its length is equal to 1. Since we can multiply any vector (except for (0,0,0)) by a scalar and therefore change its length to anything we want, we can normalize any vector by multiplying it by the inverse of its length.

In other words:

n = v * (1/|v|)

For convenience, many classes implementing vectors will define a “division by scalar” operator, so you could often just do this:

n = v/|v|

Application example: If you want a vector that represents a direction without a length, you usually want to use normalized vectors. It turns out, this is extremely common, and you will encounter normalized vectors very often.

Dot Product

Possibly the single most interesting operation on vectors, the dot product is very simple and versatile. It takes two vectors and returns a scalar number as the result, according to the following formula:

(a,b,c) . (d,e,f) = a*d + b*e + c*f

So, for example:

(2,-6,-10) . (1, 0, -1) = 2*1 + (-6)*0 + (-10)*(-1) = 2 + 10 = 12

It also has a different interpretation. Given two vectors v1 and v2, and let α be the angle between the two vectors, the dot product can be defined as:

v1 . v2 = |v1| * |v2| * cos(α)

This means that the angle between the two vectors can be determined like this:

α = arc cos( (v1 . v2) / (|v1| * |v2|) )

The formula above can easily be derived by isolating α on the previous equation. If the two vectors are normalized, then their lengths are one, and the dot product is simply the cosine of the angle between them.

One consequence of the cosine relationship is that the dot product can be used to determine the relative facing of two vectors. Let d be the dot product between two NORMALIZED vectors. Then:

v = 1: the two vectors face the exact same direction
0 < v < 1: the two vectors face roughly the same direction
v = 0: the two vectors are perpendicular
-1 < v < 0: the two vectors face roughly opposite directions
v = -1: the two vectors face exactly opposite directions

If you’re not interested in v=1 and v=-1 cases, then there is no need for the vectors to be normalized.

Applications: finding angles between vectors, projecting vectors into specific axes, determining whether a vector is facing the right direction, neutralizing a vector along a given axis, etc

Cross product

Similar to the dot product, but instead of taking two vectors and producing a scalar, the vector product takes two vectors and produces a third vector. It is defined as follows:

(a,b,c) x (d,e,f) = (b*f-c*e, c*d-a*f, a*e-b*d)

Similar to the dot product, the cross product also has an angular relationship,

|v1 x v2| = |v1| * |v2| * sin(α)

It’s important to note that while the dot product is also defined for 2D vectors, the cross product is only defined for 3D vectors. However, since it has useful properties even for 2D, a pseudo vector product can be defined for 2D vectors as follows:

(a,b) x’ (c,d) = a*d-b*c

This results in a scalar that is identical to what the “z” component of the result of extending the multiplication to 3D: (a,b,0) x (c,d,0) = (0,0,z)

A very important property of the cross product is that the cross between two vectors ALWAYS results in a vector that is perpendicular to the two original vectors (unless one of them was null). This makes the vector product extremely useful for calculating surface normal vectors – assuming that you can find three points on the surface, you can create the vectors v1 = (A-B) and v2 = (A-C), then n = v1 x v2, n’ = n/|n|.

An interesting use for the cross product (in particular, the 2D version) is that it indicates which direction a vector must rotate in order to face the same direction as the other vector, by taking the shortest path. Simply take the cross product between “current facing” and “desired facing” vectors, and the sign of the number (i.e. whether it’s negative or positive) will tell you which way to turn.

Applications: Finding normal vectors, finding turn directions, calculating torque, etc

These operations are some of the most basic things you can do with vectors. They will allow you to perform more complicated and interesting computations using vectors, so make sure that you understand them. We will use them very often in following lessons.

 

The fifth article in this series is now available here.