Matrices

libraries

OpenGL does not provide api to work with matrices.

For Java/Kotlin you can use JOML library. It is also provide stack for matrices (classes like Matrix4fStack).

For JavaScript, you can use the glMatrix library. For the stack, you can use a regular js array.

These libraries take in account that OpenGL uses column-major notation.

Follow the link to read the math details of 3D transformations with matrices.

model matrix

Typically, model geometry is centered around the origin - point (0,0,0).

One model can be used by multiple objects in the 3D scene.

At the same time, objects in a 3D scene have their own position, orientation, and size.

Model matrix transforms coordinates from model space to the world space. In other words, it transforms the model geometry as needed by the object.

projection matrix

The Projection matrix is responsible for defining the visible volume. Anything outside this volume will not be visible to the camera. Usually application has only one projection matrix. You can read more about the math details of projection matrix here.

camera and view matrices

The camera matrix defines position and orientation of camera or viewer in world space.

The View matrix transform from world space to view space, i.e. allows to represent world relative to the camera. This matrix is the inverse of the camera matrix.

There is method lookAt() that creates camera or view matrix. It has three parameters

  • camera position - default value in OpenGL is (0, 0, 0)
  • target - a point to which camera looks, in OpenGL defalut value is (0, 0, -1)
  • up vector - defining world's "upwards" direction, usually it has value (0, 1, 0)

viewmodel matrix

The ViewModel matrix defines transforms from model coordinates to eye coordinates. In math words, it is multiplication of view matrix and model matrix.

how to use matrices with shaders

Usually matrices are used as uniform variables.

in vec4 inCoords;
uniform mat4 matrix;

void main() {
    gl_Position = matrix * inCoords;
}

To bind data glUniformMatrix() functions are used.

// LWJGL+JOML
glUniformMatrix4fv(matrixLocation, false, matrix.get(matrixBuffer));

Location can be found by glGetUniformLocation() functions.

val matrixLocation = glGetUniformLocation(prog.idProgram, "matrix");

Like input attribute indices and output data locations, binding points can be set for uniforms within the shader. This is done by using the "binding" layout qualifier.

layout(binding = 1) uniform mat4 matrix;

share matrices between the shader programs

Complex app can use multiple shader programs. It is not cool to assign same projection or view matrix to each program. Fortunately, we can use a shared uniform block and to declare matrices there.

#version 330 core
layout (location = 0) in vec4 inCoords;

layout (std140) uniform Matrices
{
    mat4 projection;
    mat4 view;
};

uniform mat4 model;

void main() {
    gl_Position = projection * view * model * inCoords;
} 

Read more how to work with uniform buffer object.