Vector Math

Vector Math is easily one of the most used forms of math in 3D game programming. Here are some examples of the basics of vector math, and some of its uses in games. In the following examples we'll be referring to three dimensional vectors. They're represented by three numbers, each one corresponding to a dimension. E.g. (-2, -3, 16) can represent a point that lies at -2 in the x coordinate, -3 in the y coordinate, and 16 in the z coordinate. Vectors can also represent distances, force, velocity, and other fun stuff.

Vector subtraction

Vector subtraction is as easy as simple arithmatic. You simply subtract each component of one vector from the other.

c = a - b

Example:
Vector a = (3, -5, 7)
Vector b = (5, -2, -9)

Vector c = (3 - 5, -5 - -2, 7 - -9) = ( -2, -3, 16)

So, what does vector subtraction get us? A couple of useful things. It gives us the direction from one vector to another. In this example, 'c' is a vector that points from the point represented by vector 'b' to vector 'a'. Using vector 'c' we can determine a direction and distance from b to a, which we shall show in the next two examples.

XNA Code:

Vector3 a = new Vector3(3, -5, 7);
Vector3 b = new Vector3(5, -2, -9);

// There are a few ways we can do this, XNA has many Vector math functions built in
Vector3 c = a - b;

// Or
Vector3 c = new Vector3();
Vector3.Subtract(a, b, c); // This places the result of a - b into c.

// Or
Vector3
c = new Vector3(a.x - b.x, a.y - b.y, a.z - b.z);

If you were to draw vectors 'a' and 'b' from (0, 0, 0) to their respective points, then vector 'c', would connect the end points of each of those vectors.

Distance between two points

Given two points, we can easily determine a distance between them. Subtracting Vectors 'a' and 'b' in the previous example we were able to determine that Vector 'c' = (-2, -3, 16). Vector 'c' represents a line between points 'a' and 'b', so if we can determine the distance of the line, then we're done. The formula for this is:

d = √(x^2 + y^2 + z^2)
given our example we have:
d = √(4 + 9 + 256) = √269 = 16.4012

So the length of vector c, and the distance from 'a' to 'b' is 16.4012 units. You'll notice that we have 269 before we do the square root operation. This number is referred to as the 'squared length' or 'length squared'. As we'll see later, this number can be useful as well.

Vector3 a = new Vector3(3, -5, 7);
Vector3 b = new Vector3(5, -2, -9);

Vector3 c = a - b;

// XNA has a distance/length function
float distance = c.Length();

// Or we can do it ourself, by taking the square root of the squared length
float distance = Math.Sqrt( c.x * c.x + c.y * c.y + c.z * c.z );


Unit length direction from one point to another

Given two points, we can easily determine direction from one to the other. Continue with our original example, we subtracted vector 'b' from vector 'a', which gives us the direction and length together. In vector math it is often useful to have a unit-length vector (a vector with a length of 1), so we'll take Vector 'c' and make it unit-length, which will leave us with a vector that represents direction.

Once you've determined the length of the vector, you simply divide the original vector by it's length. In the previous example 'Distance between two vectors' we determined the length, which was ~16.4012. So we'll just divide vector 'c' by that amount.

-2 / 16.4012, -3 / 16.4012, 16 / 16.4012 = ( -0.1219, -0.1829, 0.9755 ).

This gives us the direction from point 'b' to point 'a'. Unit length vectors are useful for many purposes, such as being used to find the angle between two unit-length vectors, or if you wanted to move an AI unit in a specific direction and speed, you could use a unit-vector and then scale it by the desired speed.

Vector3 a = new Vector3(3, -5, 7);
Vector3 b = new Vector3(5, -2, -9);

Vector3 c = a - b;

// XNA has a function to create a unit-length vector for us.
c = c.Normalize();   // After this line executes, 'c' will be unit-length

// Or we can do this ourself. If we've already calculated length, this is even more efficient
// if you've already calculated distance for something else.

float distance = Math.Sqrt( c.x * c.x + c.y * c.y + c.z * c.z );
c = c / distance;

You'll notice above that we calculate distance so that we can normalize/unitize our vector. If you call the Normalize() function that comes with XNA it does this all for you. That is convienent, but if you've already calculated length for another use, and then need to normalize a vector, then it is more efficient to simply normalize it on your own. In fact, in my own programming I've come along the cases like this, or cases where I would need the length of a vector right before I normalized it, so I created a function that normalizes a vector, and returns the length before normalization.

public float Normalize(Vector3 vector)
{
    float lengthSqr = ((vector.X * vector.X) + (vector.Y * vector.Y)) + (vector.Z * vector.Z);
    float length = (float)Math.Sqrt((float)lengthSqr);
    float num = 1f / length;
    vector.X *= num;
    vector.Y *= num;
    vector.Z *= num;

    return length;
}

You may notice that all multiplication is done on each component individually. For example, instead of vector *= num, I did each component individually. This is because the overloaded operator for multiplying vectors by a scalar value is slower than multiplying each float value of a vector3 by another float. Also, by calculating 'num' we can multiply by that three times rather than doing the division by length three times. This part isn't so much a lesson in vector math, more a lesson in efficiency with XNA, and an explanation why this function has slightly more code than you might expect.

Using squared lengths

As we mentioned in one of the previous examples: 'Distance Between Two Points', squared lengths can be useful. Most of the time when you're calculating a squared length it is almost immediately square rooted to give length, but occasionally this isn't needed. For example, when you want to compare two lengths to see which is greater.

If you want to compare two lengths to see which is greater, you could find the exact length of each, and compare them, but the fact is that you really may not care what the exact lengths of each vector is, you just want to know which vector has the greatest length. In this case, you can just use a squared length.

This is same method as we described earlier, but without the square root.
d^2 = (x^2 + y^2 + z^2)

So lets see how we could put a length comparison of two vectors into a simple function.

public bool FirstVectorLongest(Vector3 vectorA, Vector3 vectorB)
{
    float lengthSqrA = ((vectorA.X * vectorA.X) + (vectorA.Y * vectorA.Y)) + (vectorA.Z * vectorA.Z);
    float lengthSqrB = ((vectorB.X * vectorB.X) + (vectorB.Y * vectorB.Y)) + (vectorB.Z * vectorB.Z);

    return lengthSqrA > lengthSqrB;
}

Comparing the length of two vectors can represent more than just distance between two points. Because vectors can also represent velocities, this function is also useful for determining which vector represents a higher velocity.

Dot Product

Dot product is one of the properties of vectors that you can get when multiplying them. The dot product has many useful properties with vectors, in fact, the Dot Product and Cross Product are probably the two most important properties of vectors in 3D math used in video games. A dot product requires multiplying each component of two vectors and adding them together, as such:

Vector a = (3, -5, 7)
Vector b = (5, -2, -9)

a (dot) b = (3 * 5 + -5 * -2 + 7 * -9) = 15 + 10 - 63 = -38

You'll notice that we end up with a real number value when using the dot product. This number can be more useful when used with two vectors of unit-length, as we'll see in an upcoming example. The dot product is also useful in vector projection, vector<->plane math, and more.

Angle between two vectors/lines

In 3D games you'll often find cases where you may want to know the angle between two vectors. For example, you may want to know how many degrees an AI unit will need to turn to face its target. You may want to know how far a camera needs to rotate to face the same direction as the player it is attached to. So how do we determine the angle between two lines? Using the Dot Product and a little bit of triginometry.

Vector a = (1, 0, 0)
Vector b = (0, 1, 0)

a (dot) b = (1 * 0 + 0 * 1 + 0 * 0) = 0
arccos(0) = 1.5708

So what we did was find the dot product between two vectors, a and b, which resulted in zero. We then find the arc cosine of zero, which is 1.5708, or half of Pi, which is 90 degrees.

public bool AngleBetweenTwoVectors(Vector3 vectorA, Vector3 vectorB)
{
    float dotProduct = 0.0f;
    Vector3.Dot(vectorA, vectorB, dotProduct);

    return dotProduct;
}


It can also be useful to not only know the angle between two vectors, but also if the signed angle should be negative or positive. This can tell us things like which direction to turn, not just how far. Here is a function to do just that for us.

public double GetSignedAngleBetweenTwoVectors ( Vector3 Source, Vector3 Dest, Vector3 DestsRight )
{
    // We make sure all of our vectors are unit length
    Source.Normalize();
    Dest.Normalize();
    DestsRight.Normalize();

    float forwardDot = Vector3.Dot( Source, Dest );
    float rightDot = Vector3.Dot( Source, DestsRight );

    // Make sure we stay in range no matter what, so Acos doesn't fail later
    forwardDot = MathHelper.Clamp( forwardDot, - 1.0f, 1.0f );

    double angleBetween = Math.Acos( (float) forwardDot );

    if ( rightDot < 0.0f )
        angleBetween *= - 1.0f;
    
    return angleBetween;
}

We do our initial dot product to find the angle between the two vectors, this is what we store in 'forwardDot'. We then do another dot product, between the source vector and a vector that is perpedicular to the dest vector and also on the same plane to the dest vector. (We'll learn how to do this soon when we learn about Cross Products). The dot product we get from this is 'rightDot'. If rightDot is less than zero then we know that the dest vector is to the right (or clockwise) from the source vector (on a unit circle), otherwise, dest vector is to the left. This is why we can multiply the angle by negative one if it is to the right, this lets us determine which direction the angle is in.

In this first example, we can see that the 'dest' vector is to the right (counterclockwise) of the source vector:


Because the angle between S and R (dest's right vector) is greater than 90 degrees, the dot product will be negative. The negative dot product is our indication that the 'dest' vector is in fact to the relative right (clockwise) to the source vector. In the next example we can see that 'dest' is to the relative left (counterclockwise) or the source vector:


In this example the dot product between S and R will give us a positive number because it the angle between them is less than 90 degrees. This proves that D (dest vector) is to the relative left of the source vector.

Knowing whether the 'dest' vector is clockwise or counterclockwise on the same plane that S and D lie on tells use which direction to turn, which is useful especially for AI movements.

Vector Projection

Vector projection means that you're taking a vector, and projecting it onto another vector.

It is important to note that the length (magnitude) of a vector is often represented like so: | b |

The formula for projecting a vector (vector A) onto another vector (vector B) is:

projB (A) = ( (a (dot) b) / |b|^2 ) * b

Lets see an example:
Vector a = (2, 2, 0)
Vector b = (1, 0, 0)

a (dot) b = 2 * 1 + 2 * 0 + 0 * 0 = 2

( 2 / 1 ) * b = (2, 0, 0)


Vector A' is the result of the vector projection of vector 'A' onto vector 'B'. The best way to think about this is that vector A' is in the same direction as vector 'B', and any part of the original 'A' that wasn't in this direction is discarded. So if you look at vector B, it is in the +X direction only, represented by 1, 0, 0. If you took vector 'A' and took out anything not in the +X direction, then you you be left with (2, 0, 0), and that is what we get with the vector projection. It is easy to look at this visually in this example because vector 'B' runs exactly along one of the three major axes. But in most cases it isn't as easy to visualize, and that is why the formula helps.

Here is how we'd do it in XNA:

public Vector3 ProjectVector( Vector3 Source, Vector3 Target, Vector3 DestsRight )
{
    float dotProduct = 0.0f;
    Vector3.Dot(Source, Target, dotProduct);

    Vector3 projectedVector = (dotProduct / Target.LengthSquared()) * Target;
    return projectedVector;
}


Cross Product (under construction)

Cross product is another product of multiplication of vectors.

Next