A Small Discussion on What The Controller Class Is and FRotationMatrix

For an extremely long time I did not actually understand the concept of the controller class and the FRotationMatrix type. These things are not commonly explained in classrooms or tutorial, and for the most part they feel like things people just expect you to go with the flow on, without fully knowing how it works.

But understanding how it works is critical in order to properly have ideas on how to best implement certain things in your workflow. And just to be safe here, these are my ideas alone, and they help my understanding, if you have a better understanding feel free to comment and add on ideas or anything below.

The Controller
So I’ll start off by saying that to understand the controller one first has to have some knowledge on pointers and how the heap works. If you’ve studied c++ well you’ll know that pointers will point to some memory location that contains data in the heap. It’s just that simple.

The controller is an object that can be pointed to that’s stored within the heap of the program. Its function is to relay input information from your keyboard/mouse/gamepad to the character movement component of whatever pawn you are working with.

Inside the controller class is a private member (which happens to be an *APawn pointer) to store the address of the pawn it possessed using the possess method contained within it. For the sake of Brevity, I’ve simplified the code for the class below:

class AController {
public:
    // Function to possess a pawn by the controller
    void Possess(APawn* PawnToPossess) {
        Pawn = PawnToPossess;
        // Additional code to handle possession logic
    }

    // Function to stop controlling the current pawn
    void UnPossess() {
        Pawn = nullptr;
        // Additional code to handle unpossession logic
    }

    // Other controller functionality and member variables...

private:
    APawn* Pawn; // Pointer to the pawn being controlled by this controller
};

Okay, now to add onto what I said earlier. The controller is an object just like any other that can be placed in the world, and it has a rotation (which we will talk about later). But for now all you need to know is that it’s an object, and it’s one that is stored in the heap (please do this).

So to show you how it all works, a simple example should tell you the rest of what is happening in a logical manner:

AController* ControllerForJoe = GetWorld()->SpawnActor<AController>();
APawn* SomePawn = GetWorld()->SpawnActor<APawn>();
ControllerForJoe->Possess(SomePawn);

I hope all of this makes sense, you have a controller, you have a pawn, and the controller uses the possess method to fill its Pawn private member. Easy peasy. There’s a lot of background stuff that goes into this, but for now this should suffice. Earlier a few years ago I wrote a post detailing how to thing about how a controller interacts with a character, which is similar to a marionette puppet. But I hope this makes sense.

FRotationMatrix

To understand FRotationMatrix, you need to first know some linear algebra and go over how Rotational Linear Transformations work. Typically rotation matrices often come up a lot in robotics, you know those fancy industrial robotic arms used in manufacturing; in their programming they’re actually working with matrices. In 3D space, which we normally denote with R3 in linear algebra, there’s three major matrices that use formulas in order to transform a vector in 3D space. This means that if you apply this transformation to a vector, you will get a new vector that has been rotated a particular angle, and typically in relation to the axis on which the vector is in. (Note that these are all separate matrices)

R0x = 1, R0y = 0, R0z = 0
R1x = 0, R1y = cos(ϕ), R1z = -sin(ϕ)
R2x = 0, R2y = sin(ϕ), R2z = cos(ϕ)

R0x = cos(θ), R0y = 0, R0z = sin(θ)
R1x = 0, R1y = 1, R1z = 0
R2x = -sin(θ), R2y = 0, R2z = cos(θ)

R0x = cos(ψ), R0y = -sin(ψ), R0z = 0
R1x = sin(ψ), R1y = cos(ψ), R1z = 0
R2x = 0, R2y = 0, R2z = 1

In game development, and I won’t go too deep as to why, we use a 4x4 (2 dimensional) matrix to represent a rotation matrix, and this is because we usually have to use this matrix to make transformations from the R3 space to the R2 space. The math just works out if you do it. So to get the rotation matrix from the three matrices I previously described earlier, all you need to do is multiply the three matrices together and you will have the lower portion of your FRotationMatrix, which holds the vectors on each row that point outward to what each unit axis (assuming the usual right hand rule orthogonal vectors):

R(ϕ)*R(θ)*R(ψ)

FRotationMatrix:
Rx Rx Rx 0
Ry Ry Ry 0
Rz Rz Rz 0
0 0 0 1

Then in our code when we call the function GetUnitAxis(), we select a particular row from this, because this set of vectors represent the unit axis of the Controller. All we are basically getting out of FRotationMatrix is a set of rotated unit axis! Brain explosion!!

If you want to dive deeper into an explanation into why all of this works this way you can check out this video here from Pikuma: Math for Game Developers: Why do we use 4x4 Matrices in 3D Graphics? - YouTube

I hope all of this made sense to you, and helps you out in your future endeavors, cheers!