# Normal Matrix Optimization

When it is time to render a mesh, we normally render that mesh multiplying all the vertices by a `Model-View-Projection`

matrix. This matrix will move, rotate, and scale all the vertices; however, we don't want to do this for the normals associated with those vertices.

To correctly rotate normals we will need another matrix, normally called `Normal Matrix`

. This matrix is a 3x3 matrix with a rotation encoded in it, and the short answer on how to get this matrix is to compute the transpose of the inverse of the Model matrix.

```
normal_mat = transpose(inverse(model_mat));
```

If you want to know more behind the math involved in this computation, please take a look at this fantastic post.

The only problem here is that `inverse(...)`

operation is expensive :).

While trying to optimize our normal matrix computation, these are some characteristics that we were required to maintain (and others to take advantage of).

- Our matrices are always orthogonal.
- Our matrices can contain non-uniform scale.

At the same time, our goal is to compute a matrix that will rotate the normal associated with a vertex in the same way the model matrix does, but removing any non-uniform scale and any translation at the same time.

Lets put an example:

Model matrix

```
X Y Z
1.0 0.0 0.0 0.0
0.0 2.0 0.0 0.0
0.0 0.0 1.5 0.0
0.0 0.0 0.0 1.0
```

Normal matrix (expected)

```
X Y Z
1.0 0.0 0.0 0.0
0.0 0.5 0.0 0.0
0.0 0.0 0.66 0.0
0.0 0.0 0.0 1.0
```

In the example above we can see how the `Y`

and `Z`

axis have a non-uniform scale, and if we want to remove that scale, the axis itself will need to multiply by the inverse of the scale.

So, we can create a `Normal Matrix`

with this idea in mind:

We extract the axis of the matrix to operate with them.

```
Matrix44 m = model_mat;
vec3 x = vec3(m[0][0], m[1][0], m[2][0]);
vec3 y = vec3(m[0][1], m[1][1], m[2][1]);
vec3 z = vec3(m[0][2], m[1][2], m[2][2]);
```

We compute the length of those axis.

```
float lx = length(x);
float ly = length(y);
float lz = length(z);
```

After we have the length, we will normalize them.

```
normalize(x);
normalize(y);
normalize(z);
```

We multiply them by the inverse of the length(scale) to remove any non-uniform scale on that axis.

```
x = x * (1.0 / lx);
y = y * (1.0 / ly);
z = z * (1.0 / lz);
```

We create a new Normal Matrix with the axis we have just computed.

```
Matrix33 normal_mat = identity_matrix;
normal_mat[0][0] = x[0];
normal_mat[1][0] = x[1];
normal_mat[2][0] = x[2];
normal_mat[0][1] = y[0];
normal_mat[1][1] = y[1];
normal_mat[2][1] = y[2];
normal_mat[0][2] = z[0];
normal_mat[1][2] = z[1];
normal_mat[2][2] = z[2];
```

At this point, `normal_mat`

will contain a Normal Matrix that will be able to rotate normals and remove the non-uniform scale of them. This will be very important to allow a correct computation of the light.

This way of computing the Normal Matrix was ~55% faster than computing it by `inverse(modela_mat)`

.