Let's begin by talking about space. When we refer to space here, we're not talking about the vast expanse beyond our planet—the stars, the moon, or asteroids. Instead, we're discussing space in a mathematical or geometric sense.
At its simplest, space can be represented as a line. When we have just one line, we typically call it the x-axis. When we introduce a second line, we usually label the horizontal one as the x-axis, and the vertical one as the y-axis. Together, these two lines form a plane.
When we add a third line, we enter the realm of 3D space, which begins to resemble the three-dimensional world we live in—something like a cube or a box. This third axis is called the z-axis.
But space doesn't stop at three dimensions. There are higher-dimensional spaces as well, like 4D or 5D space. However, human brains aren't naturally equipped to visualize these higher dimensions.
In summary, the key axes in the spaces we most commonly deal with are:
- x-axis (horizontal)
- y-axis (vertical)
- z-axis (depth, in 3D space)
- and sometimes a w-axis, which appears in 4D and beyond.
Why the sequence goes x, y, z, and then w isn't entirely clear—it might seem more intuitive for the w-axis to appear at the front or elsewhere. But this naming convention could be related to a topic we'll explore in a future session: quaternions.
Before we move on, here's a quick note for math enthusiasts: you might notice that in this example, the y-axis increases downward—this is actually the opposite of how it's usually represented in mathematics, where the y-axis points up. This downward orientation is a legacy from the way old computer monitors were designed.
Back in the CRT (Cathode Ray Tube) monitor days, an electron beam would scan from the top-left of the screen across to the top-right, then move down one row and repeat. Because of this, in computer graphics, we usually treat the top-left corner as the origin point (0, 0). From there, the x-axis increases to the right and the y-axis increases downward. This convention has stuck around mostly out of tradition, even though it's no longer technically necessary.
Vectors in Space
Let's talk about vectors in space.
We can start by creating a simple vector. A vector has a few key characteristics: it has a direction and a length. We can describe a vector numerically by measuring how far it goes along each axis.
For example, let's say we have a vector that moves 2 units along the x-axis and 2 units along the y-axis. We represent this vector as (2, 2).
Now, consider a different vector that also moves 2 units along the x-axis, but it goes down by 4 units. We would represent that vector as (2, 4). This shows how vectors can differ even if they share one coordinate.
Measuring the Length of a Vector
We mentioned that vectors have both direction and length. Let's explore length, also called the magnitude of a vector. Returning to our earlier example, the vector (2, 2) — how long is it?
We use double bars to denote the magnitude: ||(2, 2)||
To find the length, we use the Pythagorean theorem:
In this case:
So, the diagonal vector (2, 2) has a length greater than 2, which makes sense — diagonals are longer than the sides that define them.
Scaling Vectors
What else can we do with a vector like (2, 2)? We can scale it by multiplying it by a number. For instance, if we multiply (2, 2) by 2, we multiply each component by 2:
This new vector, (4, 4), points in the same direction but is twice as long. It's like a stretched version of our original vector.
Normalizing Vectors
We looked at multiplying a vector like (2, 2) by a number, such as 2. But what happens if, instead, we divide the vector by its own length?
We start with the vector (2, 2). Its length, as we've already calculated, is sqrt(8)
. So what happens if we divide each component of the vector by sqrt(8)
?
Doing this gives us a new vector:
This new vector (.7, .7) has a very important and interesting property: its length is exactly 1.
Vectors like this are called:
- Unit vectors
- Direction vectors
- Or normal vectors (in certain contexts)
They're special because they only describe direction, not magnitude. That's why they're so useful. If you take a unit vector and multiply it by any number, you get a new vector that points in the same direction, but has the length of that number. This is why they're often referred to as direction vectors—they represent pure direction.
You'll also hear about unit vectors when we talk about normals—which are vectors that are perpendicular to a surface; which are usually also unit vectors to keep things consistent and mathematically clean.
Vector Addition
What happens when we have more than one vector? Let's consider two vectors: (1, 3) and (3, 1). Now that we have two, what can we do with them?
One immediate thing we can do is add them. Vector addition is done component-wise, meaning we add the corresponding elements of each vector:
-
x-components:
-
y-components:
So, the result of adding (3, 1) and (1, 3) is a new vector: (4, 4).
Visually, we can also interpret this geometrically. If we place the second vector so that it starts at the tip of the first, we form a shape. Likewise, if we reverse the order, placing the first vector at the tip of the second, we form the same shape. The result is a tilted square-like figure, known as a parallelogram.
Parallelograms formed by vector addition will become more important later, so it's a good idea to keep them in mind.
Vector Subtraction
Next, let's consider subtraction.
Take the vectors (3, 1) and (1, 3) again. If we subtract them component-wise:
-
x-components:
-
y-components:
This gives us the new vector: (2, −2).
What does this vector represent? Geometrically, it points from one vector to the other. In this case, subtracting (1, 3) from (3, 1) [(3, 1) - (1, 3)] gives the vector from the tip of (1, 3) (the second vector) to the tip of (3, 1) (the first vector).
If we reverse the subtraction — that is, (1, 3) - (3, 1) — we get (-2, 2), which is the same vector but pointing in the opposite direction.
Why Is Subtraction Useful?
Let's look at our subtraction result: (2, −2). First, we can calculate its length:
We can then normalize it to get the unit vector pointing in that direction:
This gives us a unit vector in the same direction as (2, −2), which is useful for defining direction without regard to magnitude. We can scale this unit vector up or down depending on the application.
But there's another useful insight here: if we treat (3, 1) and (1, 3) not as arrows but simply as points in space, then the vector (2, −2) represents the straight-line path from one point to the other. Its length (2.82) is the distance between those two points.
So, vector subtraction not only gives us direction but also lets us measure how far apart two points are. That's a pretty useful concept in both math and physics.
Cross Product in 3D Space
Let's shift our focus to 3D space. We're going to explore something unique to 3D vectors—a concept known as the cross product.
Although variations of the cross product exist in other spaces, it's primarily understood and used in three dimensions.
Defining a Plane
Before diving into the cross product, we need to talk about how to define a plane in 3D space. You can define a plane using either three points or two vectors that lie within it.
For example, consider two vectors:
Which define the points:
These two vectors (lying on the XY-plane) define a flat surface. You could make more complex planes by choosing points with different z-values, but this simple setup is enough to illustrate the concept.
The Cross Product
Now, suppose we want to find a vector that points straight up: a vector perpendicular to the plane formed by A and B. This perpendicular vector is known as a normal vector, and we calculate it using the cross product.
In practical terms, imagine bouncing a ball off a surface. The angle of incidence (the angle it hits the surface/green) and the angle of reflection (the angle it bounces away/blue) are equal. To calculate this reflection correctly, you need the normal vector (red) to the surface.
The cross product A * B results in a new vector C = (x, y, z). The formula is as follows:
This structure is consistent across all components: you multiply the components that aren't present in the result, then subtract the reverse order.
Let's apply this to our plane vectors:
- A = (2, 1, 0) (red)
- B = (1, 2, 0) (blue)
Substituting into the formula:
So the result is the vector (0, 0, 3).
This vector points straight up, perpendicular to the plane formed by A and B—just as we expected.
Geometric Interpretation: Area
Here's an interesting geometric fact: the length (or magnitude) of the cross product vector equals the area of the parallelogram formed by the two original vectors.
In our case, he magnitude of (0, 0, 3) is 3: so, the parallelogram formed by A and B has an area of 3. And since a triangle is half of a parallelogram, the area of the triangle defined by vectors A and B is 1.5.
In computer graphics, most shapes are rendered as triangles. Knowing the area of a triangle is crucial for things like weighting, shading, or physics calculations. One common approach is to compute the cross product of two sides of a triangle and use its magnitude to determine area-related properties.
Dot Product
We've already seen the cross product, but there's another very useful operation involving vectors: the dot product.
Imagine we have two vectors, and we want to understand how they relate in terms of their directions.
Take two vectors for example:
- Green vector: (3, 1)
- Blue vector: (2, 4)
To calculate the dot product of these two vectors, we multiply their components element-wise and then add the results:
The dot product is a measure of how much two vectors point in the same direction. If two vectors are perfectly perpendicular (at right angles), their dot product is 0. If they point roughly in opposite directions, their dot product is less than 0 (negative).
So the number 10 from our example tells us the green and blue vectors point roughly in the same direction… but what exactly does the 10 represent?
Interpreting the Dot Product as a Projection
It helps to consider unit vectors (vectors with length 1) for clarity.
For the blue vector (2, 4), we calculate its length:
Dividing each component by 4.47 gives the unit vector:
Now, taking the dot product of the green vector (3, 1) with this unit vector:
The value 2.21 represents the length of the projection of the green vector onto the blue vector's direction.
If you multiply the blue unit vector by 2.21, you get a vector representing the part of the green vector along the blue vector's direction. Notice how the dashed line and the blue vector are normal (90 degrees) to each other?
So, the dot product between a vector and a unit vector tells you the length of the vector in the direction of that unit vector.
Using the Dot Product for Reflection
Remember when we talked about bouncing a ball off a surface? Let's analyze the reflection vector.
- We have an incoming direction (green vector).
- The surface's normal vector (red vector), which we assume is a unit vector.
- The reflected vector (blue vector) we want to find.
The key insight is that the reflection vector can be thought of as the incoming vector projected along the normal and then flipped, while the component perpendicular to the normal remains unchanged.
To find the reflection, we break the incoming vector d (direction) into two parts:
- The component along the normal vector n (the ^ indicates a unit vector/orange):
- The component perpendicular to the normal (purple):
The reflection vector (blue) is then:
Since we flip the component along the normal and keep the perpendicular part as is.
Writing this out in a compact formula:
This formula lets you calculate the bounce direction of a vector reflecting off a surface, using the dot product to project onto the normal and then flipping that component.
Angles and Rotations
It's time to shift focus from vectors to angles.
If we map every possible unit vector, and plot just their end points it will create a circle of radius 1 centered at the origin. Every point on this "unit circle" thus corresponds to a vector of length 1.
For example:
- This blue vector lies at the rightmost point on the circle.
- This white vector points roughly halfway up.
- This red vector points roughly halfway down.
Most people learn in school that a full circle measures 360 degrees. This means:
- Halfway around the circle is 180 degrees.
- The blue vector at the rightmost point corresponds to both 0 degrees and 360 degrees because the circle wraps around.
- The white vector, about halfway up, corresponds roughly to 45 degrees.
- The red vector, about halfway down, corresponds roughly to −45 degrees, or equivalently 315 degrees (since 360 - 45 = 315).
We can describe vectors by their direction in terms of the angle they make with a reference axis. For example: to rotate the red vector to align with the white vector, you need to rotate by 90 degrees (45 degrees + 45 degrees).
Introducing Radians
Degrees are intuitive but mathematicians prefer to measure angles in radians. The circumference of a circle is roughly 3.14 times its radius.This special number, 3.14, is called pi (π). It even has its down day celebrating it on March 14th (3/14).
In radians:
- Half a circle (180 degrees) equals π radians.
- A full circle (360 degrees) equals 2π radians.
- A right angle (90 degrees) equals π/2 radians.
Keep this in mind as it makes understanding rotations easier.
How Do We Perform Rotations?
Now we introduce a concept that may seem intimidating: the matrix.
Consider this 2x2 matrix:
Multiplying this matrix by a vector (x, y) (written vertically) rotates the vector by an angle a
.
Before we proceed, let's clarify what sine and cosine actually are.
What is Sine?
The sine function measures how far up (along the y-axis) a point on the unit circle is. When the angle is 0, sine is 0 (we're at the origin horizontally). At π/2 (90 degrees), sine reaches its maximum value of 1 (the highest point on the unit circle). At π (180 degrees), sine returns to 0. At (3π)/2 (270 degrees), sine goes down to −1 (the lowest point). And at 2π (360 degrees), sine returns back to 0.
If you plot sine over these angles, it forms a smooth wave that oscillates between 1 and −1 — the famous sine wave.
What is Cosine?
Cosine measures how far right (along the x-axis) a point on the unit circle is. At angle 0, cosine is 1 (furthest right on the circle). At π/2, cosine goes down to 0 (the top of the circle). At π, cosine becomes −1 (furthest left). At 3π/2, cosine goes back to 0. And at 2π, cosine returns to 1.
Plotting cosine creates a wave similar to sine, but shifted — it looks like sine slid sideways.
Connecting to Vectors
If you know the angle a vector makes with the horizontal axis:
- The x-component of the vector is equal to the cosine of that angle.
- The y-component of the vector is equal to the sine of that angle.
Matrices
Let's shift back to the idea of matrices, but instead of starting with the rotation matrix, let's begin with a simpler one.
Consider the matrix:
and multiply it by the vector (2, 2).
When we multiply a matrix by a vector, we take each row of the matrix and compute the dot product with the vector to get each component of the resulting vector.
For this matrix:
-
The first row (1, 0) dot product with (2, 2) is:
-
The second row (0, 1) dot product with (2, 2) is:
Thus:
The resulting vector is (2, 2), the same as our original vector. This matrix is called the "identity matrix" because multiplying any vector by it leaves the vector unchanged.
Scaling with a Matrix
Now, what if we take the identity matrix and multiply every element by a number, say 3? The matrix becomes:
Multiplying this matrix by the vector (2, 2):
The resulting vector is (6, 6), which is the original vector scaled by 3. Matrices like this are called "scale matrices" because they scale vectors.
Rotation Matrix Example
Recall the rotation matrix:
For a rotation of 45 degrees, convert degrees to radians (π/4):
Approximating sine and cosine values:
The rotation matrix becomes:
Multiplying this matrix by the vector (2, 2):
This means the vector (2, 2), when rotated 45 degrees, points roughly straight down with a length about 2.8 (remember that in graphics y goes down).
Matrix-Matrix Multiplication
One more thing worth discussing while we're on the subject of matrices is what happens when we multiply two matrices together.
Suppose we have two matrices:
We can think of the second matrix as two vectors:
and
We already know how to multiply a matrix by a vector: we take each row of the first matrix, dot product it with the vector, and put the result in each "row" of the vector. So, when multiplying the two matrices, we take each row of the first matrix and dot product it with each column vector of the second matrix.
That means the resulting matrix elements are:
Working through these calculations manually is tedious and repetitive, which is why you should let a computer or calculator handle matrix multiplication—it makes your life much easier.
Extending Matrices to 3D
Everything we've talked about with 2D matrices extends to 3D matrices. The multiplication process remains the same—dot products between rows and columns. The identity matrix in 3D looks like this:
It's just ones along the diagonal and zeros everywhere else.
Rotation matrices in 3D are more complicated. Instead of a simple 2x2 matrix, we now have a 3x3 matrix with rotation values placed around it, depending on the axis of rotation.
This complexity raises questions like: when we say "rotate 45 degrees," around which axis do we rotate? The x-axis? The y-axis? The z-axis? Some other arbitrary axis?
This means we need to think about rotations as a combination of an axis and an angle.
Euler Angles
To manage this, we often use what are called Euler angles. Euler defined rotations as a sequence of rotations around the X, Y, and then Z axes. To compute these rotations, we:
- Build a rotation matrix for the X axis,
- Multiply it by the rotation matrix for the Y axis,
- Multiply that result by the rotation matrix for the Z axis.
You multiply all these matrices together in this order to get a combined rotation matrix.
Some systems allow changing the order (like Z, X, Y), but usually, the order is X, Y, Z, following spatial intuition.
The Gimbal Lock Problem
However, Euler angles have a problem: gimbal lock. When one axis rotates by 90 degrees, the other two axes can align and start rotating around the same plane, causing a loss of one degree of freedom.
Visually, if you rotate around Y properly, the rotations around X and Z can lie in the same plane, making them indistinguishable.
This problem doesn't cause issues when entering static rotation values, but it creates complications when blending multiple rotations for animations.
To solve this problem, we use a concept called quaternions. In an upcoming discussion, we'll explore quaternions and how they provide a more robust and smooth way to handle 3D rotations without the gimbal lock issue.
Transformation Matrices and Homogeneous Coordinates
So far, we've seen how to write scale matrices, and how to create rotation matrices. But how do we handle movement or sliding in space — in other words, translation matrices?
It turns out that to represent translation properly, we need to move into 4D space. This is similar to quaternions: quaternions are a 4D extension used to smooth rotations. Similarly, translation requires us to extend our coordinates from 3D to 4D.
Here's how it works: we start with our normal 3D coordinates (X, Y, Z), and then add a fourth coordinate, either 1 or 0. When this fourth value is 1, it means we are dealing with a point — something that can be translated or moved around in space. When it is 0, it means we are dealing with a direction — which can only represent orientation and cannot be moved around.
Next, we create a new 4x4 matrix that combines scale, rotation, and translation:
- The upper-left 3x3 portion contains the scale and rotation information.
- The rightmost column (excluding the last element) contains the translation values along the X, Y, and Z axes.
- The bottom row is filled mostly with zeros, except the last element, which is 1.
This is called homogeneous coordinates, and the resulting 4x4 matrix is known as a transformation matrix. It can encode position, rotation, and scale all in one matrix — which are the main transformations we need when positioning a 3D model in a virtual world.
So, while we've covered a lot of complicated math, thankfully, it's all manageable once you understand the basic concepts.
Basic Physics
The last topic we'll cover today is some very basic physics. Let's imagine you are a point in space, and you have a velocity vector that tells you the speed and direction you want to move. Where will this point be after applying that vector?
Well, if you're moving at, say, five meters per second, then after one second, you should be exactly five meters away from your starting position.
How can we represent this in a computer? We simply update the position by adding the velocity vector to it. Since both position and velocity can be treated as vectors, this addition is straightforward. If we use homogeneous coordinates, the position vector's ( W ) component would be 1 (since it's a point), and the velocity vector's ( W ) would be 0 (since it's a direction).
However, there's a practical issue with this simple approach. Usually, we run this update inside a loop that runs every frame. Imagine you're running your game at 60 frames per second (fps) — everything looks smooth. But your friend runs the same game on a slower machine that only manages 5 fps. What happens then? Your character would move much faster than your friend's because their velocity updates happen less frequently but cover the same distance each time.
To fix this, we multiply the velocity by the time elapsed per frame (1/"fps"), often called delta time. Instead of using "1 over fps," we use the symbol Δtime (delta time), where delta means "change." This scales the velocity so the movement is consistent regardless of the frame rate.
So the core formula becomes:
This formula covers a huge amount of basic physics you need for games. If you add acceleration, you get:
This takes you even further into physics simulations. More advanced topics, like multiplayer synchronization, require additional tricks such as splitting velocity updates before and after certain calculations, but that's beyond today's scope.