Skip to main content

3D Math Primer - Vectors

This article contains my reading notes from the second chapter of the book 3D Math Primer for Graphics and Game Development, 2nd edition. The subject of the chapter is Vectors, and the chapter starts with the basic properties of vectors. Below I have noted some important (to me) definitions.

As the subject of the book is graphics, the coverage is focused on the geometric interpretations of vectors and vector operations. Geometrically speaking, a vector is a directed line segment that has magnitude and direction.

For any given vector dimension, there is a special vector, known as the zero vector, that has zeroes in every position. The zero vector has zero magnitude, and no direction. Think of the zero vector as a way to express the concept of "no displacement", much as the scalar zero stands for the concept of "no quantity". Below is the three-dimensional zero vector:

\[ \boldsymbol{0} = \begin{bmatrix} 0 \\ 0 \\ 0 \\ \end{bmatrix} \]

It is important to understand that points and vectors are conceptually distinct, but mathematically equivalent. When you think of a location, think of a point and visualize a dot. When you think of a displacement, think of a vector and visualize an arrow. The math we develop in the following sections operates on "vectors" rather than "points". Keep in mind that any point can be represented as a vector from the origin.

Negating a vector results in a vector of the same magnitude but opposite direction. We negate a vector by negating each component of it, i.e.:

\[ - \begin{bmatrix} 2 \\ 2 \\ \end{bmatrix} = \begin{bmatrix} -2 \\ -2 \\ \end{bmatrix} \]

A vector can be multiplied by a scalar, and this will change the magnitude of the vector, and possibly the direction as well.

The linear algebra rules for vector addition are simple: to add two vectors, we add the corresponding components:

\[ \begin{bmatrix} a_1 \\ a_2 \\ \vdots \\ a_n \\ \end{bmatrix} + \begin{bmatrix} b_1 \\ b_2 \\ \vdots \\ b_n \\ \end{bmatrix} = \begin{bmatrix} a_1 + b_1 \\ a_2 + b_2 \\ \vdots \\ a_n + b_n \\ \end{bmatrix} \]

Vector multiplication by a scalar is straightforward; we simply multiply each component of the vector by the scalar:

\[ k \begin{bmatrix} a_1 \\ a_2 \\ \vdots \\ a_n \\ \end{bmatrix} = \begin{bmatrix} a_1 \\ a_2 \\ \vdots \\ a_n \\ \end{bmatrix} k = \begin{bmatrix} k a_1 \\ k a_2 \\ \vdots \\ k a_n \\ \end{bmatrix} \]

Vector addition is commutative,

\[ a+b = b+a \]

whereas vector subtraction is anticommutative,

\[ a−b = −(b−a) \]

The vector subtraction \( b − a \) yields a vector from a to b.

The equation for computing the magnitude of a vector of arbitrary dimension n is as follows:

\[ \lVert \boldsymbol{v} \rVert = \sqrt{\sum_{i=1}^{n} {v_{i}}^{2}} = \sqrt{{v_{1}}^{2} + {v_{2}}^{2} + \dots + {v_{n}}^{2}} \]

A unit vector is a vector that has a magnitude of one. When this book refers to a vector as a "normal" it means "a unit vector perpendicular to something else". This is common usage, but be warned that the word "normal" primarily means "perpendicular" and not "unit length".

For any nonzero vector \( \boldsymbol{v} \), we can compute a unit vector that points in the same direction as \( \boldsymbol{v} \). This process is known as normalizing the vector. The book uses the common notation of putting a hat symbol over unit vectors; for example, \( \hat{\boldsymbol{v}} \), (pronounced "v hat"). To normalize a vector, we divide the vector by its magnitude

\[ \hat{\boldsymbol{v}} = \frac{\boldsymbol{v}}{\lVert \boldsymbol{v} \rVert} \]

The distance formula

The distance between two points can be calculated by determining the length of the vector from one point to another. The distance between two points \( a \) and \( b \) can be determined by subtracting \( b \) from \( a \) (thus getting a vector \( \boldsymbol{d} \)) and calculating the magnitude of this vector. Note, in this formula we are treating points as if they were vectors starting from the origin of the coordinate system.

\[ distance(\boldsymbol{a}, \boldsymbol{b}) = \lVert \boldsymbol{b} - \boldsymbol{a} \rVert = \sqrt{(b_x - a_x)^2 + (b_y - a_y)^2 + (b_z - a_z)^2 } \]

Dot product

The dot product is the sum of the products of corresponding components, resulting in a scalar.

\[ \begin{bmatrix} a_1 \\ a_2 \\ \vdots \\ a_n \\ \end{bmatrix} \cdot \begin{bmatrix} b_1 \\ b_2 \\ \vdots \\ b_n \\ \end{bmatrix} = a_1 b_1 + a_2 b_2 + \dots + a_n b_n \]

Formally, this can be described as follows:

\[ \boldsymbol{a} \cdot \boldsymbol{b} = \sum_{i=1}^{n} a_i b_i \]

For 2D and 3D vectors, this yields the following:

\[ \boldsymbol{a} \cdot \boldsymbol{b} = a_x b_x + a_y b_y \] \[ \boldsymbol{a} \cdot \boldsymbol{b} = a_x b_x + a_y b_y + a_z b_z \]

The dot product \(\boldsymbol{a} \cdot \boldsymbol{b} \) is equal to the signed length of the projection of \( \boldsymbol{b} \) onto any line parallel to \(\boldsymbol{a}\), multiplied by the length of \(\boldsymbol{a}\).

The dot product can also be defined trigonometrically as follows:

\[ \boldsymbol{a} \cdot \boldsymbol{b} = \lVert \boldsymbol{a} \rVert \lVert \boldsymbol{b} \rVert \cos \theta \]

In the formula above, \( \theta \) is the angle between the two vectors when having the same origin.

Given two vectors, we can use the dot product to find the angles between them:

\[ \theta = \arccos \left( \frac{\boldsymbol{a} \cdot \boldsymbol{b}}{\lVert \boldsymbol{a} \rVert \lVert \boldsymbol{b} \rVert} \right) \]

If \( \boldsymbol{a} \) and \( \boldsymbol{b} \) are unit vectors, the equation simply becomes:

\[ \theta = \arccos \left( \hat{\boldsymbol{a}} \cdot \hat{\boldsymbol{b}} \right) \]

One very common use of the dot product is as a projection. Assume once more that \( \hat{\boldsymbol{a}} \) is a unit vector and \( \boldsymbol{b} \) has arbitrary length. Using the dot product, it’s possible to separate \( \boldsymbol{b} \) into two values, \( \boldsymbol{b_{\parallel}} \) and \( \boldsymbol{b_{\perp}} \) (read "b parallel" and "b perp"), which are parallel and perpendicular to \( \hat{\boldsymbol{a}} \), respectively, such that \( \boldsymbol{b} = \boldsymbol{b_{\parallel}} + \boldsymbol{b_{\perp}} \).

We’ve already established that the length of \( \boldsymbol{b_{\parallel}} \) will be equal to \( \hat{\boldsymbol{a}} \cdot \boldsymbol{b} \). But the dot product yields a scalar, and \( \boldsymbol{b_{\parallel}} \) is a vector, so we’ll take the direction specified by the unit vector \( \hat{\boldsymbol{a}} \) and scale it up:

\[ \boldsymbol{b_{\parallel}} = (\hat{\boldsymbol{a}} \cdot \boldsymbol{b}) \hat{\boldsymbol{a}}\]

Once we know \( \boldsymbol{b_{\parallel}} \), we can easily solve for \( \boldsymbol{b_{\perp}} \):

\[ \boldsymbol{b_{\perp}} = \boldsymbol{b} - \boldsymbol{b_{\parallel}} \]

Cross product

The other vector product, known as the cross product, can be applied only in 3D. Unlike the dot product, which yields a scalar and is commutative, the vector cross product yields a 3D vector and is not commutative. The equation for the cross product is:

\[ \begin{bmatrix} x_1 \\ y_1 \\ z_1 \\ \end{bmatrix} \times \begin{bmatrix} x_2 \\ y_2 \\ z_2 \\ \end{bmatrix} = \begin{bmatrix} y_1 z_2 - z_1 y_2\\ z_1 x_2 - x_1 z_2\\ x_1 y_2 - y_1 x_2\\ \end{bmatrix} \]

The cross product yields a vector that is perpendicular to the original two vectors.

The length of the vector \( \boldsymbol{a} \times \boldsymbol{b} \) is:

\[ \lVert \boldsymbol{a} \times \boldsymbol{b} \rVert = \lVert \boldsymbol{a} \rVert \lVert \boldsymbol{b} \rVert \sin \theta \]

One of the most important uses of the cross product is to create a vector that is perpendicular to a plane.