How GLSL outerProduct Calculates Matrices
The outerProduct function in the OpenGL Shading Language
(GLSL) creates a matrix from two vectors by computing their outer, or
tensor, product. This article explains the underlying mathematical
mechanics of the function, how vector dimensions determine the resulting
matrix size in GLSL, and how the calculation maps directly to GLSL's
column-major matrix structure.
Mathematical Principle
The outer product between a column vector \(\mathbf{c}\) of length \(M\) and a row vector \(\mathbf{r}\) of length \(N\) yields an \(M \times N\) matrix (\(M\) rows, \(N\) columns). Every element \(A_{ij}\) at row \(i\) and column \(j\) in the resulting matrix is calculated by multiplying the \(i\)-th component of the first vector by the \(j\)-th component of the second vector:
\[A_{ij} = c_i \cdot r_j\]
Unlike the dot product (dot()), which multiplies two
vectors of the same dimension to produce a single scalar value, the
outer product expands two vectors into a full transformation matrix.
GLSL Dimensional Mapping
GLSL matrices follow a mat<columns>x<rows>
naming convention, and matrices are stored in column-major order. The
outerProduct function signature reflects this
relationship:
matNxM outerProduct(vecM c, vecN r);- The first parameter
cdefines the number of rows (\(M\)). - The second parameter
rdefines the number of columns (\(N\)). - The return type is a matrix with \(N\) columns and \(M\) rows (
matNxM).
For example, passing a vec3 and a vec2
yields a mat2x3 (two columns, three rows):
mat2x3 outerProduct(vec3 c, vec2 r);How the Elements Are Populated
Because GLSL treats matrices as collections of column vectors
(matrix[column][row]), each column \(j\) in the result is simply the entire
first vector c scaled by the single scalar component
r[j]:
result[j] = c * r[j];Accessing the element at column \(j\) and row \(i\) corresponds to:
result[j][i] = c[i] * r[j];Practical Example
Consider the following operation in GLSL:
vec3 c = vec3(1.0, 2.0, 3.0);
vec2 r = vec2(4.0, 5.0);
mat2x3 result = outerProduct(c, r);The function computes each column sequentially:
Column 0 (
result[0]): Vectorcscaled byr.x(\(4.0\)) \[\begin{bmatrix} 1.0 \times 4.0 \\ 2.0 \times 4.0 \\ 3.0 \times 4.0 \end{bmatrix} = \begin{bmatrix} 4.0 \\ 8.0 \\ 12.0 \end{bmatrix}\]Column 1 (
result[1]): Vectorcscaled byr.y(\(5.0\)) \[\begin{bmatrix} 1.0 \times 5.0 \\ 2.0 \times 5.0 \\ 3.0 \times 5.0 \end{bmatrix} = \begin{bmatrix} 5.0 \\ 10.0 \\ 15.0 \end{bmatrix}\]
The resulting mat2x3 layout represents the combined
\(3 \times 2\) matrix:
\[\begin{bmatrix} 4.0 & 5.0 \\ 8.0 & 10.0 \\ 12.0 & 15.0 \end{bmatrix}\]
This operation is commonly used in shaders for computing covariance matrices, directional lighting tensors, coordinate-space projections, and physical simulation constraints.