The simplest of the four 3D matrix types is the Scaling matrix.
In this context, “scaling” means to make a shape larger or smaller by multiplying a vector by a scalar value.
Given a data type Vector4:
struct Vector4
{
float X;
float Y;
float Z;
float W;
};
A simple way to scale a vector might be:
Vector4 Scale(const Vector4& v, const float uniformScale)
{
return Vector4(v.x * uniformScale, v.y * uniformScale, v.z * uniformScale, v.w);
}
However, if we plan on performing this operation on lots of data points – say, in a vertex shader which operates on every vertex in our model, we’d like to use a matrix so that the scale operation can be combined with our rotation, translation and projection operations. Given an identity matrix:
\(\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \\
\end{bmatrix} \\
\)
and remembering that in a row-major matrix such as this, each row represents a basis vector of a transformed coordinate system. The values on the diagonal of an identity matrix represent a coordinate system that has a scale of 1. Not very exciting.
To create a scaling matrix, we’ll multiply the values on the diagonal with our scale vector
\(\vec{s} = (s_x, s_y, s_z, 1)\)
which gives us:
\begin{bmatrix}
s_x & 0 & 0 & 0 \\
0 & s_y & 0 & 0 \\
0 & 0 & s_z & 0 \\
0 & 0 & 0 & 1 \\
\end{bmatrix}
\)
Notes:
- The the W component of the last row (bottom right corner of the matrix) is NOT modified, as we are only concerned with scaling in X, Y and Z. Scaling W leads to interesting side effects.
- Although this example allows for \(\vec{s}\) to have different values for its \((s_x, s_y, s_z)\) components, we will usually want these all to be the same number for uniform scaling.