# Transformation

You may need to read the previous articles about attributes and uniforms in order to understand this one.

A *transformation* is a way to change something. There are three basic transformations: *translation*, *rotation*, and *scaling*.

## Translation

A translation is a movement. It is performed by adding a vector value to each vertex. For an initial vector $(x_0,y_0,z_0)$ and a translation vector $(x_t,y_t,z_t)$, the resulting vector is $(x_0+x_t,y_0+y_t,z_0+z_t)$.

In a vertex shader, a translation could be implemented with a vector uniform.

```
#version 300 es
in vec4 a_position;
uniform vec4 u_translation;
void main() {
gl_Position = a_position + u_translation;
}
```

## Rotation

A rotation is performed by multiplying each vertex by a point on the *unit circle*. The unit circle is the circle
with a radius of $1$. As such, it can be thought of as a rotating $1$, in that multiplying a vertex by a point on
the unit circle will not change its value (shape) except by rotating it.

A point on the unit circle can be calculated with the *sine* and *cosine* functions for the $x$ and $y$ values, respectively.
For an initial vector $(x_0,y_0)$ and a rotation value of $r$ radians, the resulting vector is $(x\sin(r)+y\cos(r),y\sin(r)-x\cos(r))$.
Different algorithms are used for different axes in higher dimensions (more details below).

In a vertex shader, a rotation could be implemented with a floating-point uniform.

```
#version 3000 es
in vec4 a_position;
uniform float u_rotation;
void main() {
float x = a_position.x * sin(u_rotation)
+ a_position.y * cos(u_rotation);
float y = a_position.y * sin(u_rotation)
+ a_position.x * sin(u_rotation);
gl_Position = vec4(x, y, a_position.zw);
}
```

## Scaling

A scaling is performed by multiplying each vertex by a vector. For an initial vector $(x_0,y_0,z_0)$ and a scaling vector $(x_s,y_s,z_s)$, the resulting vector is $(x_0x_s,y_0y_s,z_0z_s)$.

In a vertex shader, a scaling could be implemented with a vector uniform.

```
#version 300
in vec4 a_position;
uniform vec4 u_scaling;
void main() {
gl_Position = a_position * u_scaling;
}
```

## Matrices

There are various problems with using individual uniforms for translation, rotation, and scaling as described above. It can be tedious to use three different uniforms to describe the transformation of a vertex. Additionally, since the transformation logic is written into the vertex shader, a completely different shader program is required in order to apply the transformations in a different order.

A better way to pass transformations to the vertex shader is with *matrices*. Matrices are rectangular arrays of
numbers arranged in rows and columns and manipulated according to particular rules.

**Matrices are column-major**, which means that a matrix defined in JavaScript looks "sideways."

```
const matrix = [
1, 2, 3, // Column 1
4, 5, 6, // Column 2
7, 8, 9 // Column 3
];
```

The JavaScript "matrix" above is equivalent to the matrix below.

A *transformation matrix* is a matrix with $n$ rows and $n$ columns, where $n-1$ is the number of dimensions being
transformed. To transform a vertex by a transformation matrix, simply multiply the vertex by the matrix.

The product of the above matrices (a vector/vertex is just a matrix with one column) is a vector $(x_1,y_1,z_1)$.

Matrices can be constructed in specific ways such that the matrix multiplication described above has the same function as various transformations.

### Matrix translation

The following matrix translates an initial vector $(x_0,y_0,z_0)$ by $(x_t,y_t,z_t)$, resulting in a vector $(x_1,y_1,z_1)$.

### Matrix rotation

The following matrix rotates an initial vector $(x_0,y_0,z_0)$ by $r$ radians around the $z$ axis (most common in two dimensions), resulting in a vector $(x_1,y_1,z_1)$, where $c=\cos(r)$ and $s=\sin(r)$.

The following matrix is the equivalent for the $x$ axis.

The following matrix is the equivalent for the $y$ axis.

The following matrix is the equivalent for the $(x_a,y_a,z_a)$ axis, where $l=\sqrt{{x_a}^2+{y_a}^2+{z_a}^2}$ and $t=1-c$.

### Matrix scaling

The following matrix scales an initial vector $(x_0,y_0,z_0)$ by a scaling vector $(x_s,y_s,z_s)$, resulting in a vector $(x_1,y_1,z_1)$.

### Orthographic projection

It is also possible to make a matrix that converts from screen space to clip space (known as an *orthographic projection*),
since that operation is just a scale and a rotation. The following matrix converts a clip space vector $(x_0,y_0,z_0,w_0)$ to a
screen space vector $(x_1,y_1,z_1,w_1)$, where $l$, $r$, $b$, $t$, $n$, and $f$ are the left, right, bottom, top, near, and far
bounds of the frustum, respectively.

### Matrix multiplication

Like numbers, matrices can be multiplied together. The product of two transformation matrices has the combined transformations of both. Matrix multiplication is not commutative, which means that the order of the operands matters. The first operand's transformations are applied first, followed by the second operand's transformations.

Matrices can be passed as uniforms.

```
#version 300 es
in vec4 a_position;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * a_position;
}
```

In order to avoid implementing all of the algorithms described above, subsequent examples will use glMatrix to perform matrix math.

## Animation

Animation in WebGL is accomplished by changing the uniform (and sometimes attribute) values between frames.

```
const mat = mat4.create();
function renderStep() {
requestAnimationFrame(renderStep);
// Rotate the matrix slightly.
mat4.rotateZ(mat, mat, 0.01);
// Set the new uniform value.
program.uniforms.get("u_matrix").value = mat;
}
requestAnimationFrame(renderStep);
```

Note that since `requestAnimationFrame`

executes once each frame rather than at regular intervals, the time between
render steps can vary. In other words, animations being calculated within the render step can vary in speed based
on the framerate of the user. In order to ensure that animations remain smooth, the size of each transformation
should be scaled by the amount of time that passed between frames. The first argument passed to any function passed to
`requestAnimationFrame`

is the amount of time that that function has been running.

```
// Store the time of the last frame.
let then = 0;
function renderStep(now) {
requestAnimationFrame(renderStep);
// Calculate the amount of time between frames.
const deltaTime = now - then;
then = now;
mat4.rotateZ(mat, mat, 0.001 * deltaTime);
}
requestAnimationFrame(renderStep);
```

The next article is about the scene graph.