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.
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;
The inverse of a rotation matrix is the adjugate of this matrix.
Adjugate of a rotation 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 :
The inverse of a rotation matrix is the transpose of this matrix.
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);