The Vector Dot Product – Useful Math for Game Developers

Have you ever heard about the Vector Dot Product? Perhaps you have seen it mentioned and maybe you come across it in code. So what is the vector dot product exactly?

The vector dot product is an incredible useful mathematical function that returns information about two vectors. We can check if vectors are parallel and perpendicular..

The uses of Vector Dot Products are found throughout the game development landscape. It’s used in rendering optimization, gameplay programming to AI techniques.

The Vector Dot Product - Useful math for game developers

What is the Vector Dot Product?

The Vector Dot Product is a mathematical function that can be performed on two Vectors. The result is a value that describes the angular relationship between the two vectors. In simpler words, it is a function that returns a value that represents the angle between the two vectors.

While there are many math libraries out there, implementing your own dot product is not very difficult. Once you have a Vector3 structure, you can implement a Dot product as follows:

  1. public float DotProduct(Vector3 a, Vector3 b)
  2. {
  3. return (a.x * b.x) + (a.y + b.y) + (a.z * b.z);
  4. }

What Makes the Vector Dot Product so Useful?

As mentioned before, applying the Dot Product on two vectors returns a value that equals the angular relationship between them. So why is this useful to us? Well, this means it’s easy figure out if the vectors are pointing in the same direction. Next to that, we can check if they are perpendicular or are pointing in the opposite direction.

To illustrate this, we created three possible scenarios that all feature two normalized vectors (red and blue). For extra clarity we indicated the angle between the two vectors. You can try visualizing the blue vector rotating in a clockwise direction. As the blue vector rotates, the angle a gets smaller and smaller until both vectors line up. In the third scenarios the vectors actually line up precisely so we colored them purple.

Dot product between two vectors offset by an angle of 180 degrees

Situation A
a = 180 Degrees

Dot product between two vectors offset by an angle of 90 degrees

Situation B
a = 90 Degrees

Dot product between two vectors offset by an angle of 0 degrees

Situation C
a = 0 Degrees

When we calculate the Dot Product using the vectors from the above scenarios we get the following results:

Situation A
Dot Product = -1

Situation B
Dot Product = 0

Situation C
Dot Product = 1


Looking at the results, you should see an interesting pattern starting to emerge. By using the Dot Product, we are able to figure out how the vectors are aligned to each other. As can be seen above, when the vectors get closer to lining up, the Dot Product will return a value closer to 1. Similarly, the more opposite the vectors get, the closer the Dot Product will return a value of -1. Finally, the closer the vectors are to being perfectly orthogonal (Situation B) the Dot Product will return a value closer to 0.


What Functions Can We Use the Dot Product For?

Now that we have figured out some interesting properties of the Dot Product, we can start utilizing them. Let’s explore how we can use these properties in a variety of ways to our benefit. For example, we can create algorithms to steer objects automatically. Next to that, we can even calculate how surfaces should be lit during rendering.

1. Detecting Whether an Object is Facing Another Object

In the example below, we have a player ship represented in green. Next, we have two enemy ships represented using the color red. By using the Dot Product, we can determine if the player ship is facing (pointing towards) any of the two enemy ships.

Detect if an object is facing another object.
Player Ship with 2 Enemy Ships

To determine if the player ship is facing an enemy ship, we need to have two vectors in place.

The first vector is the normalized direction vector of the player ship (purple). The second vector is a vector that represents the normalized direction from the player to an enemy ship (red or blue).

We can calculate the directions towards the enemy ships very easily. We do this by subtracting the position of each enemy ship by position from the player ship. As a result, we end up with two vectors (red and blue)

Now that we have constructed two vectors, we can calculate the corresponding Dot Product. If we think back about the properties of the Dot Product, we can predict that the Dot Product of the left enemy ship will return a value ranging from [0….1. Also, the top enemy ship will return a value ranging from [-1…0].. As you can see, we now have a way to determine if the enemy ship is visible. We do this by comparing the return value of the Dot Products for each enemy ship with the player.

Additionally, we can implement a sort of threshold value. Using this value we can implement a Field of View for the player ship. As a result, if the enemy ship is within this field of view then we can assume it’s seen by the player.. An implementation of this can be seen in the snippet below.

  1. public bool IsInFieldOfView(Vector3 playerDirection, Vector3 playerPosition, Vector3 enemyPosition, float fov)
  2. {
  3. // Calculate at which angle the player is facing the enemy
  4. Vector3 enemyDirection = Vector3.Normalize(playerPosition - enemyPosition);
  5. float facingAngle = Vector3.Dot(playerDirection, enemyDirection);
  6.  
  7. // Determine if the facing angle is within the specified fov
  8. if(facingAngle >= 0.0f)
  9. {
  10. float halfFoV = fov * 0.5f;
  11. float inverseFacingAngleDegrees = (1.0f-facingAngle) * 90.0f;
  12.  
  13. return (inverseFacingAngleDegrees <= halfFoV);
  14. }
  15.  
  16. return false;
  17. }

2. Lighting of Surfaces

Since the Dot Product can be used to determine the angle between two vectors, we can use it to determine how much a surface should be lit. This is often done in rendering to produce so called diffuse lighting. In the illustration below, there are two surfaces that we try to light by a light source. In the illustration, the light source represents our sun. Next, we represent the sun by a normalized direction vector (like a sun ray). Since the sun is so far away, we consider all rays parallel and thus being the same.

First, let’s think about how we could approach this by taking examples from the real world. What happens if the surface rotates away or towards the sun?

  • If a surface points towards the sun, we say that the sun is lighting up the surface.
  • If the surface points away from the sun, we say that the sun is no longer lighting up the surface.

To determine how much to light a surface, we simply take the Dot Product of both the surface normal (red or blue) and a sun ray (yellow).

However, when remembering the properties of the Dot Product, we actually need to inverse the resulting value of the Dot Product. In this case, we want to light up a surface if the two vectors are opposing each other.

Finally, we also want to make sure that we stop processing if the resulting Dot Product becomes negative. In our scenario this would simply mean that the surface is fully pointing away from the sun.

Use the dot product to implement diffuse lighting of surfaces
Sun Rays Htting 2 Surfaces

An implementation could look as follows. Important to note in this implementation is that instead of actually inversing the output of the Dot Product, we actually just flip the sun direction by negating it. Also, we clamp the resulting value in the range of [0….1] to make sure there will be no negative values at all.

  1. public float CalculateSurfaceLight(Vector3 surfaceNormal, Vector3 sunDirection)
  2. {
  3. float dot = Vector3.Dot(surfaceNormal, -sunDirection);
  4. return Mathf.Clamp(dot, 0.0f, 1.0f);
  5. }

3. Rendering Optimizations

Using what we learned in the previous paragraph, we can also use the Vector Dot Product for Rendering Optimizations. However, this time we don’t use a sun direction but a camera direction vector. Then we use the camera direction to determine if we can actually see a surface or not. Similarly to checking if a surface should be lit, we can check if a surface can be seen by the camera.

This technique is called backface culling. In this technique, we don’t try to render the backsides of models as we can’t see these anyway. This leads to performance optimizations as we only render to the screen what the user sees. As a result, this improving performance by reducing draw calls.


Summary

What you learned in this article:

  • The vector dot product is an incredible useful mathematical function that returns information about two vectors.
  • It is a function that returns a value that represents the angle between the two vectors.
  • We can use it to figure out if the vectors are pointing in the same direction, are perpendicular or are pointing in the opposite direction.
  • We shared how the dot product can be used in determining if 3d objects can see each other.
  • We shared how the dot product can be used to perform lighting calculations and rendering optimizations.
Summary of the article

Conclusion

To conclude, we hope you now have a better understanding of the Vector Dot Product and why it is so incredibly useful. In this article, we have shown you how it works along with some of the math behind it. Finally, we have shown you several examples where the dot product is used in game development.