Roll, Pitch, Yaw rotations - Strange Behavior

Hi guys, I am rotating an object and I found a strange behavior. I manually set the rotation of the object in the scene so that the Local Coord System of the object is not equal to the World Coord System. When I rotate the object around the Roll(X) and Pitch(Y) axes, the rotation is performed around the Local X and Y axes of the object. However, when I rotate the object around the Yaw(Z) axis, the rotation is performed around the World Z axis. Is this a correct behavior or I am not using the SerActorRotation(FRotator NewRotation) method correctly?

Here is the code:

// Pickup.h

UCLASS()
class APickup : public AActor
{
	GENERATED_UCLASS_BODY()

public:
	/** The root component of the pickup object */
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Components")
	TSubobjectPtr<USceneComponent> SceneComponent;

	/** The static mesh of the pickup object */
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Components")
	TSubobjectPtr<UStaticMeshComponent> PickupMesh;

	/** The rotation rate of the pickup object in degrees/second for each axis of the FRotator */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rotation")
	FRotator RotationRate;

	virtual void Tick(float DeltaTime) override;
};

// Pickup.cpp

APickup::APickup(const FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	this->PrimaryActorTick.bCanEverTick = true;

	this->SceneComponent = PCIP.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComponent"));
	this->RootComponent = this->SceneComponent;

	this->PickupMesh = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("PickupMesh"));
	this->PickupMesh->AttachTo(this->RootComponent);

	this->RotationRate = FRotator(180.0f, 0.0f, 0.0f);
}

void APickup::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	this->SetActorRotation(this->GetActorRotation() + (this->RotationRate * DeltaTime));
}

First off, the docs say SetActorRotation(link):

bool AActor::SetActorRotation(FRotator NewRotation)
{
    if (RootComponent)
    {
        return RootComponent->MoveComponent( FVector::ZeroVector, NewRotation, true );
    }
 
    return false;
}

So if we look at MoveComponent, the docs say (link):

NewRotation Parameter ==> The new desired rotation in world space.

So this function you are using sets the new rotation relative to world space coordinates.

Here are two suggestions for what you are trying to do:

Use AddActorLocalRotation (link).

void APickup::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    this->AddActorLocalRotation(this->RotationRate * DeltaTime, false);

}

Hopefully this fixes the problem for you =)

Edit: I initially had two functions to choose from for modifying local rotation… I haven’t tested one so I removed it from the answer. The remaining one should work fine as I currently use it this way.

Thank you very much mate, very useful answer. I guess I need to spend some more time exploring the docs.

The class hierarchy in UE is pretty big and can become overwhelming quickly. The reason I made the answer like this is so you can use the same logic to help you (and others) debug future problems that are similar in nature =)

I’m glad the solution worked for you as I had a very similar problem in the past =D