Applications of the dot product

Here you can see the full diagram of the dot product! In the following, we will explore, how these parts can be used for various operations.

In all of the following visualizations, you can move around any points (gray circles) with your mouse.

Introduction

I have seen a few people without a background in math or computer science struggling with writing code for game scripts. While having comprehensive understanding of math isn't needed, I feel that grasping the basic concepts can spare you a lot of problems.

This small course aims to show you some basic operations of the dot product that might be usable in a game development context. Each section will contain some explanations, interactive diagrams and formulas to give you all you need get started. Additionally, I will try to list problems, that can be solved with the given operation. Semi formal proofs are also given, so if you want a slightly deeper understanding about how something works, you can check those out.

Generally, all the diagrams can be manipulated in some way by dragging the marked points to show you visually and with calculations what is happening.

The two basic geometric properties associated with the dot product are distances and angles, which makes it usable in many contexts. Basically, every time you have a problem involving any of these two properties, there is a good chance, the dot product is involved in one way or another.

I will always suggest drawing the geometry you are interested in! For example, your character will send out an energy wave in an arc with some extent. Now, when you draw this on a page, you might quickly see, that it looks very similar to the diagram in the section about cones! Then you already have a quick recipe to get a base implementation.

If you just only find some more insight into what the dot product means, then I am already happy with the results!

With that, let's get going!

Basics

Before we start with the actual applications, let's just recap the basics.

We will write vectors in bold face like a,b,u,v\mathbf{a},\mathbf{b}, \mathbf{u},\mathbf{v}. We will use only 2D vectors here, but all the formulas work in any dimension (3,4, ...), as aside from computing the value of the dot product itself, we won't need any coordinates. We will write coordinates of a vector in a normal font with the coordinate as a subscript to the vector name. For example, the x-coordinate of a\mathbf{a} is written as axa_x.

This will not be a full introduction into vectors, but as a quick recap:

In the following, we only have to deal with one angle, the angle between two vectors. We will write it, if needed, as α\alpha (alpha). The angle between two vectors is the smallest angle between them, which is 0[rad]=00 [rad] = 0^\circ when they coincide and π[rad]=180\pi [rad] = 180^\circ when they point in opposite directions. You can see this below.

When writing out angles, we will generally use degrees here, as many may not be that familiar with radians, but I highly advise you to get comfortable with radians, as it is the unit that math functions work with. If you mix the two units, you might run into very hard to track bugs.

The dot product will be written with a dot between two vectors. So the dot product of a\mathbf{a} and b\mathbf{b} is ab\mathbf{a}\cdot \mathbf{b}

There are two equivalent definitions of the dot product:

ab=axbx+ayby=abcosα\begin{align*} \mathbf{a}\cdot \mathbf{b} &= a_x b_x + a_y b_y \\ &= |\mathbf{a}| |\mathbf{b}| \cos\alpha \end{align*}

(For higher dimensions, you would just add more terms for the appropriate coordinate in the sum)

Here, |\cdot| denotes the length of a vector (we don't use ||\cdot|| to make it easier to read). This is computed as the square root of the sum of all squared components of a vector, so for 2D it is (Pythagoras!):

a=ax2+ay2 |\mathbf{a}|= \sqrt{a_x^2 + a_y^2}

You can think about the two definitions as follows:

axbx+aybya_x b_x + a_y b_y is used to "mechanically" compute the value of the dot product, as we only need to know vector coordinates. It is more of a helper function. In pretty much all game engines and programming languages/libraries that support vectors, you will also have a function, that does this for you, usually just called 'dot' (or 'Dot', as can be seen in Unity).

abcosα|\mathbf{a}| |\mathbf{b}| \cos\alpha is used when we want to think about the geometric meaning of the dot product, as it contains both distances (the lengths) and the angle.

From this, we can already gather a few computation rules already.

Since ab=ba|\mathbf{a}| |\mathbf{b}| = |\mathbf{b}| |\mathbf{a}|, the order of the vectors doesn't matter.

ab=ba\mathbf{a}\cdot \mathbf{b} = \mathbf{b}\cdot \mathbf{a}

This is called the commutative property.

It is a bit tedious, but from the first definition, we can see that:

a(sb+c)=s(ab)+ac\mathbf{a}\cdot (s\mathbf{b} + \mathbf{c}) = s(\mathbf{a}\cdot\mathbf{b}) + \mathbf{a}\cdot \mathbf{c}

We will quickly verify this with a 1D vector (only x-coordinates), but you can try to prove it yourself by adding y or z or any number of coordinates.

a(sb+c)=ax(sbx+cx)=saxbx+axcx=s(ab)+ac \mathbf{a}\cdot (s\mathbf{b} + \mathbf{c}) = a_x (s b_x + c_x) = s a_x b_x + a_x c_x = s(\mathbf{a}\cdot\mathbf{b}) + \mathbf{a}\cdot \mathbf{c}

This is called bilinearity, which is just a fancy way of saying that you can do scalar multiplication outside the dot product or inside and that addition can get split into two dot products (just like with normal numbers).

As a quick reminder, here is a visualization of one way to define the cosine (and sine) of an angle:

If we imagine a unit circle (circle with radius 1) and choose the point on the circle corresponding to the angle α\alpha, then the x-coordinate of that point is the cosine and the y-coordinate is the sine of that angle.

We will see a very similar image in the different operations again.

That is basically all we really need here, so let's get started with the applications.

If you are curious, the full geometry of the dot product can be seen in the following diagram. The dot product can be visualized as the area spanned by the projection of one vector onto another (covered here) and the length of that other vector. When either or both vectors have length 1, you can find some useful special cases!

Angle/Cosine of angle between two vectors

Applications

Procedure - Find the angle/cosine of the angle between a\mathbf{a} and b\mathbf{b}

  1. Compute the length of both vectors: a,b|\mathbf{a}|, |\mathbf{b}|
  2. Compute the dot product: ab\mathbf{a}\cdot \mathbf{b}
  3. The cosine of the angle is: cosα=abab\cos{\alpha} = \frac{\mathbf{a}\cdot \mathbf{b}}{|\mathbf{a}| |\mathbf{b}|}
  4. (OPTIONAL) The angle is: α=acos(cosα)\alpha = \operatorname{acos}(\cos{\alpha})

In many cases, it is useful to have some idea about angles between vectors. For example, let's say you want an interface, where you can specify the direction in which to throw a paper plane. For calculations or information UI, you might want to find the angle to the ground or the optimal throwing direction.

So our goal is to find the shortest angle between two vectors. Though, in many cases, we don't actually need the angle itself, as the cosine is enough. For example, we want to check, whether the angle is smaller than some maximum angle αmax\alpha_{\text{max}}. We can instead just use cosαmax\cos{\alpha_{\text{max}}} for comparisons. The cosine starts at its highest value at 00^\circ and decreases until the highest angle 180180^\circ (Note: The actual cosine function does extend past this range, but we will only get these angles). So if we want to express α<αmax\alpha < \alpha_{\text{max}}, we can instead use cosα>cosαmax\cos{\alpha} > \cos{\alpha_{\text{max}}}. The diagram will make the shape of the cosine with respect to the angle a bit clearer.

As this operation is very general, it is part of many others. Thus the most direct applications listed above are comparing directions and just computing cosine terms directly, as they come up a lot in shading calculations.


Derivation

Since we have ab=abcosα\mathbf{a}\cdot \mathbf{b} = |\mathbf{a}| |\mathbf{b}|\cos{\alpha}, we can get the cosine by dividing through the equation.

ab=abcosαabab=cosα\begin{align*} \mathbf{a}\cdot \mathbf{b} &= |\mathbf{a}| |\mathbf{b}|\cos{\alpha} \\ \frac{\mathbf{a}\cdot \mathbf{b}}{|\mathbf{a}| |\mathbf{b}|} &= \cos{\alpha} \end{align*}

Length of a vector

Applications

Procedure - Find the (squared) length of a vector a\mathbf{a}

  1. Compute the dot product: aa\mathbf{a}\cdot \mathbf{a}
  2. The squared length is equal to the value of step 1: a2=aa|\mathbf{a}|^2 = \mathbf{a}\cdot \mathbf{a}
  3. (OPTIONAL) The length is: a=a2=aa|\mathbf{a}| = \sqrt{|\mathbf{a}|^2} = \sqrt{\mathbf{a}\cdot \mathbf{a}}

Distance is something that comes up all the time. Is an object in range? How strong is the influence of a power up at a far away point? What is the closest enemy?

We already know, how to compute the length of a vector, but when multiplying a vector by itself using the dot product, we actually get the squared length, which is in many cases all we need. For example, if you want to check, whether a vector's length is smaller than some value r0r \geq 0. You can express this as a<r|\mathbf{a}| < r (\leq is also possible) As both sides of this inequality are greater than zero, we are allowed to apply a square operation on both sides. Thus we have:

a<ra2<r2aa<r2\begin{align*} |\mathbf{a}| &< r \\ |\mathbf{a}|^2 < r^2 \\ \mathbf{a}\cdot\mathbf{a} < r^2 \end{align*}

Of course, you can do the same with a greater sign.

This allows you to skip a whole square root operation, which today isn't much, but if you do it a lot it might still cost some computation power.

One obvious application, is checking whether a point is less than a certain radius away from another point. For example, if you want to check, whether a player is in the influence area of some item that has a specified radius. Let the player be at position p\mathbf{p}, the item at q\mathbf{q} and the radius be rr. Then we can apply the above.

Let a=pq\mathbf{a} = \mathbf{p} - \mathbf{q} be the vector from the item to the player. If aa<r2\mathbf{a}\cdot\mathbf{a} < r^2, then the player is influenced by the item, otherwise not.

You can see this in the diagram below.


Derivation

We know that the length of a vector a\mathbf{a} is computed as a=ax2+ay2|\mathbf{a}| = \sqrt{a_x^2 + a_y^2}.

The dot product aa\mathbf{a} \cdot \mathbf{a} is:

aa=axax+ayay=ax2+ay2=a2\begin{align*} \mathbf{a} \cdot \mathbf{a} &= a_x a_x + a_y a_y \\ &= a_x^2 + a_y^2 \\ &= |\mathbf{a}|^2 \end{align*}

For other dimensions, this is the same. For example in 3D, we have a=ax2+ay2+az2|\mathbf{a}| = \sqrt{a_x^2 + a_y^2 + a_z^2}. In the dot product, the z-term is added as well, so the result will be the same.

Actually, in some math contexts, the length is just defined via the dot product!

Check, if a vector lies in a cone

Applications

Procedure - Check, whether a vector a\mathbf{a} lies in a cone with direction v\mathbf{v}, maximum opening angle αmax\alpha_{\text{max}} and radius rr.

If your cone does not have a maximum radius, you can skip step 1). You could also add a minimum radius rminr_{\text{min}} by adding a second distance check with a << or \leq check instead

  1. Compute the squared distance of a\mathbf{a}: a2=aa|\mathbf{a}|^2= \mathbf{a}\cdot \mathbf{a}

    1. If a2>r|\mathbf{a}|^2 > r \Rightarrow, vector is outside
    2. Otherwise, it is inside the radius. We also need to check the angle
  2. Compute the cosine of the angle α\alpha between a\mathbf{a} and v\mathbf{v}: cosα=avav \cos{\alpha} = \frac{\mathbf{a}\cdot \mathbf{v}}{|\mathbf{a}| |\mathbf{v}|}

  3. Compute cosαmax\cos{\alpha_{\text{max}}} (can be precomputed, if it doesn't constantly changed)

    1. If cosα<cosαmax\cos{\alpha} < \cos{\alpha_{\text{max}}}, vector is outside
    2. Otherwise, it is inside the angular constraint
  4. If either the distance or angular constraint said, the vector is outside, it is outside. Otherwise it is inside (you can early return at step 1.1)

This operation is basically just a combination of the distance check and the cosine angle calculation. As mentioned in the latter, instead of checking α<αmax\alpha < \alpha_{\text{max}}, we can instead use cosα>cosαmax\cos{\alpha} > \cos{\alpha_{\text{max}}}.

Let's say, we have our player character at position p\mathbf{p} and the enemy at q\mathbf{q}. The enemy is looking in a direction v\mathbf{v}, has a field of vision (half angle) of αmax\alpha_{\text{max}} and can see rr units far. The vector a\mathbf{a} from the enemy to the player is a=pq\mathbf{a} = \mathbf{p} - \mathbf{q}. Using this and the above procedure above, we can determine, whether the enemy can spot us!

You can see this scenario in the diagram below.


Derivation

This is a consequence of the previous entries distance check and angle calculation.

Checking, if two vectors point into the same half space

Applications

Procedure - Check, whether a vector a\mathbf{a} points in the same or opposite half space of b\mathbf{b} (and vice versa)

  1. Compute the dot product ab \mathbf{a}\cdot \mathbf{b}

    1. If ab>0\mathbf{a}\cdot \mathbf{b} > 0 \Rightarrow both vectors point into the same half space
    2. If ab<0\mathbf{a}\cdot \mathbf{b} < 0 \Rightarrow both vectors point into opposite half spaces
    3. Otherwise (ab=0\mathbf{a}\cdot \mathbf{b} = 0 ) \Rightarrow both vectors are perpendicular to each other

A vector can divide space into points pointing in the same half space, the opposite one or being perpendicular. In 2D, this means, this division line can be visualized as a line perpendicular to the vector. In 3D it is a plane and in higher dimensions it is a hyperplane.

Intuitively you can think about a compass. Let's take north as our vector direction. Then north-east and north-west point into the same half space (north itself of course also points in the same one). east and west are perpendicular. south, south-east and south-west all point in the opposite half-space.

We can also formulate this with angles. If the angle between two vectors is less than 9090^\circ, they point in the same half space. If the angle is exactly 9090^\circ, they are perpendicular. Otherwise (the angle is greater than 9090^\circ), they point in opposite half spaces.

The above procedure is very efficient, as it only requires a single dot product.

You can see this in the diagram below:


Derivation

If you have a look at the diagram in the angle section, you can check out the ranges of the cosine for the angles between the vectors. Importantly, these angles are only in the range [0,180][0^\circ,180^\circ].

For α[0,90)\alpha \in [0^\circ, 90^\circ), we see that cos(α)>0\cos(\alpha) > 0. For α=90\alpha = 90^\circ,cos(α)=0\cos(\alpha) = 0 and for the rest cos(α)<0\cos(\alpha) < 0.

So to determine, which half-spaces the vectors point into, we just need to check the sign of the cosine.

The dot product is ab=abcosα\mathbf{a} \cdot \mathbf{b} = |\mathbf{a}| |\mathbf{b}| \cos\alpha. But a |\mathbf{a}| and b|\mathbf{b}| are both zero or positive, so they have no influence on the sign of the dot product! That means, we don't need to divide by the vector lengths to get the sign of the cosine and we can skip that computation.

Projection of one vector onto another

Applications

Procedure - Project a vector a\mathbf{a} onto a vector b\mathbf{b}

  1. Compute the dot product ab \mathbf{a}\cdot \mathbf{b}

  2. The projection aba_{\mathbf{b}} is: ab=abb=abba_{\mathbf{b}} = \frac{ \mathbf{a}\cdot \mathbf{b}}{|\mathbf{b}|} = \mathbf{a}\cdot \frac{\mathbf{b}}{|\mathbf{b}|}

    • Note: If b\mathbf{b} is normalized (b=1|\mathbf{b}| = 1), then you can skip the division. Sometimes, you know the length beforehand, for example, if you enforce it via code or generate it via special means.

Projecting a vector a\mathbf{a} onto another vector b\mathbf{b} means: How much of a\mathbf{a} points into the direction of b\mathbf{b}. In other words. We draw a line perpendicular to b\mathbf{b} that goes through the tip of a\mathbf{a}. Where that line intersects b\mathbf{b} is the tip of the projection of a\mathbf{a}. Like the shadow of a\mathbf{a} onto b\mathbf{b}.

Let's say you have a line segment between two points p1\mathbf{p}_1 and p0\mathbf{p}_0. The vector between them is b=q1q0\mathbf{b} = \mathbf{q}_1 - \mathbf{q}_0. This could be a segment of a racing game track. The player is at position p\mathbf{p}. How far along the way from q0\mathbf{q}_0 to q1\mathbf{q}_1 is the player? This is the projection! You can compute the vector b=pq0\mathbf{b} = \mathbf{p} - \mathbf{q}_0 (so both a\mathbf{a} and b\mathbf{b} have the same reference point). With this, the above procedure gives us the projecti


Derivation

We can think about the definition of the cosine in the unit circle again, as seen in the basics

Now, let's say we are not in the unit circle, but instead one with radius rr. What happens to the coordinate? Well, the circle will basically look the same, but it is scaled with a factor of rr! The coordinates are, of course, scaled as well, so the x-coordinate is rcosαr\cos\alpha instead of cosα\cos\alpha.

The x-coordinate is just the circle point projected onto the x-axis.

Now, let's say our vector b\mathbf{b} corresponds to the x-axis and a\mathbf{a} to the vector to the circle point. The angle of that point is the angle between the two vectors. The radius rr is just the length of a\mathbf{a}: a|\mathbf{a}|.

Plugging that into the scaled circle x-coordinate results in: rcosα=acosαr\cos\alpha =|\mathbf{a}|\cos\alpha . This is just the dot product divided by b|\mathbf{b}|!

Thus our projection aba_{\mathbf{b}} of a\mathbf{a} onto b\mathbf{b} is:

ab=acosα=abbabb\begin{align*} a_{\mathbf{b}} &= |\mathbf{a}|\cos\alpha \\ &= \frac{\mathbf{a} \cdot \mathbf{b}}{\mathbf{b}}\\ \mathbf{a}\cdot \frac{\mathbf{b}}{|\mathbf{b}|} \end{align*}

The last line results from b|\mathbf{b}|| just being a number, so we can move it into the dot product due to its property of linearity.

Additionally, this means, the projection of a vector onto a normalized vector is just the dot product!

We can see this in action in the following diagram.

Decomposing a vector with respect to another

Applications

Procedure - Decompose a vector a\mathbf{a} with respect to b\mathbf{b} into a vector parallel to b\mathbf{b} (ab\mathbf{a}_{\mathbf{b}}) and one perpendicular to b\mathbf{b} (ab)\mathbf{a}_{\mathbf{b}}^\perp), such that a=ab+ab \mathbf{a} = \mathbf{a}_{\mathbf{b}} + \mathbf{a}_{\mathbf{b}}^\perp

  1. Compute the dot product ab \mathbf{a}\cdot \mathbf{b}
  2. Compute the projection vector ab\mathbf{a}_{\mathbf{b}} of a\mathbf{a} onto b\mathbf{b}: ab=abb2b\mathbf{a}_{\mathbf{b}} = \frac{ \mathbf{a}\cdot \mathbf{b}}{|\mathbf{b}|^2} \mathbf{b}
  3. Compute the perpendicular projection vector ab\mathbf{a}_{\mathbf{b}}^\perp: ab=aab \mathbf{a}_{\mathbf{b}}^\perp=\mathbf{a} - \mathbf{a}_{\mathbf{b}}

In the previous section, we found th projection of a vector a\mathbf{a} onto another vector b\mathbf{b}. This is just an extension to that. Instead of just computing the length of the projection, we also want the vector corresponding to it, so a vector with the length of the projection pointing in the same direction as b\mathbf{b}. And from the previous diagram, there is another vector: The perpendicular part from the tip of the projection to the tip of a\mathbf{a}.

How can this be useful? First of all, having the direction in addition to the length allows you to show the projection itself. Let's say you have a spaceship game, where the ship can move in all directions. Let's say you fly to the right and there is a vertical wall. If you keep going in the same direction, the wall will block you so you don't move at all. But if the wall is angled, you will expect to keep moving, but maybe not with the same speed, since you are still partially pressing into the wall. And maybe you want to bounce your player a bit away from the wall when they ram into it. You could handle all the specific wall angles, or you could decompose the vector into the part pointing along the wall normal and the other one being in the wall plane. Movement is then only the part in the wall plane and the bounce happens in the direction of the normal. This is of course a simple scenario, but an actual implementation can be very similar to this (and a physics based solution is also very similar)!

You can see the decomposition in the diagram below:


Derivation

From the previous section, we know how to compute the projection of a vector onto another (which is a signed length). ab=abba_{\mathbf{b}} = \frac{\mathbf{a} \cdot \mathbf{b}}{\mathbf{b}}

To get a vector with that length pointing in the same direction as b\mathbf{b}, we just need to normalize b\mathbf{b} and multiply it with the length of the projection.

ab=abbb=abbbb=abb2b\begin{align*} \mathbf{a}_{\mathbf{b}} &= a_{\mathbf{b}} \frac{\mathbf{b}}{|\mathbf{b}|} \\ &= \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{b}|} \frac{\mathbf{b}}{|\mathbf{b}|} \\ &= \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{b}|^2} \mathbf{b} \end{align*}

We then compute the perpendicular part as described in the procedure: ab=aab \mathbf{a}_{\mathbf{b}}^\perp=\mathbf{a} - \mathbf{a}_{\mathbf{b}}.

As ab\mathbf{a}_{\mathbf{b}} was constructed to point into the same direction as b\mathbf{b}, we know they are parallel. But we also need to show, that ab\mathbf{a}_{\mathbf{b}}^\perp really is perpendicular to b\mathbf{b}.

For that we use the dot product rule from the section about half spaces. The dot product must be zero.

abb=(aab)b=ababb=ababb2bb=ababb2b2=abab=0\begin{align*} \mathbf{a}_{\mathbf{b}}^\perp \cdot \mathbf{b} &= (\mathbf{a} - \mathbf{a}_{\mathbf{b}} ) \cdot \mathbf{b}\\ &= \mathbf{a}\cdot \mathbf{b} - \mathbf{a}_{\mathbf{b}} \cdot \mathbf{b}\\ &= \mathbf{a}\cdot \mathbf{b} - \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{b}|^2} \mathbf{b} \cdot \mathbf{b}\\ &= \mathbf{a}\cdot \mathbf{b} - \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{b}|^2} |\mathbf{b}|^2\\ &= \mathbf{a}\cdot \mathbf{b} - \mathbf{a} \cdot \mathbf{b}\\ &= 0 \end{align*}

Thus, ab\mathbf{a}_{\mathbf{b}}^\perp really is perpendicular to b\mathbf{b}!

Just as a formality, we show, that we can reconstruct a\mathbf{a} from its decomposition:

ab+ab=ab+aab=a\begin{align*} \mathbf{a}_{\mathbf{b}} + \mathbf{a}_{\mathbf{b}}^\perp &= \mathbf{a}_{\mathbf{b}} + \mathbf{a} - \mathbf{a}_{\mathbf{b}} \\ &= \mathbf{a} \end{align*}