Introduction to Points and Vectors

Most of us already know what points and vectors are. Even in games. I am here to show common pitfalls and and useful tips on how to use the most basic of tools to improve your understanding of game math and to show some cool techniques you can do with them. If you already have a good grasp of points and vectors and just want some information on where you can use them just scroll down below.

A point represents a location in 3D space.

So, a vector is a dude that represents a direction. A direction is not a point. Repeat this with me. A direction is not a point. A direction is not a point. A direction is not a point. Now when you try to do some weird math, let’s conceptualize what we are doing.

From the Game Engine Architecture book by Jason Gregory, (Lead Programmer of Naughty Dog) he has a bit on this and I am going to put an excerpt of it here. You guys better use this till its ingrained in your memory.

• direction + direction = direction
• direction – direction = direction
• point + direction = point
• point – point = direction
• point + point = nonsense (don’t do it!)

An easy way to remember what you are doing, let’s assume all directions are equal to 0 and all points are equal to 1. When you do the operations again up above, see what value you get. Cool isn’t it. (If you want more information on why this is true, look into homogeneous coordinates.)

Direction and Points are represented the same way in code sometimes.

In code, you might see something like this.

//Points in 3D space
Vector3 l_PlayerPosition = transform.position;
Vector3 l_TargetPosition = m_Target.transform.position;

//Direction From Player to Target
Vector3 l_DirectonFromPlayerToTarget = l_TargetPosition - l_PlayerPosition;

A vector is made up of two points. So let’s say we have two points, A and B. If we want the direction from point A to point B. What do we do! We subtract A from B! You would think it would be A – B to get the direction from A to B but boy are you wrong. It is B – A. Good, we now know what a direction and point is.

Point Operations

A point doesn’t have many operations but it is still super important to know what it means. If you have looked above to the excerpt by Jason Gregory, Point + Direction = Point. It is the only one that results in a point and it is super important to know that. I once failed an interview for not utilizing such a simple thing. Alright, so what does this mean? When you have a point and add it to a direction, what you are doing is you are shifting that direction to the point we are adding it to. Then getting the end point of the direction and saying that is the new point.

Picture here for demonstration

Vector Operations

I want to go over 6 operations: addition, subtraction, magnitude, normalizing a vector, projection, and normal vectors. There are 2 more, called dot product and cross product but they will have their dedicated introduction and use cases as well.

Adding or subtracting two vectors or directions as we sometimes call them is quite unique. I would like to show an example for this one before going into the definition.

Alright so notice how we have two vectors V and U. It does not matter the order we add them up in, but notice the resultant. It makes a completely new vector that is in a new direction called U + V. We took the start of one of the vectors and put it at the end of the other vector. Then we created a vector from the first vector’s starting point and the end point of second vector.

You can imagine what subtracting a vector is then. Just take the second vector and flip it in the opposite direction and BAM! We got a new vector just like that. The common mistake here is thinking that subtracting in any order creates the same result. News flash, it does not. So think carefully when subtracting vectors. This means U – V is not the same as V – U. A good way to think about subtraction is thinking in terms of addition. U – V is the same as U + -V. Cool right.

To calculate vector addition or subtraction it is simply adding its components and respectively to subtract it is simply subtract the components in order. The result of this is the new components of the new direction vector.

Vector3 A(1,1,1); //initialized to the direction vector 1,1,1
Vector3 B(1,2,1); //initialized to the direction vector 1,2,1
Vectro3 resultant = A + B; //direction vector of A + B into resultant vector which is 2,3,2

We now know what adding and subtracting vectors is, what it means visually to add and subtract vectors, and how it is calculated.

Magnitude

A magnitude is the length of a vector. Yea that’s right, it means, it is how long that vector is. More importantly is the units which is a scalar. In code, that would be a float.

Let’s see how we calculate the magnitude. We take the components of each vector, we multiply itself together and add it with the next component. Then once all of them are added up, we take the square root. In programming square roots are bad but for learning purposes this is the way. If you want a more optimized version, look into magnitude squared and understand its use cases.

static float magnitude(const vec3& a)
{
return sqrtf(a.x * a.x + a.y * a.y + a.z * a.z);
}


Cool we now know what is a magnitude, what it means visually, and how it is calculated. One other thing is how it might look when writing magnitude in math terms. Usually if I have a direction vector AB, the magnitude of that vector can be shorthanded to this, ||AB||. It can even look like this |AB| but this might conflict with the absolute value symbol so stick with the first one. The people that do the second ones are trolling you.

Normalized Vector

A normalized vector is a vector of magnitude 1. We call these boys unit vectors in the game industry and math in general. These are useful because we can set a standard for all vectors and what I mean by that is since we know the magnitude is 1, that means the length of the vector is 1 right. So when we scale a vector, we get a proper uniform scaling. Other reasons you might want to normalize vectors is with quaternions but that is for another topic.

This is what it looks like when you normalize some vectors. Notice how the length of the green vectors are all the same while the blue ones aren’t. The directions for all the green ones are the same as the blue ones. To normalize a vector, you take the components of the vector and magnitude of that vector and then simply divide each component by the magnitude.

Here is some simple code to normalize a vector.

static vec3 normalize(const vec3& a)
{
float mag_vec = magnitude(a);
return vec3(a.x / mag_vec, a.y / mag_vec, a.z / mag_vec);
}

We know what a normalized vector is, what it means visually, and how it is calculated. These can also be shorthanded to something called hats. I don’t make this stuff up. If I have a vector called AB and I normalize it, it might be called AB hat. The reason for this is the notation of what that might look like which is this.

You see the i, j, and k, they all have hats over them in the picture above. These vectors all have a magnitude of 1. So any vector with a magnitude of 1 is a unit vector than can also be called “whatever name of vector + hat.”

Projection Vector

A projection vector is an operation that allows you to take one vector and project it onto another vector. I did just use the word as the definition but listen its kinda hard to explain. So let’s just look at a picture and you will be like “Ohhhh, I get it.”

Aight, did you get it. Nope, uh, okay, alright. Let us break this picture apart. You see, there is this long blue vector boy V and there is the red vector one over there called U. A projection is as it sounds takes that U vector and puts it on the V vector. This makes the green vector which we call ProjVU. So what we did was projected vector U onto V. So what does this mean, it means we got a vector that is a percentage of the other blue vector V. This will be useful for specific game programming operations which I will show below soon.

To calculate a projection, we take the dot product of U vector and V vector, which we will discuss later and then divide that with magnitude of V squared and then finally multiply all that by vector V.

static float dotp(const vec3& a, const vec3& b)
{
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
}

//project v onto n
static vec3 project_onto(const vec3& v, const vec3& n)
{
float dot = dotp(v, n);
float mag_n = magitude(n);

float scalar = dot / (mag_n * mag_n);
return n * scalar;
}


Notice here there is an operation of the dot product here on the projection code. We will discuss this in another tutorial specifically for dot products. For completeness I am putting it here but know there will be more on what this means.

I want you to notice though is the scalar part. We take the vector n and multiply it by a scalar with that being the percent part of the vector for how long the green vector should be. Also notice the output of the projection is a vector and not a point. We know the difference don’t we. So when you hear someone say to project a point onto the vector, slap them. Just kidding don’t do that but know they are wrong. You can not project a point onto a vector. But lookie here we know the starting point of the vector we are projecting on and we know the vector we want to project. To get the point at the tip of the projected vector we simply take the starting point of the vector we want to project it on and add it with the projected vector.

Now we know what a projected vector is, what it means visually, and how to calculate it.

Normal Vectors

A Normal Vector is a vector that is perfectly perpendicular to another vector, a face, or plane. Nothing fancy there unless you don’t know what perpendicular means. It pretty much means that a line exists that is 90 degrees from the original vector and that is called the normal vector. As Wikipedia says in its fancy terms, “A relationship between two lines which meet at right angles. (90 degrees).”

If you still don’t see it, let’s show an example. I will show you a normal of a line and a normal of a face/plane. We will discuss the similarities in concept.

A line is defined by two points in this case Q1 and Q2 and as we can see the vector n is the normal of that line.

As you can see here, this is a normal of face/plane.

We can take normal vectors of pretty much anything. A lot of games do this as well to do specific gameplay things or just math things. I will show some use cases of them later. I usually show some code here to how to get the information needed for the normal but we can just math this one out. I will do it for lines. I would show you how to do it for faces and planes but I will leave that information in another article talking about cross products and maybe one for planes.

First we get the slope of the line. You guys remember that. 8th grade for me. I can’t believe I am writing about it now.

We have the slope now, if we take the reciprocal of the m, we get the direction vector of the normal. This slope formula can extend to 3D as well. So this will work for both 2D and 3D lines.

Finally we know what a normal vector is, what it means visually, and how to calculate the normal of a line. In games the more useful case is to calculate the normals of faces and planes.

Holy crap this is only the half way point. If you are still here go take a break, grab some water and some snacks.

Actual Use Cases in Game Development

Finally we have learned some important math! Now when you ask your teacher, “When will we ever use this?” I am here to give you that answer!

Most of the math here is used in conjunction with all the other ones. Individually most of these operations are not that valuable but when you put them together, literally endless gameplay possibilities open up! So my favorite part, let’s talk about how we can use them in games.

I am coming up with some of these situations on the spot and some are from games so lets see how this works! When you become a gameplay programmer, games are more fun when you start analyzing how something is made so that is what we are going to do here.

So we know a magnitude is the length of a vector right. We also know it is a scalar value. We also know what it means to normalize a vector. Knowing these facts we can make a camera controller that is X units away at all times while not colliding with anything. So what can we do? We can grab the direction vector from the camera and the player we want to look at. Then we can normalize that vector and finally scale it by X units. The scale is the length of that vector at all times. Lastly we set the Camera Position to be that many units away. Remember position + direction = position.

//Position of Player
Vector3 l_PlayerPosition; //let this be some existing position of the player

//Position of Camera
Vector3 l_CameraPosition; //let this be some existing position of the camera

//Distance we want the Camera to be away from the Player at all times
float l_DistanceFromCamera; //let this be some valid distance away from the player

//Vector from player to camera
Vector3 l_DirectionFromPlayerToCamera = l_PlayerPosition - l_CameraPosition;

//normalize the vector and store it back into vector made up above
l_DirectionFromPlayerToCamera = normalize(l_DirectionToCameraFromPlayer);

//set the position of the camera l_DistanceFromCamera units away from the player at all times
l_CameraPosition = l_PlayerPosition  + l_DirectionFromPlayerToCamera * l_DistanceFromCamera;

//Rotate the Camera to look at the player
l_CameraPosition.lookAt(l_PlayerPosition);

What we used: Normalizing a Vector, Using the concepts of magnitude in terms of a vector, creating a direction vector, and knowing that a position + direction = position. With these tools we were able to make a quick and dirty 3rd Person Camera Controller feature, one that is used in literally every 3rd Person game.

Let’s analyze a gameplay mechanic from a game called Destiny 2. Destiny 2 just got a massive update that involves a new ability they have added called the stasis wall grenade. (My game team was going to add this to our game and we even prototyped something similar to this earlier in development.)

Alright so from watching both of these short clips what do we notice. Both walls are made exactly perpendicular to the wall they spawn on. Ding! Ding! Ding! They instantiated a wall pillar along the normal of the surface. They grab the normal of the triangle of the surface and create the wall along the direction of the normal. We will discuss how to get a normal of a triangle/plane/surface when we talk about cross products and planes.

However this is more tricky than it seems. If you are reading this Bungie I think you guys used a triangle strip to get the distance away for each pillar to spawn from the center pillar and small timer for the walls outside to ascend in the direction of the normal. The edge case I did not understand was sometimes the wall would wrap around lets say a pillar and sometimes it would just create in the same spot. I assume distance away for that and then I saw it overlap a set of objects and I was confused. If you do read this, let me know!

What They Might Have Used: Getting the normal, normalizing the normal vector, Maybe using the concept of magnitude in terms of a vector to scale the wall to an appropriate length.

These are just some ideas of course, and definitely not the actual implementation, but this is fun to do! Trying to break down the math of a gameplay mechanic gives you insight on how things are made and helps you form a better understanding of the tools at your disposal.