How to avoid gimbal lock in Unreal Engine (c++)?

I created an orbit camera (sometimes called turntable camera; similar to the one with the "use UE3 orbit controls" setting in a static mesh view).

I attached the camera to a USpringArmComponent with a TargetArmLength set to 400. In the tick function, I rotate the arm with this simple method:

        // Simple, clamped version
FRotator Rotation = CameraSpringArm->GetComponentRotation();
Rotation.Yaw += CameraInput.X * CameraRotationSpeed;
Rotation.Pitch = FMath::Clamp(Rotation.Pitch + CameraInput.Y * CameraRotationSpeed, -85.0f, 85.0f);
CameraSpringArm->SetRelativeRotation(Rotation);


I had to clamp the pitch to hide the gimbal lock problem. But this prevent users to rotate completely around objects. I don't understand why the Z rotation (the yaw) occurs on the world z axis ( FVector::UpVector which is (0, 0, 1)) and not on the local z axis. It turns out that this is exactly what I want.

I tried to solve this gimbal lock problem with this other method:

        // Taken from https://answers.unrealengine.com/questions/232923/how-can-i-avoid-gimbal-lock-in-code.html
FRotator RotationDelta(CameraInput.Y * CameraRotationSpeed, CameraInput.X * CameraRotationSpeed, 0.f);
FTransform NewTransform = CameraSpringArm->GetComponentTransform();
NewTransform.ConcatenateRotation(RotationDelta.Quaternion());
NewTransform.NormalizeRotation();
CameraSpringArm->SetWorldTransform(NewTransform);


It works, but this time, the Z rotation (yaw) occurs on the local Z axis. How can I change it to rotate around the world Z axis, and the local Y axis, without gimbal lock?

I tried this hybrid solution, but the gimbal lock is still there:

        // Hybrid
FRotator RotationDelta(CameraInput.Y * CameraRotationSpeed, 0.f, 0.f);
FTransform Transform = CameraSpringArm->GetComponentTransform();
FRotator Rotation = CameraSpringArm->GetComponentRotation();
Rotation.Yaw += CameraInput.X * CameraRotationSpeed;
Transform.SetRotation(Rotation.Quaternion());
Transform.ConcatenateRotation(RotationDelta.Quaternion());
Transform.NormalizeRotation();
CameraSpringArm->SetWorldTransform(Transform);


I did solve this problem (a long time ago) in OpenGL using quaternions, so I tried this version:

        // Quaternion
FRotator Rotator = CameraSpringArm->GetComponentRotation();
FQuat Quaternion = Rotator.Quaternion();
// Rotate around the world Z axis:
Quaternion *= FQuat(FVector::UpVector, FMath::DegreesToRadians(CameraInput.X * CameraRotationSpeed));
// Rotate around the local Y axis:
Quaternion *= FQuat(Rotation.RotateVector(FVector::RightVector), FMath::DegreesToRadians(CameraInput.Y * CameraRotationSpeed));
CameraSpringArm->SetRelativeTransform(Quaternion);


But this does not work. I also tried this:

        // Quaternion + transform
FTransform Transform = CameraSpringArm->GetComponentTransform();

Removing the camera lag (CameraSpringArm->bEnableCameraRotationLag = false;) solved the problem.