GLSL Programming/Vector and Matrix Operations

The syntax of GLSL is very similar to C (and therefore to C++ and Java); however, there are built-in data types and functions for floating-point vectors and matrices, which are specific to GLSL. These are discussed here. A full description of GLSL can be found in the literature in the “Further Reading” section.

Data Types
In GLSL, the types,  , and   represent 2D, 3D, and 4D floating-point vectors. (There are also types for integer and boolean vectors, which are not discussed here.) Vector variables are defined as you would expect if C, C++ or Java had these types:

The data types for floating-point 2×2, 3×3, and 4×4 matrices are:,  , and  :

Precision Qualifiers
When declaring a floating-point variable (including vector and matrix variables), you can suggest a precision by using one of the precision qualifiers,  , or  , for example:

The idea is that  variables require less computation time and less storage (and therefore also less bandwidth) than   variables, and   variables require less time than   variables. Thus, for best performance you should use the lowest precision that still gives satisfactory results. (There are only a few exceptions to this, for example accessing individual elements of a  vector can be slower than for a   vector because it requires additional decoding.) Note that it is up to the compiler and driver to decide which precision is actually used; the precision qualifiers are only suggestions by the programmer. Also note that the range of  variables can be very limited (e.g. from -2.0 to 2.0), thus,   is most useful for colors but usually not for positions.

To define default precisions for all floating-point variables, you should use the  command, for example: This will use  if no explicit precision qualifier is specified for a floating-point variable. Without the command, the default precision for float is  in an OpenGL or OpenGL ES vertex shader,   in an OpenGL fragment shader, and undefined in an OpenGL ES fragment shader. (In Unity, however, the  command is not available and the default precision is   in a vertex shader and   in a fragment shader.)

Constructors
Vectors can be initialized and converted by constructors of the same name as the data type: Note that some GLSL compilers will complain if integers are used to initialize floating-point vectors; thus, it is good practice to always include the decimal point.

One can also use one floating-point number in the constructor to set all components to the same value:

Casting a higher-dimensional vector to a lower-dimensional vector is also achieved with these constructors:

Casting a lower-dimensional vector to a higher-dimensional vector is achieved by supplying these constructors with the correct number of components:

Similarly, matrices can be initialized and constructed. Note that the values specified in a matrix constructor are consumed to fill the first column, then the second column, etc.:

If a larger matrix is constructed from a smaller matrix, the additional rows and columns are set to the values they would have in an identity matrix: If a smaller matrix is constructed from a larger matrix, the top, left submatrix of the larger matrix is chosen, e.g. in the last line of the previous example.

Components
Components of vectors are accessed by array indexing with the -operator (indexing starts with 0) or with the  -operator and the element names   or   or  :

It is also possible to construct new vectors by extending the -notation ("swizzling"):

Matrices are considered to consist of column vectors, which are accessed by array indexing with the -operator. Elements of the resulting (column) vector can be accessed as discussed above:

Operators
If the binary operators  are used between vectors of the same type, they just work component-wise: Note in particular that  represents a component-wise product of two vectors, which is not often seen in linear algebra.

For matrices, these operators also work component-wise, except for the -operator, which represents a matrix-matrix product, e.g.:

$$\mathrm{A} \mathrm{B} = \left[ \begin{matrix} a_{1,1} & a_{1,2} \\ a_{2,1} & a_{2,2} \end{matrix} \right] \left[ \begin{matrix} b_{1,1} & b_{1,2} \\ b_{2,1} & b_{2,2} \end{matrix} \right]$$ $$ = \left[ \begin{matrix} a_{1,1} b_{1,1} + a_{1,2} b_{2,1} & a_{1,1} b_{1,2} + a_{1,2} b_{2,2} \\ a_{2,1} b_{1,1} + a_{2,2} b_{2,1} & a_{2,1} b_{1,2} + a_{2,2} b_{2,2} \end{matrix} \right]$$

And in GLSL: For a component-wise matrix product, the built-in function  is provided.

The -operator can also be used to multiply a floating-point value (i.e. a scalar) to all components of a vector or matrix (from left or right):

Furthermore, the -operator can be used for matrix-vector products of the corresponding dimension, e.g.:

$$\mathrm{M} \mathbf{v} = \left[ \begin{matrix} m_{1,1} & m_{1,2} \\ m_{2,1} & m_{2,2} \end{matrix} \right] \left[ \begin{matrix} v_{1} \\ v_{2} \end{matrix} \right]$$ $$= \left[ \begin{matrix} m_{1,1} v_{1} + m_{1,2} v_{2}\\ m_{2,1} v_{1} + m_{2,2} v_{2} \end{matrix} \right]$$

And in GLSL:

Note that the vector has to be multiplied to the matrix from the right.

If a vector is multiplied to a matrix from the left, the result corresponds to multiplying a row vector from the left to the matrix. This corresponds to multiplying a column vector to the transposed matrix from the right:

$$\mathbf{v}^T \mathrm{M} = \left(\mathrm{M}^T \mathbf{v}\right)^T $$

In components:

$$\mathbf{v}^T \mathrm{M} = \left[ \begin{matrix} v_{1} & v_{2} \end{matrix} \right] \left[ \begin{matrix} m_{1,1} & m_{1,2} \\ m_{2,1} & m_{2,2} \end{matrix} \right]$$ $$= \left[ \begin{matrix} v_{1} m_{1,1} + v_{2} m_{2,1} & v_{1} m_{1,2} + v_{2} m_{2,2} \end{matrix} \right]$$ $$= \left( \left[ \begin{matrix} m_{1,1} & m_{2,1} \\ m_{1,2} & m_{2,2} \end{matrix} \right] \left[ \begin{matrix} v_{1} \\ v_{2} \end{matrix} \right]\right)^T$$ $$= \left(\mathrm{M}^T\mathbf{v}\right)^T$$

Thus, multiplying a vector from the left to a matrix corresponds to multiplying it from the right to the transposed matrix: Since there is no built-in function to compute a transposed matrix, this technique is extremely useful: whenever a vector should be multiplied with a transposed matrix, one can just multiply it from the left to the original matrix. Several applications of this technique are described in.

Component-Wise Functions
As mentioned, the function computes a component-wise product for the matrix types,   and  , which are denoted as.

The following functions work component-wise for variables of type  and , which are denoted as  : There are more built-in functions, which also work component-wise but are less useful for vectors, e.g.,,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,   (converts degrees to radians),   (converts radians to degrees),  ,  ,  ,  ,  ,   (with one argument and with two arguments for signed numerator and signed denominator),  ,  ,  ,  ,  ,  , and.

Geometric Functions
The following functions are particular useful for vector operations. is any of:  and   (only one of them per line).

Functions for Physics
The function computes the direction of a refracted ray if  specifies the normalized(!) direction of the incoming ray and   specifies the normalized(!) normal vector of the interface of two optical media (e.g. air and water). The vector  should point to the side from where   is coming, i.e. the dot product of   and   should be negative. The floating-point number  is the ratio of the refractive index of the medium from where the ray comes to the refractive index of the medium on the other side of the surface. Thus, if a ray comes from air (refractive index about 1.0) and hits the surface of water (refractive index 1.33), then the ratio  is 1.0 / 1.33 = 0.75. The computation of the function is: As the code shows, the function returns a vector of length 0 in the case of total internal reflection (see the entry in Wikipedia), i.e. if the ray does not pass the interface between the two materials.