# Unreal Engine C++: FMatrix doc sheet # #include "Math/Matrix.h"

## Memory layout

Matrix elements are accessed with:

```    FMatrix::M[rowIndex][columnIndex]
```

Therefore `FMatrices` are row major in memory.

(Since: `int array = { {0, 1}, {2, 3} };` In memory looks like this: `0 1 2 3`)

## Representation (CPU)

Recall that the "matrix representation" ≠ "memory layout". You can have a column-major memory layout but a row-matrix representation (basis vectors set as rows)

Ultimately it's only the user that knows how the numbers inside a `FMatrices` are organized but Unreal's convention is to use a row-matrix representation:

```    X.x  X.y  X.z  0.0 // Basis vector X
Y.x  Y.y  Y.z  0.0 // Basis vector Y
Z.x  Z.y  Z.z  0.0 // Basis vector Z
T.x  T.y  T.z  1.0 // Translation vector
```

`FMatrix::setAxis()` and methods alike uses row-matrix representation.

## Multiplication

Because `FMatrix` convention is to use row-matrix representation the order you multiply matrices together is the opposite of the traditional math way:

• Math (column representation):
`M3 * M2 * M1 * vec`
M1 gets applied first and M3 last
• UE (row representation):
`vec * M1 * M2 * M3`
for M1 to be applied first multiplication needs to be reversed.

Note that there is nothing particular about the implementation of the multiplication operator:

```void FMatrix::mult(int A[N][N], int B[N][N]) {
int C[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int num = 0;
for (int k = 0; k < N; k++) {
num += A[i][k] * B[k][j];
}
C[i][j] = num;
}
}
}
```

But since UE lays out the coefficients of the matrix in a transpose way of the conventional math way, we need to reverse the order transforms are usually multiplied.

Something pretty usual with `FMatrix` when it gets uploaded to gpu/shader in Unreal code base, is that it gets transposed and converted to a float3x4

```FMatrix44f mat;
// fill mat
float mat3x4_columnMajor;
mat.To3x4MatrixTranspose(/*out: */ mat3x4_columnMajor);
```

Therefore, usually, the code in the Unreal's shader relies on a column-matrix representation of the transformations and multiplication happens in the conventional math way: `M3 * M2 * M1 * vec`

```//HLSL
float3x4 M1; // First transformation
float3x4 M2; // Second transformation
vec3 new_position = mul( M2, mul( M1, vec3(position)));
```

Note: HLSL memory layout is row-major, just like a `FMatrix` memory layout is row-major. If we had not transposed it, we would multiply from the left inside the Shader code as well, just like in CPU code.

# Code samples

```// Copy constructor / copy operator :
FMatrix44f mat = FMatrix44f::Identity;

mat.M = 1.0f;
mat.M = 0.0f;
mat.M = 0.0f;

FMatrix44f mat2 = mat;

FMatrix44f mat3 = FMatrix44f::Identity;

mat3 = mat;

mat.M = -1.0f;
mat.M = -1.0f;
mat.M = -1.0f;

// FMatrix is a 4x4 *double matrix:
FMatrix m = FMatrix::Identity;

m.M = -2.0;
m.M = -2.0;
m.M = -2.0;

FMatrix44f mat4 = FMatrix44f(m);

// Convert transform to FMatrix:
FTransform tr = FTransform::Identity;
mat4 = FMatrix44f( tr.ToMatrixWithScale() );

// FVector is a 3D double vector:
FVector pos(1.0, 2.0, 3.0);
// multiply against the 4x4 matrix (pox.x, pos.y, pos.z, 1.0)
pos = m.TransformPosition( pos );
```

# FTransform

The order of multiplication is the same as a FMatrix:
`vec * T1 * T2 * T3`

`T1` gets applied first and `T3` last.

```FTransform tr{
FRotator{ 10.0f, 20.0f, 30.0f },    // Rotation around each axis in degrees (y, x ,z)
FVector{ 1.0f, 2.0f, 3.0f },        // Translation
FVector{ 2.0f, 1.0f, 1.0f }         // Scale
};
FTransform tr_inv = tr.Inverse();
FTransform identity = tr * tr_inv;

FVector pos = FVector{ 50.0f, 60.0f, 70.0 };
FVector new_pos = tr.TransformPosition( pos );

// WARNING: be sure to use InverseTransformPosition() and not TransformPosition()
// Although each components (rotation, translation, scale) is inverted.
// You must also invert the order you apply the components to truly invert the transformation:
FVector back_to_pos = tr_inv.InverseTransformPosition( new_pos );

// On  the other hand when working with FMatrix you don't need to
// pay attention to the above corner case:
FMatrix mat_inv = tr.ToMatrixWithScale().Inverse();
FVector back_to_pos = mat_inv.TransformPosition( new_pos );
``` 