# PSXDEV : Billboard system

Trying to devise a billboard system for this psx 3d engine I've been working on, I first used a trigonometric approach that used atan2, then found out that it was simpler and cheaper to use a inverse rotation matrix.

## Trigonometry

So this was my first idea :

```
// Sprite system WIP
// Find angle between billboard object and camera object using atan2
objAngleToCam.vy = patan( posToCam.vx,posToCam.vz );
objAngleToCam.vx = patan( posToCam.vx,posToCam.vy );
// Apply rotation to billboard
curLvl.meshPlan->rot.vy = -( (objAngleToCam.vy >> 4) + 1024 ) ;
// Update billboard's relative position to camera object
posToCam.vx = -camera.pos.vx - curLvl.meshPlan->pos.vx ;
posToCam.vz = -camera.pos.vz - curLvl.meshPlan->pos.vz ;
posToCam.vy = -camera.pos.vy - curLvl.meshPlan->pos.vy ;
```

So here we're using `patan()`

, which is a function that uses a pre-calculated atan2 table for speed.

As is, this solution works, but only for the Y axis (PSX uses a Y-down coord system).

Trying to align it on the X and Z axis result in gimbal lock, which is not good looking.

## Inverse rotation matrix

Fast forward a few weeks, and I have this realization that somewhere in my brain is a knowledge I can use to solve this another way !

I learned from my good psxdev pal **@Nicolas Noble** that finding an inverse rotation matrix is quite trivial if you already have a rotation matrix handy :

Here is the inverse matrix formula :

In plain english, that's : The inverse matrix is the transpose of the matrix's co-factors divided by the determinant.

We know that the determinant of a rotation matrix is 1 :

Rotation matrices are square matrices, with real entries. More specifically, they can be characterized as orthogonal matrices with determinant 1;

https://en.wikipedia.org/wiki/Rotation_matrix

thus :

The inverse of a rotation matrix is the adjugate of this matrix.

### Adjugate of a rotation matrix

The adjoint or adjugate of a matrix is the "transpose of the cofactor matrix".

Let's try with a rotation matrix. We know that the rotation matrix on the X axis is

Let's isolate the rotation part in a 2x2 matrix :

According to this document, finding the adjugate means swapping the entries without the signs diagonally, then applying the sign matrix :

In this case, on the diagonals, we switch with ... , and with ... .

Nothing changed so far.

But applying the sign matrix changes the signs of the and we end up with :

### Transpose of a rotation matrix

The transpose of a matrix is a new matrix whose rows are the columns of the original. [https://www.quora.com/What-is-the-geometric-interpretation-of-the-transpose-of-a-matrix]

Remember the rotation part of our rotation matrix on X ?

Let's try to find the transpose of that.

The first column of that matrix is and the second column is .

Let's make our first row : .

Now let's make our second row : .

The result is ... ! Looks familiar ?

So we can see that if :

hence :

The inverse of a rotation matrix is the transpose of this matrix.

### Code

So we know that the adjugate of a rotation matrix is the same as its transpose...

We do have a `TransposeMatrix()`

function available in PsyQ, so let's use that !

```
// Find inverse rotation matrix so that the billboard object always faces camera
// working matrices
MATRIX curRot, invRot;
// Get current rotation matrix
ReadRotMatrix(&curRot);
// Get transpose of current rotation matrix and store it in invRot
TransposeMatrix(&curRot, &invRot);
// Multiply current rotation matrix by the inverse matrix
SetMulRotMatrix(&invRot);
```

## Sources

https://discord.com/channels/642647820683444236/663664210525290507/826109895874838551

https://en.wikipedia.org/wiki/Rotation_matrix

https://en.wikipedia.org/wiki/Adjugate_matrix

http://www.macs.hw.ac.uk/~markl/teaching/Inverses.pdf

https://www.quora.com/What-is-the-geometric-interpretation-of-the-transpose-of-a-matrix