<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Linear Algebra on msagca</title><link>https://msagca.github.io/tags/linear-algebra/</link><description>Recent content in Linear Algebra on msagca</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 29 Aug 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://msagca.github.io/tags/linear-algebra/index.xml" rel="self" type="application/rss+xml"/><item><title>Math and Transformations for OpenGL</title><link>https://msagca.github.io/math-and-transformations-for-opengl/</link><pubDate>Fri, 29 Aug 2025 00:00:00 +0000</pubDate><guid>https://msagca.github.io/math-and-transformations-for-opengl/</guid><description>&lt;h2 id="coordinate-spaces-systems-and-frames"&gt;Coordinate Spaces, Systems and Frames
&lt;/h2&gt;&lt;p&gt;Notice that so far, we&amp;rsquo;ve used points within the range $[-1,1]$ on all axes. Also, recall that our vertex shader did not do any transformations, and directly output the values we set via a VBO. For a vertex to be visible on the screen in OpenGL, it must be in &lt;strong&gt;Normalized Device Coordinates (NDC)&lt;/strong&gt; after it is processed. NDC is a space where all coordinates are normalized to $[-1,1]^3$. These numbers, however, are merely percentages that need to be transformed to a coordinate frame, e.g., screen coordinates, to represent actual positions. Before we go any further, it&amp;rsquo;s important to define the terms &amp;ldquo;space&amp;rdquo;, &amp;ldquo;system&amp;rdquo; and &amp;ldquo;frame&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;geometric space&lt;/strong&gt; is an abstract framework that defines the geometric rules (axioms), e.g., how to measure distances or angles, or how lines behave, to represent physical space. A &lt;strong&gt;Euclidean&lt;/strong&gt; space is one such space where Euclidean geometry rules apply; for example, distances are calculated using the &lt;a class="link" href="https://en.wikipedia.org/wiki/Euclidean_distance" target="_blank" rel="noopener"
 &gt;Euclidean distance&lt;/a&gt; formula. A &lt;strong&gt;coordinate system&lt;/strong&gt; describes how to uniquely specify each point in a space. A &lt;strong&gt;Cartesian&lt;/strong&gt; coordinate system specifies points using real numbers called &lt;strong&gt;coordinates&lt;/strong&gt;, which are the signed distances from perpendicular oriented lines called coordinate lines or axes. The point where these axes meet is called the &lt;strong&gt;origin&lt;/strong&gt;. The direction vectors that represent these axes (e.g., $(1,0,0)$, $(0,1,0)$ and $(0,0,1)$) form an &lt;strong&gt;orthogonal basis&lt;/strong&gt;, meaning that they are mutually orthogonal, and any vector in this system can be represented as a finite linear combination of these basis vectors. A &lt;strong&gt;coordinate frame&lt;/strong&gt; is a specific instance of a coordinate system with a defined origin and basis. In computer graphics, a &lt;strong&gt;coordinate space&lt;/strong&gt; usually means a frame of reference in space (a coordinate frame).&lt;/p&gt;
&lt;p&gt;In graphics applications, some calculations can be done more efficiently and are more intuitive in certain coordinate spaces. We move a vector from one space to another by applying a &lt;strong&gt;transformation&lt;/strong&gt;. Before diving into transformations, it&amp;rsquo;s important to build a solid understanding of vectors and matrices.&lt;/p&gt;
&lt;h2 id="vector-operations"&gt;Vector Operations
&lt;/h2&gt;&lt;p&gt;A &lt;strong&gt;vector&lt;/strong&gt; ($\vec{v}$) is a 1D array of numerical components. It can be of size &lt;em&gt;n&lt;/em&gt;, which is the number of components the vector has. In computer graphics, we usually use vectors of size up to 4.&lt;/p&gt;
$$
\vec{a} =
\begin{bmatrix}
a_1 \\
a_2 \\
a_3
\end{bmatrix}
$$&lt;p&gt;A &lt;strong&gt;vector space&lt;/strong&gt; (&lt;em&gt;V&lt;/em&gt;) defines a set of axioms (e.g., commutativity, associativity, etc.), and a set of vector operations (e.g., addition, multiplication, etc.) over a field (e.g., real numbers ($\mathbb{R}$)) in algebraic terms. A Euclidean space satisfies all the axioms of a vector space over the real numbers.&lt;/p&gt;
&lt;p&gt;We can add or subtract a scalar (&lt;em&gt;c&lt;/em&gt;) to or from a vector, or multiply or divide a vector by a scalar by simply applying this operation to each component of the vector.&lt;/p&gt;
$$
c\vec{a} = c
\begin{bmatrix}
a_1 \\
a_2 \\
a_3
\end{bmatrix} =
\begin{bmatrix}
c \cdot a_1 \\
c \cdot a_2 \\
c \cdot a_3
\end{bmatrix}
$$&lt;p&gt;The &lt;strong&gt;length&lt;/strong&gt; (magnitude) of a vector is defined as the square root of the sum of the squares of its components.&lt;/p&gt;
$$
\|\vec{a}\| = \sqrt{a_1^2+a_2^2+a_3^2}
$$&lt;p&gt;A vector can be &lt;strong&gt;normalized&lt;/strong&gt; to obtain a &lt;strong&gt;unit vector&lt;/strong&gt; (a vector with a length of 1) by dividing its components by its length. Unit vectors are easy to work with when we only care about a vector&amp;rsquo;s direction.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Normalizing does not change a vector&amp;rsquo;s direction.&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\hat{a} =
\frac{\vec{a}}{\|\vec{a}\|} =
\frac{1}{\sqrt{a_1^2+a_2^2+a_3^2}}
\begin{bmatrix}
a_1 \\
a_2 \\
a_3
\end{bmatrix}
$$&lt;p&gt;Two vectors of the same size can be added or subtracted through component-wise addition or subtraction.&lt;/p&gt;
$$
\vec{a} + \vec{b} =
\begin{bmatrix}
a_1 \\
a_2 \\
a_3
\end{bmatrix} +
\begin{bmatrix}
b_1 \\
b_2 \\
b_3
\end{bmatrix} =
\begin{bmatrix}
a_1 + b_1 \\
a_2 + b_2 \\
a_3 + b_3
\end{bmatrix}
$$&lt;p&gt;GLSL defines vector-vector multiplication as component-wise multiplication. However, there are more useful and specialized forms of multiplication: dot and cross products.&lt;/p&gt;
&lt;h3 id="dot-product"&gt;Dot Product
&lt;/h3&gt;&lt;p&gt;In graphics applications, it&amp;rsquo;s important to know how much two vectors align, i.e., whether they&amp;rsquo;re parallel, perpendicular, or somewhere in between. &lt;strong&gt;Dot product&lt;/strong&gt; is the operation that tells us about this relationship. It can be calculated by summing the component-wise products. The same result can be obtained by multiplying the lengths of the two vectors and the cosine of the angle between them. The second method is more intuitive because this operation is defined, geometrically, as the length of one vector&amp;rsquo;s projection onto the other, multiplied by the other&amp;rsquo;s length. One can verify that the two equations are identical through the use of the &lt;a class="link" href="https://en.wikipedia.org/wiki/Law_of_cosines" target="_blank" rel="noopener"
 &gt;law of cosines&lt;/a&gt; on a triangle formed by the two vectors (making an angle $\theta$) and their difference vector connecting both.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;The result of a dot product is a scalar (not a vector).&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\vec{a} \cdot \vec{b} =
\begin{bmatrix}
a_1 \\
a_2 \\
a_3
\end{bmatrix} \cdot
\begin{bmatrix}
b_1 \\
b_2 \\
b_3
\end{bmatrix} = a_1b_1 + a_2b_2 + a_3b_3 = \|\vec{a}\| \|\vec{b}\| \cos{\theta}
$$
 &lt;blockquote&gt;
 &lt;p&gt;If two vectors are perpendicular, their dot product is zero ($\cos{90^\circ} = 0$).&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Dot product is commutative, that is, $\vec{a}\cdot\vec{b}$ is equal to $\vec{b}\cdot\vec{a}$.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;A geometric space, e.g., a Euclidean space, is a vector space plus an inner product that defines lengths of vectors, angles between vectors, or orthogonality. An &lt;strong&gt;inner product&lt;/strong&gt;, e.g., the dot product, is an operation that takes two vectors and produces a single scalar in a way that encodes geometric meaning — it lets us talk about lengths, angles, and orthogonality inside a vector space.&lt;/p&gt;
&lt;h3 id="cross-product"&gt;Cross Product
&lt;/h3&gt;&lt;p&gt;This operation takes two non-parallel vectors as input and outputs a vector that is orthogonal to both inputs. It will prove useful in future chapters.&lt;/p&gt;
$$
\vec{a} \times \vec{b} =
\begin{bmatrix}
a_1 \\
a_2 \\
a_3
\end{bmatrix} \times
\begin{bmatrix}
b_1 \\
b_2 \\
b_3
\end{bmatrix} =
\begin{bmatrix}
a_2b_3 - a_3b_2 \\
a_3b_1 - a_1b_3 \\
a_1b_2 - a_2b_1
\end{bmatrix}
$$&lt;h2 id="matrix-operations"&gt;Matrix Operations
&lt;/h2&gt;&lt;p&gt;A &lt;strong&gt;matrix&lt;/strong&gt; (&lt;em&gt;M&lt;/em&gt;) is a 2D array of elements, where each element is identified by its row and column indices. If a matrix has &lt;em&gt;m&lt;/em&gt; rows and &lt;em&gt;n&lt;/em&gt; columns, it&amp;rsquo;s an &lt;em&gt;mxn&lt;/em&gt; matrix, and these are called the matrix dimensions.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;If both dimensions are the same, then the matrix is called a &lt;strong&gt;square matrix&lt;/strong&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;A matrix-scalar product multiplies each element of the matrix by a scalar. Addition and subtraction can be done element-wise if both matrices have the same dimensions.&lt;/p&gt;
$$
A + B =
\begin{bmatrix}
1 &amp; 2 \\
3 &amp; 4
\end{bmatrix} +
\begin{bmatrix}
5 &amp; 6 \\
7 &amp; 8
\end{bmatrix} =
\begin{bmatrix}
1 + 5 &amp; 2 + 6 \\
3 + 7 &amp; 4 + 8
\end{bmatrix} =
\begin{bmatrix}
6 &amp; 8 \\
10 &amp; 12
\end{bmatrix}
$$&lt;p&gt;Two matrices, &lt;em&gt;A&lt;/em&gt; and &lt;em&gt;B&lt;/em&gt;, can be multiplied (in this order) if the number of columns in &lt;em&gt;A&lt;/em&gt; is equal to the number of rows in &lt;em&gt;B&lt;/em&gt;. Every element in a row of &lt;em&gt;A&lt;/em&gt; is multiplied by the corresponding element in a column of &lt;em&gt;B&lt;/em&gt;. Then, these products are summed up to obtain one element in the resulting matrix &lt;em&gt;C&lt;/em&gt;. The result obtained from processing row &lt;em&gt;i&lt;/em&gt; of &lt;em&gt;A&lt;/em&gt; and column &lt;em&gt;j&lt;/em&gt; of &lt;em&gt;B&lt;/em&gt; will end up in the $i^{th}$ row and $j^{th}$ column of &lt;em&gt;C&lt;/em&gt;. This implies that the resulting matrix has the same number of rows as &lt;em&gt;A&lt;/em&gt; and the same number of columns as &lt;em&gt;B&lt;/em&gt;.&lt;/p&gt;
$$
AB =
\begin{bmatrix}
1 &amp; 2 \\
3 &amp; 4
\end{bmatrix}
\begin{bmatrix}
5 &amp; 6 \\
7 &amp; 8
\end{bmatrix} =
\begin{bmatrix}
1 \cdot 5 + 2 \cdot 7 &amp; 1 \cdot 6 + 2 \cdot 8 \\
3 \cdot 5 + 4 \cdot 7 &amp; 3 \cdot 6 + 4 \cdot 8
\end{bmatrix} \\
= \begin{bmatrix}
5 + 14 &amp; 6 + 16 \\
15 + 28 &amp; 18 + 32
\end{bmatrix} =
\begin{bmatrix}
19 &amp; 22 \\
43 &amp; 50
\end{bmatrix}
$$
 &lt;blockquote&gt;
 &lt;p&gt;Matrix multiplication is not commutative, that is, &lt;em&gt;AB&lt;/em&gt; is not the same as &lt;em&gt;BA&lt;/em&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
$$
BA =
\begin{bmatrix}
5 &amp; 6 \\
7 &amp; 8
\end{bmatrix}
\begin{bmatrix}
1 &amp; 2 \\
3 &amp; 4
\end{bmatrix} =
\begin{bmatrix}
5 \cdot 1 + 6 \cdot 3 &amp; 5 \cdot 2 + 6 \cdot 4 \\
7 \cdot 1 + 8 \cdot 3 &amp; 7 \cdot 2 + 8 \cdot 4
\end{bmatrix} \\
= \begin{bmatrix}
5 + 18 &amp; 10 + 24 \\
7 + 24 &amp; 14 + 32
\end{bmatrix} =
\begin{bmatrix}
23 &amp; 34 \\
31 &amp; 46
\end{bmatrix}
$$&lt;p&gt;When a matrix is &lt;strong&gt;transposed&lt;/strong&gt;, its rows become its columns and vice versa. If &lt;em&gt;M&lt;/em&gt; has the dimensions &lt;em&gt;mxn&lt;/em&gt;, $M^T$ (transpose of &lt;em&gt;M&lt;/em&gt;) has a dimension of &lt;em&gt;nxm&lt;/em&gt;.&lt;/p&gt;
$$
A^T =
\begin{bmatrix}
1 &amp; 3 \\
2 &amp; 4
\end{bmatrix},
B^T =
\begin{bmatrix}
5 &amp; 7 \\
6 &amp; 8
\end{bmatrix}
$$&lt;p&gt;The transpose of a product is equal to the product of the transposes in &lt;strong&gt;reverse&lt;/strong&gt; order.&lt;/p&gt;
$$
(AB)^T =
B^TA^T =
\begin{bmatrix}
5 &amp; 7 \\
6 &amp; 8
\end{bmatrix}
\begin{bmatrix}
1 &amp; 3 \\
2 &amp; 4
\end{bmatrix} =
\begin{bmatrix}
5 \cdot 1 + 7 \cdot 2 &amp; 5 \cdot 3 + 7 \cdot 4 \\
6 \cdot 1 + 8 \cdot 2 &amp; 6 \cdot 3 + 8 \cdot 4
\end{bmatrix} \\
= \begin{bmatrix}
5 + 14 &amp; 15 + 28 \\
6 + 16 &amp; 18 + 32
\end{bmatrix} =
\begin{bmatrix}
19 &amp; 43 \\
22 &amp; 50
\end{bmatrix}
$$&lt;h2 id="transformations"&gt;Transformations
&lt;/h2&gt;&lt;p&gt;A vector is basically an &lt;em&gt;nx1&lt;/em&gt; matrix, if represented as a &lt;strong&gt;column vector&lt;/strong&gt; (i.e., components appear in the same column); hence, it can be multiplied by an &lt;em&gt;mxn&lt;/em&gt; matrix ($M\vec{v}$). Through matrix multiplication, a vector can be transformed into another vector. We use matrices for transforming vectors, because they allow us to combine multiple transformations into a single matrix, which we&amp;rsquo;ll see later on.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;GPUs are very good at multiplying thousands of matrices in parallel.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;An &lt;strong&gt;identity matrix&lt;/strong&gt; is an &lt;em&gt;nxn&lt;/em&gt; matrix that has &lt;em&gt;1s&lt;/em&gt; on its &lt;strong&gt;main diagonal&lt;/strong&gt; (from top-left to bottom-right) and &lt;em&gt;0s&lt;/em&gt; elsewhere. When you multiply any compatible matrix or vector with it, you get the original matrix or vector back. So, it&amp;rsquo;s essentially a &lt;strong&gt;no transform&lt;/strong&gt;.&lt;/p&gt;
$$
IA = \begin{bmatrix}
1 &amp; 0 \\
0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 2 \\
3 &amp; 4
\end{bmatrix} =
\begin{bmatrix}
1 \cdot 1 + 0 \cdot 3 &amp; 1 \cdot 2 + 0 \cdot 4 \\
0 \cdot 1 + 1 \cdot 3 &amp; 0 \cdot 2 + 1 \cdot 4
\end{bmatrix} =
\begin{bmatrix}
1 &amp; 2 \\
3 &amp; 4
\end{bmatrix}
$$
 &lt;blockquote&gt;
 &lt;p&gt;A &lt;strong&gt;diagonal matrix&lt;/strong&gt; has non-zero entries only along its main diagonal.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="scaling"&gt;Scaling
&lt;/h3&gt;&lt;p&gt;We can change the length (and direction) of a vector by scaling it. This is achieved by multiplying individual components by a scalar. If the same scalar is used for all components, it is a &lt;strong&gt;uniform&lt;/strong&gt; scale operation; otherwise, it&amp;rsquo;s called a &lt;strong&gt;non-uniform&lt;/strong&gt; scale.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A positive uniform scale operation does not change a vector&amp;rsquo;s direction. If it&amp;rsquo;s negative, then the vector points the opposite way.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We would like to form a scale matrix (&lt;em&gt;S&lt;/em&gt;) so that the scaling operation could be represented as a matrix-vector multiplication. To obtain that matrix, let&amp;rsquo;s first write a set of equations that describes scaling for a vector in a Euclidean space defined by Cartesian coordinates:&lt;/p&gt;
$$
x' = S_x \cdot x \\
y' = S_y \cdot y \\
z' = S_z \cdot z
$$&lt;p&gt;Since there are 3 equations, there should be 3 rows in the scale matrix to store the coefficients for each equation. Also, since a 3D vector is a &lt;em&gt;3x1&lt;/em&gt; matrix, our matrix needs to have 3 columns to be compatible. So, this will be a &lt;em&gt;3x3&lt;/em&gt; matrix. Let&amp;rsquo;s rewrite the equations so that each one has 3 coefficients (columns):&lt;/p&gt;
$$
x' = S_x \cdot x + 0 \cdot y + 0 \cdot z \\
y' = 0 \cdot x + S_y \cdot y + 0 \cdot z \\
z' = 0 \cdot x + 0 \cdot y + S_z \cdot z
$$&lt;p&gt;We want to scale each axis independently; hence, we want no contribution from other axes. For this purpose, we set the coefficients of other components to 0. In this type of scenario, we obtain a diagonal matrix. These equations can be written in matrix form as follows:&lt;/p&gt;
$$
\begin{bmatrix}
x' \\
y' \\
z'
\end{bmatrix} =
\begin{bmatrix}
S_x &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 \\
0 &amp; 0 &amp; S_z
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}
$$&lt;h3 id="translation"&gt;Translation
&lt;/h3&gt;&lt;p&gt;We can move (translate) a vector by adding another vector to it. Similar to scaling, we would love to represent this too as a matrix multiplication, which will help us combine both matrices into one. Again, let&amp;rsquo;s start by writing a set of equations that translate a vector:&lt;/p&gt;
$$
x' = x + T_x \\
y' = y + T_y \\
z' = z + T_z
$$&lt;p&gt;Wait&amp;hellip; can we obtain $x+T_x$ through matrix multiplication? This seems impossible&amp;hellip; and it is, in the same dimensional space. The reason is that matrix multiplication is a &lt;strong&gt;linear transformation&lt;/strong&gt;; but, translation is an &lt;strong&gt;affine transformation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A transformation (&lt;em&gt;L&lt;/em&gt;) is &lt;strong&gt;linear&lt;/strong&gt; if it satisfies the following condition, where &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt; are scalars:&lt;/p&gt;
$$
L(a\vec{u} + b\vec{v}) = aL(\vec{u}) + bL(\vec{v})
$$&lt;p&gt;An &lt;strong&gt;affine&lt;/strong&gt; transformation (&lt;em&gt;A&lt;/em&gt;) has the following form, where &lt;em&gt;L&lt;/em&gt; is the linear part, and $\vec{c}$ is a constant vector (e.g., translation vector):&lt;/p&gt;
$$
A(\vec{u}) = L\vec{u} + \vec{c}
$$&lt;p&gt;This is not linear because:&lt;/p&gt;
$$
A(\vec{u} + \vec{v}) = L(\vec{u} + \vec{v}) + \vec{c} \neq A(\vec{u}) + A(\vec{v}) = L(\vec{u}) + \vec{c} + L(\vec{v}) + \vec{c}
$$&lt;p&gt;There is, however, an augmentation technique we can use to obtain a translation matrix. But first, let&amp;rsquo;s expand the equations to include all the components, which must have a corresponding coefficient in each row of this matrix. It&amp;rsquo;s obvious that these coefficients should be 0. On the other hand, translation amounts must be preserved; hence, they are multiplied by 1.&lt;/p&gt;
$$
x' = 1 \cdot x + 0 \cdot y + 0 \cdot z + T_x \cdot 1 \\
y' = 0 \cdot x + 1 \cdot y + 0 \cdot z + T_y \cdot 1 \\
z' = 0 \cdot x + 0 \cdot y + 1 \cdot z + T_z \cdot 1
$$&lt;p&gt;It looks like our vector is not $(x,y,z)$ anymore, but rather $(x,y,z,1)$. Similarly, each row appears to have one more coefficient that is the translation amount. Let&amp;rsquo;s try to convert this to a matrix multiplication using the available information:&lt;/p&gt;
$$
\begin{bmatrix}
x' \\
y' \\
z'
\end{bmatrix} =
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; T_x \\
0 &amp; 1 &amp; 0 &amp; T_y \\
0 &amp; 0 &amp; 1 &amp; T_z
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$&lt;p&gt;This operation is valid because the translation matrix (&lt;em&gt;T&lt;/em&gt;) has a dimension of &lt;em&gt;3x4&lt;/em&gt; and it is multiplied by a &lt;em&gt;4x1&lt;/em&gt; vector, and the resulting vector is of size &lt;em&gt;3x1&lt;/em&gt;. More importantly, it gives the correct result. So, we&amp;rsquo;ve finally obtained a translation matrix by introducing a new dimension.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;When a 3D point is represented in a 4D projective space, the new coordinate system is referred to as &lt;strong&gt;homogenous coordinates&lt;/strong&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;There is a problem though. The &lt;em&gt;w&lt;/em&gt; component we added to our original vector makes it impossible to perform multiplications with our scale matrix since the dimensions &lt;em&gt;3x3&lt;/em&gt; and &lt;em&gt;4x1&lt;/em&gt; are not compatible ($3\neq 4$). As a workaround, we could add one extra column of &lt;em&gt;0s&lt;/em&gt; to our scale matrix:&lt;/p&gt;
$$
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} =
\begin{bmatrix}
S_x \cdot x \\
S_y \cdot y \\
S_z \cdot z
\end{bmatrix}
$$&lt;p&gt;This seems to work, but we do not just perform one transformation on a vector and call it a day; it&amp;rsquo;s often necessary to apply a series of transformations to the same vector. Let&amp;rsquo;s say we intend to apply a translation next, can we do it? Notice that we no longer have a &lt;em&gt;4x1&lt;/em&gt; vector; we have lost the &lt;em&gt;w&lt;/em&gt; component, which makes it impossible to perform this operation. It&amp;rsquo;s clear that we have to preserve the 4D representation while operating on the vector.&lt;/p&gt;
&lt;p&gt;What dimensions does the scale matrix need to have to produce a &lt;em&gt;4x1&lt;/em&gt; vector when multiplied by a &lt;em&gt;4x1&lt;/em&gt; vector? Yes, the answer is &lt;em&gt;4x4&lt;/em&gt;. But, what values should we have in this new row? The &lt;em&gt;w&lt;/em&gt; component of the result must be 1, which suggests $(0,0,0,1)$.&lt;/p&gt;
$$
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} =
\begin{bmatrix}
S_x \cdot x \\
S_y \cdot y \\
S_z \cdot z \\
1
\end{bmatrix}
$$&lt;p&gt;Now, let&amp;rsquo;s try to apply scaling followed by translation. When using column vectors, this chain of operations is written left to right, but performed right to left. It follows the &lt;strong&gt;nested functions&lt;/strong&gt; analogy: $f(g(h(x))) = (f \circ g \circ h)(x)$.&lt;/p&gt;
$$
TS\vec{v} =
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; T_x \\
0 &amp; 1 &amp; 0 &amp; T_y \\
0 &amp; 0 &amp; 1 &amp; T_z \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} \\
= \begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; T_x \\
0 &amp; 1 &amp; 0 &amp; T_y \\
0 &amp; 0 &amp; 1 &amp; T_z \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
S_x \cdot x \\
S_y \cdot y \\
S_z \cdot z \\
1
\end{bmatrix} =
\begin{bmatrix}
S_x \cdot x + T_x \\
S_y \cdot y + T_y \\
S_z \cdot z + T_z \\
1
\end{bmatrix}
$$&lt;p&gt;Matrix multiplication is &lt;strong&gt;associative&lt;/strong&gt;, that is, $(AB)C = A(BC)$; hence, we are free to combine any adjacent pair without changing the order. This allows us to collapse the entire transformation chain into one matrix. Let&amp;rsquo;s combine the translation and scale matrices:&lt;/p&gt;
$$
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; T_x \\
0 &amp; 1 &amp; 0 &amp; T_y \\
0 &amp; 0 &amp; 1 &amp; T_z \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} =
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; T_x \\
0 &amp; S_y &amp; 0 &amp; T_y \\
0 &amp; 0 &amp; S_z &amp; T_z \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$
 &lt;blockquote&gt;
 &lt;p&gt;Being able to represent a sequence of transformations as a single matrix can save precious GPU resources.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;If the vector was represented as a row vector, then the multiplication would be done left to right in reverse order, i.e., we would take the transpose of the transformation chain: $(TS\vec{v})^T=\vec{v}^TS^TT^T$. Notice that the vector dimensions become &lt;em&gt;1x4&lt;/em&gt;, and the transform matrices are of size &lt;em&gt;4x4&lt;/em&gt;, which explains the need to reverse the order to make them compatible for multiplication.&lt;/p&gt;
$$
\begin{bmatrix}
x &amp; y &amp; z &amp; 1
\end{bmatrix}
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; 1 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
T_x &amp; T_y &amp; T_z &amp; 1
\end{bmatrix} \\
= \begin{bmatrix}
x &amp; y &amp; z &amp; 1
\end{bmatrix}
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0 \\
T_x &amp; T_y &amp; T_z &amp; 1
\end{bmatrix}
$$&lt;h3 id="rotation"&gt;Rotation
&lt;/h3&gt;&lt;p&gt;One way to represent rotations is by using three separate rotations around coordinate axes, applied in a specific sequence. For example, we first rotate around &lt;em&gt;x&lt;/em&gt; by $\alpha$, then around &lt;em&gt;y&lt;/em&gt; by $\beta$, and finally around &lt;em&gt;z&lt;/em&gt; by $\gamma$. These are called &lt;strong&gt;Euler angles&lt;/strong&gt;. In different industries, these rotations might have different names; for example, in avionics, rotations around &lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt; and &lt;em&gt;z&lt;/em&gt; are called &lt;strong&gt;pitch&lt;/strong&gt;, &lt;strong&gt;yaw&lt;/strong&gt; and &lt;strong&gt;roll&lt;/strong&gt;, respectively, given that &lt;em&gt;y&lt;/em&gt; is up. The following are the most common rotation matrices, derived for the right-handed basis &lt;a class="link" href="https://en.wikipedia.org/wiki/Orientation_%28vector_space%29" target="_blank" rel="noopener"
 &gt;orientation&lt;/a&gt;.&lt;/p&gt;
$$
R_z R_y R_x =
\begin{bmatrix}
\cos{\gamma} &amp; -\sin{\gamma} &amp; 0 &amp; 0\\
\sin{\gamma} &amp; \cos{\gamma} &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
\cos{\beta} &amp; 0 &amp; \sin{\beta} &amp; 0\\
0 &amp; 1 &amp; 0 &amp; 0 \\
-\sin{\beta} &amp; 0 &amp; \cos{\beta} &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 0\\
0 &amp; \cos{\alpha} &amp; -\sin{\alpha} &amp; 0 \\
0 &amp; \sin{\alpha} &amp; \cos{\alpha} &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$&lt;p&gt;This representation is easy to understand and visualize, but it&amp;rsquo;s not perfect. Before we point out the issues, let&amp;rsquo;s make some observations. The first thing to notice is that a rotation around a certain axis preserves the coordinates on that axis (through multiplication by 1), which is expected. Another thing to notice is that the order matters due to the non-commutative nature of matrix multiplication, but in what order should we apply these rotations?&lt;/p&gt;
&lt;p&gt;An important thing to know is that there are two types of rotations: intrinsic and extrinsic. These describe the frame of reference you&amp;rsquo;re rotating about, which completely changes how the same sequence of angles plays out. With &lt;strong&gt;intrinsic rotations&lt;/strong&gt;, the object is rotated about its local frame, which means that each rotation causes the local coordinate axes to move; the next rotation in the sequence happens relative to the new orientation. On the other hand, &lt;strong&gt;extrinsic rotations&lt;/strong&gt; are about a fixed frame, e.g., world frame, or the parent object&amp;rsquo;s frame.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;When we talk about rotations, we usually mean intrinsic rotations.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;The problems associated with the representation above is not clear at first glance. To give you a clue, the first axis (rightmost in the matrix multiplication, outermost in a three-gimbal mechanism) can spin freely as it&amp;rsquo;s fixed in the world frame, the middle one is orthogonal to both the first and the last by definition, but there is a chance for the first and last to align when the middle axis is at its extremes (e.g., at 90 degrees). When two axes align, rotations around both will have the same effect; hence, we lose one degree of freedom, which is called &lt;strong&gt;gimbal lock&lt;/strong&gt;. Changing the multiplication order does not prevent this from happening, it just changes the pair that gets aligned.&lt;/p&gt;
&lt;p&gt;To avoid gimbal lock, we could limit the movement of the middle axis, and in some cases, we could get away with it. For example, in an FPS game, players rarely look up to the sky or down to the ground, and it won&amp;rsquo;t bother them when the rotation hits its limitations as it would also be physically impossible for a human&amp;rsquo;s head to move beyond those angles. However, this is not a fix, just a mitigation. To eliminate the possibility of a gimbal lock altogether, modern graphics applications represent rotations using &lt;a class="link" href="https://en.wikipedia.org/wiki/Quaternion" target="_blank" rel="noopener"
 &gt;quaternions&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="algebraic-explanation-of-gimbal-lock"&gt;Algebraic Explanation of Gimbal Lock
&lt;/h4&gt;&lt;p&gt;Let&amp;rsquo;s say we have rotated around the &lt;em&gt;y&lt;/em&gt;-axis by ${90^\circ}$, then the transformation becomes:&lt;/p&gt;
$$
\begin{bmatrix}
\cos{\gamma} &amp; -\sin{\gamma} &amp; 0 &amp; 0\\
\sin{\gamma} &amp; \cos{\gamma} &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
0 &amp; 0 &amp; 1 &amp; 0\\
0 &amp; 1 &amp; 0 &amp; 0 \\
-1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 0\\
0 &amp; \cos{\alpha} &amp; -\sin{\alpha} &amp; 0 \\
0 &amp; \sin{\alpha} &amp; \cos{\alpha} &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$$$
\begin{bmatrix}
\cos{\gamma} &amp; -\sin{\gamma} &amp; 0 &amp; 0\\
\sin{\gamma} &amp; \cos{\gamma} &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
0 &amp; \sin{\alpha} &amp; \cos{\alpha} &amp; 0\\
0 &amp; \cos{\alpha} &amp; -\sin{\alpha} &amp; 0 \\
-1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$$$
\begin{bmatrix}
0 &amp; \cos{\gamma}\sin{\alpha} - \sin{\gamma}\cos{\alpha} &amp; \cos{\gamma}\cos{\alpha} + \sin{\gamma}\sin{\alpha} &amp; 0 \\
0 &amp; \sin{\gamma}\sin{\alpha} + \cos{\gamma}\cos{\alpha} &amp; \sin{\gamma}\cos{\alpha} - \cos{\gamma}\sin{\alpha} &amp; 0 \\
-1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$&lt;p&gt;Using trigonometric identities, e.g., $\cos{\gamma}\sin{\alpha} - \sin{\gamma}\cos{\alpha} = \sin{(\alpha-\gamma)}$, we can rewrite this matrix as:&lt;/p&gt;
$$
\begin{bmatrix}
0 &amp; \sin{(\alpha-\gamma)} &amp; \cos{(\alpha-\gamma)} &amp; 0 \\
0 &amp; \cos{(\alpha-\gamma)} &amp; -\sin{(\alpha-\gamma)} &amp; 0 \\
-1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$&lt;p&gt;Notice that the final rotation matrix only depends on the difference $\alpha-\gamma$, not on $\alpha$ and $\gamma$ individually; they&amp;rsquo;re now coupled. Substituting $\theta$ for $\alpha-\gamma$, we can see that we now have two degrees of freedom, $\beta$ and $\theta$, one less compared to before: $\alpha$, $\beta$, $\gamma$.&lt;/p&gt;
&lt;h3 id="transformation-order"&gt;Transformation Order
&lt;/h3&gt;&lt;p&gt;In a matrix-based system, the order matters because the multiplication operation is not commutative. When deciding on an order, we must consider in what space each operation should happen. There is no right or wrong answer — it all depends on what result we want to achieve at the end. Let&amp;rsquo;s analyze $TS\vec{v}$, which we derived before, in reverse order ($ST\vec{v}$).&lt;/p&gt;
$$
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; S_y &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; S_z &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; T_x \\
0 &amp; 1 &amp; 0 &amp; T_y \\
0 &amp; 0 &amp; 1 &amp; T_z \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix} =
\begin{bmatrix}
S_x &amp; 0 &amp; 0 &amp; S_x \cdot T_x \\
0 &amp; S_y &amp; 0 &amp; S_y \cdot T_y \\
0 &amp; 0 &amp; S_z &amp; S_z \cdot T_z \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$&lt;p&gt;As you can see, if translation is applied first, then the translation vector is scaled as well. If it was rotation that followed translation, then the object would be rotated about a shifted origin, which would result in an arc shaped movement. If scale follows rotation, then it&amp;rsquo;s applied with respect to the new orientation, which would make even a uniform scale look non-uniform. In many applications, we want to scale first, then rotate, and finally translate: $TRS\vec{v}$.&lt;/p&gt;
&lt;h2 id="glm"&gt;GLM
&lt;/h2&gt;&lt;p&gt;In graphics applications, it&amp;rsquo;s common, and often necessary, to perform matrix operations on the CPU. For example, in a game engine, object hierarchies are stored in CPU memory, and the transforms need to be re-calculated only when an object&amp;rsquo;s local transform or a parent transform changes, which can be done more efficiently on the CPU. The &lt;strong&gt;OpenGL Mathematics Library (GLM)&lt;/strong&gt; is a header-only C++ math library that provides a large set of classes and functions that follow the same naming conventions and functionality as GLSL. It can be added to a CMake project as we did with GLFW.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule add https://github.com/g-truc/glm /external/glm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmake" data-lang="cmake"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;add_subdirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;${CMAKE_CURRENT_SOURCE_DIR}/external/glm&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;${PROJECT_NAME}&amp;#34;&lt;/span&gt; &lt;span class="s"&gt;PUBLIC&lt;/span&gt; &lt;span class="s"&gt;glm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Now, we can include the required GLM headers and define the transformation matrices. We usually start with a unit matrix, and call either one of &lt;code&gt;glm::rotate&lt;/code&gt;, &lt;code&gt;glm::scale&lt;/code&gt; or &lt;code&gt;glm::translate&lt;/code&gt;, to obtain a combined matrix. Since GLM, like OpenGL, represents matrices in &lt;strong&gt;column-major&lt;/strong&gt; order, we place the first transformation to apply at the end in the multiplication.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;glm/glm.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;glm/gtc/matrix_transform.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;glm/gtc/type_ptr.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// vertex specification &amp;amp; shader creation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mat4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// a uniform scale of .5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// rotate 90 degrees around the z-axis
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;radians&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;90.0f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0f&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// translate by (.3, .2, .1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.3f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1f&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// construct the transform matrix
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;A transformation is typically defined per object — it applies to all vertices of that object. When a draw call (e.g., &lt;code&gt;glDrawArrays&lt;/code&gt;) is issued, GPU launches many shader invocations in parallel — one per vertex, fragment, etc. GLSL defines per-draw, read-only constants called &lt;strong&gt;uniforms&lt;/strong&gt; that are stored in a dedicated, broadcast-friendly area in GPU memory. Every thread can access these uniforms at no additional cost.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Uniform variables are global to the program object; if both vertex and fragment shaders define the same uniform, the linker treats them as referring to the same data.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;In our vertex shader, we can define a uniform of type &lt;code&gt;mat4&lt;/code&gt; for the transform matrix. Then, we multiply the position vector with this matrix to obtain a final position. Notice that we represent the position in homogenous coordinates so that it&amp;rsquo;s compatible with the matrix, and the &lt;em&gt;w&lt;/em&gt; component is &lt;code&gt;1.0&lt;/code&gt; since this is a position vector.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-glsl" data-lang="glsl"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#version 330 core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mo"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;vec3&lt;/span&gt; &lt;span class="n"&gt;i_pos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;uniform&lt;/span&gt; &lt;span class="n"&gt;mat4&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gl_Position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;vec4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i_pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;To send the transform matrix to the shader, we first need to query its location via &lt;code&gt;glGetUniformLocation&lt;/code&gt;. It&amp;rsquo;s advised to cache this location for later use since every communication with the graphics driver adds some latency. Then, we can send the transform data by calling &lt;code&gt;glUniformMatrix4fv&lt;/code&gt; with the following arguments: location, the number of matrices to set, whether to transpose the matrix, and a pointer to the matrix data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;glUseProgram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shaderProgram&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;GLuint&lt;/span&gt; &lt;span class="n"&gt;transformLoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glGetUniformLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shaderProgram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;transform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;glUniformMatrix4fv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transformLoc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GL_FALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;value_ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item></channel></rss>