# Transforming models

When a mesh is rendered, each of its vertices goes through a series of matrix multiplications before it finally gets on the screen. These matrices are knows as the *world*, *view* and *projection* matrices. While the view and the projection matrix control where is the camera, which direction is it looking and how is the 3D scene projected onto the screen (i.e. orthographic or perspective projection), the world matrix is the one that moves, rotates and scales the models. In this tutorial we will have a look at how you can transforms models using the world matrix.

## Contents

## The world matrix

GML comes with a few built-in functions using which you can control mentioned matrices and you can find them in the official manual. For us the most interesting ones are `matrix_build`

, `matrix_build_identity`

, `matrix_multiply`

and `matrix_set`

.

```
bbmod_material_reset();
matrix_set(matrix_world, matrix_build(x, y, z, 0, 0, direction, 1, 1, 1));
model.submit();
matrix_set(matrix_world, matrix_build_identity());
bbmod_material_reset();
```

The code above uses `matrix_build`

to create a new matrix that:

- rotates the model around the Z axis by the
`direction`

variable, - leaves the scale of the model at 1 for each axis,
- translates the model by
`x`

,`y`

,`z`

variables on the XYZ axes,

all of which **in this exact order**, then sets it as the current world matrix with `matrix_set(matrix_world, ...)`

and draws a model. Note that because of this order of transformations `matrix_build`

produces skew matrices when non-uniform scaling is used in combination with rotations! If you instead wanted to scale the model first and then rotate it, you would have to do that with two separate matrices multiplied together:

```
// Only scales model:
var _matrixScale = matrix_build(0, 0, 0, 0, 0, 0, scaleX, scaleY, scaleZ);
// Only rotates and translates model:
var _matrixRotateTranslate = matrix_build(x, y, z, 0, 0, direction, 1, 1, 1);
// Scales first, then rotates and translates:
var _matrixScaleRotateTranslate = matrix_multiply(_matrixScale, _matrixRotateTranslate);
matrix_set(matrix_world, _matrixScaleRotateTranslate);
```

The last line in our previous example resets the world matrix back to an *identity* matrix, which is built using the `matrix_build_identity`

function. This matrix leaves vertices untransformed, i.e. the resulting vertex position is the same one as the input vertex position. This is not necessarily required to do after each model is drawn, but it definitely should be done after all models are drawn, otherwise the world matrix could also transform other graphical elements like GUI for example.

## Matrix utilities

As you have noticed, the built-in GML functions for dealing with matrices can be quite verbose, especially when doing more complex transformations that require several matrix multiplications. For this reason BBMOD comes with a struct BBMOD_Matrix, which simplifies chained transformations into method calls. Here is how would you rewrite the code above using `BBMOD_Matrix`

:

```
bbmod_material_reset();
new BBMOD_Matrix()
.RotateZ(direction)
.Translate(x, y, z)
.ApplyWorld();
model.submit();
new BBMOD_Matrix().ApplyWorld();
bbmod_material_reset();
```

The code became much more self-explanatory, without having to learn in which specific order is translation, rotation and scale executed when you use `matrix_build`

. Not to mention that you do not need to fill in all 9 arguments even in case you just wanted to rotate a model around single axis. For the full list of `BBMOD_Matrix`

methods, please see its documentation.

## Performance considerations

Matrix multiplications in GML are an expensive operation and doing a lot of them each frame can drastically affect performance. It is recommended to instead *cache the results and reuse them whenever possible!* For example, if you have an object that never moves, you can compute its transformation just once in the object's create event and then simply set it in the draw event:

```
// Some place executed just once, for example inside of a script:
global.matrixIdentity = matrix_build_identity();
```

```
/// @desc Create event
matrix = new BBMOD_Matrix()
.Scale(scaleX, scaleY, scaleZ)
.RotateZ(direction)
.Translate(x, y, z);
```

```
/// @desc Draw event
bbmod_material_reset();
matrix.ApplyWorld();
model.submit();
matrix_set(matrix_world, global.matrixIdentity);
bbmod_material_reset();
```