Need help with matrices

Was hoping I wouldn’t have to call for help for this one, but it’s just beyond me. :frowning:

I modified the ShooterGame so that the camera follows a socket, defined on the mesh (it’s a child of the b_head). It’s working, but when the character moves, there is a sort of offset: the 1st person weapon mesh moves opposite to where the character is going. This happens because the camera is no longer fixed, but follows the mesh’s animation.

So, I realized I had to change the OnCameraUpdate() function. That function positions the first person mesh when the camera moves.

Here is my code:

void AShooterCharacter::OnCameraUpdate(const FVector& CameraLocation, const FRotator& CameraRotation)
{
	USkeletalMeshComponent* DefMesh1P = Cast(GetClass()->GetDefaultSubobjectByName(TEXT("PawnMesh1P")));
	const FMatrix DefMeshLS = FRotationTranslationMatrix(DefMesh1P->GetComponentRotation(), CameraLocation + DefMesh1P->RelativeLocation);
	
	const FRotator RotCameraPitch(CameraRotation.Pitch, 0.0f, 0.0f);
	const FRotator RotCameraYaw(0.0f, CameraRotation.Yaw, 0.0f);

	FMatrix LeveledCameraLS = FRotationTranslationMatrix(RotCameraYaw, CameraLocation);
	FMatrix PitchedCameraLS = FRotationMatrix(RotCameraPitch) * LeveledCameraLS;
	const FMatrix MeshRelativeToCamera = DefMeshLS * LeveledCameraLS.InverseSafe();
	const FMatrix PitchedMesh = MeshRelativeToCamera * PitchedCameraLS;
	Mesh1P->SetWorldLocationAndRotation(PitchedMesh.GetOrigin(), PitchedMesh.Rotator());
}

With this code:

  • During movement, the weapon looks perfectly still, it only plays the Mesh1P animation (this is the intended behaviour);
  • If I aim up/down, the Mesh1P updates correctly.
  • But if I look left/right, the Mesh1P doesn’t updates. Its yaw is fixed.

How do I fix the yaw update?

For reference, here’s the original code on ShooterGame. Modified lines are noted with —.

void AShooterCharacter::OnCameraUpdate(const FVector& CameraLocation, const FRotator& CameraRotation)
{
	USkeletalMeshComponent* DefMesh1P = Cast(GetClass()->GetDefaultSubobjectByName(TEXT("PawnMesh1P")));
--- const FMatrix DefMeshLS = FRotationTranslationMatrix(DefMesh1P->RelativeRotation, DefMesh1P->RelativeLocation);
	const FMatrix LocalToWorld = ActorToWorld().ToMatrixWithScale();

	// Mesh rotating code expect uniform scale in LocalToWorld matrix

	const FRotator RotCameraPitch(CameraRotation.Pitch, 0.0f, 0.0f);
	const FRotator RotCameraYaw(0.0f, CameraRotation.Yaw, 0.0f);

--- const FMatrix LeveledCameraLS = FRotationTranslationMatrix(RotCameraYaw, CameraLocation) * LocalToWorld.InverseSafe();
	const FMatrix PitchedCameraLS = FRotationMatrix(RotCameraPitch) * LeveledCameraLS;
	const FMatrix MeshRelativeToCamera = DefMeshLS * LeveledCameraLS.InverseSafe();
	const FMatrix PitchedMesh = MeshRelativeToCamera * PitchedCameraLS;

--- Mesh1P->SetRelativeLocationAndRotation(PitchedMesh.GetOrigin(), PitchedMesh.Rotator());
}

I am just trying to provide some pointers in (hopefully) the right direction since I cannot test this myself, but these two lines seem the most interesting to me:

FMatrix PitchedCameraLS = FRotationMatrix(RotCameraPitch) * LeveledCameraLS;

const FMatrix PitchedMesh = MeshRelativeToCamera * PitchedCameraLS;

:slight_smile:

Seems like you need to make another FRotationMatrix for the yaw, and multiply the Pitched Mesh by that as well

const FMatrix YawedCamera = FRotationMatrix(RotCameraYaw);

:slight_smile:

for a grand conclusion of:

const FMatrix PitchedMesh = MeshRelativeToCamera * PitchedCameraLS * YawedCamera;

Note I did not multiply the YawedCamera by LeveledCameraLS;

you could try that as well :slight_smile:

Let me know if this gets you going in the right direction!

Rama

No, that didn’t do it. But you did get me in the right direction!

I’ve rewritten everything for clarity. The end result is:

void AShooterCharacter::OnCameraUpdate(const FVector& CameraLocation, const FRotator& CameraRotation)
{
    const FRotator RotCameraPitch(CameraRotation.Pitch, 0.0f, 0.0f);
    const FRotator RotCameraYaw(0.0f, CameraRotation.Yaw, 0.0f);
	USkeletalMeshComponent* DefMesh1P = Cast(GetClass()->GetDefaultSubobjectByName(TEXT("PawnMesh1P")));
    
	const FMatrix CameraTranslationMatrix = FTranslationMatrix(CameraLocation);
	const FMatrix StartingTranslationMatrix = FTranslationMatrix(DefMesh1P->RelativeLocation);
	const FMatrix StartingRotationMatrix = FRotationMatrix(DefMesh1P->RelativeRotation);
    const FMatrix PitchedMatrix = FRotationMatrix(RotCameraPitch);
	const FMatrix YawedMatrix = FRotationMatrix(RotCameraYaw);
    const FMatrix ResultMatrix = StartingTranslationMatrix * StartingRotationMatrix * PitchedMatrix * YawedMatrix * CameraTranslationMatrix;
    Mesh1P->SetWorldLocationAndRotation(ResultMatrix.GetOrigin(), ResultMatrix.Rotator());
}

ResultMatrix = StartingTranslationMatrix (the weapon offset) * StartingRotationMatrix (rotation defined on the component in Blueprint) * PitchedMatrix (camera rotation) * YawedMatrix (camera rotation) * CameraTranslationMatrix (final camera position) is what I wanted to do all along. Can’t believe I spent like 5 hours to figure this out. It’s so clear now!

Thanks Rama!