How Does GLSL Evaluate Matrix-Vector Multiplication?
In the OpenGL Shading Language (GLSL), matrix-vector multiplication
is evaluated using standard linear algebra rules, with the mathematical
behavior determined by whether the vector appears on the right or left
side of the operator. GLSL treats vectors on the right
(M * v) as column vectors and vectors on the left
(v * M) as row vectors. Internally, matrices are structured
around column vectors, meaning evaluation translates directly into
either linear combinations of matrix columns or dot products against
matrix rows and columns.
Matrix Layout and Indexing in GLSL
Before evaluating arithmetic operations, it is necessary to understand how matrices are indexed in GLSL. GLSL matrices use column-major notation:
- In a matrix type
matC, ormatCxR, \(C\) represents the number of columns and \(R\) represents the number of rows. - Accessing
M[j]accesses the \(j\)-th column vector. - Accessing
M[j][i]accesses the component at column \(j\), row \(i\).
Consider a standard \(4 \times 4\) matrix \(M\):
\[M = \begin{bmatrix} m_{00} & m_{10} & m_{20} & m_{30} \\ m_{01} & m_{11} & m_{21} & m_{31} \\ m_{02} & m_{12} & m_{22} & m_{32} \\ m_{03} & m_{13} & m_{23} & m_{33} \end{bmatrix} = \begin{bmatrix} \mathbf{c}_0 & \mathbf{c}_1 & \mathbf{c}_2 & \mathbf{c}_3 \end{bmatrix}\]
Here, each \(\mathbf{c}_j\)
corresponds directly to the vector stored at M[j].
Matrix Times Vector:
M * v
When multiplying a matrix by a vector on the right, GLSL treats the vector \(\mathbf{v}\) as a column vector (\(4 \times 1\)). The operation produces a new column vector \(\mathbf{u}\):
\[\mathbf{u} = M \mathbf{v}\]
Component-Wise Evaluation
Mathematically, each row of the matrix computes a standard dot product with the vector \(\mathbf{v}\):
\[u_0 = m_{00} v_x + m_{10} v_y + m_{20} v_z + m_{30} v_w\]
\[u_1 = m_{01} v_x + m_{11} v_y + m_{21} v_z + m_{31} v_w\]
\[u_2 = m_{02} v_x + m_{12} v_y + m_{22} v_z + m_{32} v_w\]
\[u_3 = m_{03} v_x + m_{13} v_y + m_{23} v_z + m_{33} v_w\]
Linear Combination Interpretation
Because GLSL internally organizes matrices by columns, the operation can also be evaluated as a linear combination of the matrix’s column vectors scaled by the components of \(\mathbf{v}\):
\[\mathbf{u} = v_x \mathbf{c}_0 + v_y \mathbf{c}_1 + v_z \mathbf{c}_2 + v_w \mathbf{c}_3\]
In GLSL code, evaluating vec4 u = M * v; is
mathematically equivalent to:
vec4 u = v.x * M[0] + v.y * M[1] + v.z * M[2] + v.w * M[3];Vector Times Matrix:
v * M
When the vector is placed on the left side of the operator, GLSL treats the vector as a row vector (\(1 \times 4\)):
\[\mathbf{u}^T = \mathbf{v}^T M\]
Component-Wise Evaluation
In this form, each component of the resulting row vector is evaluated as the dot product between the input vector \(\mathbf{v}\) and the corresponding column vector of \(M\):
\[u_0 = \mathbf{v} \cdot \mathbf{c}_0 = v_x m_{00} + v_y m_{01} + v_z m_{02} + v_w m_{03}\]
\[u_1 = \mathbf{v} \cdot \mathbf{c}_1 = v_x m_{10} + v_y m_{11} + v_z m_{12} + v_w m_{13}\]
\[u_2 = \mathbf{v} \cdot \mathbf{c}_2 = v_x m_{20} + v_y m_{21} + v_z m_{22} + v_w m_{23}\]
\[u_3 = \mathbf{v} \cdot \mathbf{c}_3 = v_x m_{30} + v_y m_{31} + v_z m_{32} + v_w m_{33}\]
In GLSL code, vec4 u = v * M; is mathematically
equivalent to:
vec4 u = vec4(dot(v, M[0]), dot(v, M[1]), dot(v, M[2]), dot(v, M[3]));Dimension Matching for Non-Square Matrices
For non-square matrices (matCxR), matrix-vector
multiplications enforce strict dimension rules:
matCxR * vecC: Multiplying a matrix with \(C\) columns and \(R\) rows on the right by a vector of length \(C\) evaluates to a vector of length \(R\).vecR * matCxR: Multiplying a vector of length \(R\) on the left by a matrix with \(C\) columns and \(R\) rows evaluates to a vector of length \(C\).