Rotating Steps in Quaternions

Hello,

I’m using a quaternion (obtained by a simple ArcBall system) to rotate an actor. Everything is working great!
(Important note: It doesn’t work very well if I convert it to Euler before applying the rotation :frowning: )

But problem arises as soon as I try to make it rotate only by 10 degrees.

I tried using a FRotator:



	FQuat MyRotation = GetMyArcBall()->GetRotationQuat(); // My code, get the rotation quaternion 
// ...
	const int rotationStep = 10; // TODO: Add a setting for this
	FRotator CurrentRotator = MyRotation.Rotator();
	
	float YawMod = FMath::Fmod(CurrentRotator.Yaw, rotationStep);
	float YawAdjustment = -YawMod;
	if (YawMod > (rotationStep / 2))
		YawAdjustment = (rotationStep - YawMod);
		
	FQuat RotationStepAdjustment(FRotator(0.f, YawAdjustment, 0.f));
	
	MyRotation = RotationStepAdjustment * MyRotation;

This works nicely. But if I try the exact same code for Pitch, the rotation freaks out! (with the obvious replacement, below)


FQuat RotationStepAdjustment(FRotator(PitchAdjustment, 0.f, 0.f));

I’m trying to fix this for a gooooood while now :frowning:

From what I understood, I’d need to modify the x,y,z part of the quaternion, without touching the w part. Still, I’m having a hard time to understand how to do that properly.

Can someone give me a hand in this?

Thank you very much in advance!

I don’t understand why you’re creating an FRotator only to pass it to the FQuat constructor, just use directly a quaternion.
You can declare a quaternion like this:


// World space
FQuat YawRotation(FVector::UpVector, YawAdjustment);

// Actor space, GetActorUpVector() if derives from AActor
FQuat YawRotation(GetMyArcBall()->GetActorUpVector(), YawAdjustment);

For pitch rotation:


// World space
FQuat PitchRotation(FVector::RightVector, PitchAdjustment);

// Actor space
FQuat PitchRotation(GetMyArcBall()->GetActorRightVector(), PitchAdjustment);

1 Like

Thanks for your input Sneppy.

This was my previous code:


	FQuat PitchRotation(FVector::RightVector, FMath::DegreesToRadians(PitchAdjustment));

With so many different attempts to find a solution, my code changed a lot and ended up with a FRotator.

Still, it works with Yaw, but in Pitch, it keeps “flickering” around.
I just tried with GetMyArcBall()->GetActorRightVector(), but didn’t work either :frowning:

Are you trying to create a kind of angle snapping system?

Exactly :slight_smile:

Advices? :slight_smile:

Well, it depends on what kind of rotation you want to perform. A very simple method is applying rotation and then round to the nearest 10 each component of the FRotator, something like:


void RSnap(FRotator &OutRotation, float SnapValue = 10.f)
{
	const float Pitch = round(OutRotation.Pitch / SnapValue) * SnapValue;
	const float Yaw = round(OutRotation.Yaw / SnapValue) * SnapValue;
	const float Roll = round(OutRotation.Roll / SnapValue) * SnapValue;

	// I don't really remember components' order in constructor
	OutRotation = FRotator(Pitch, Yaw, Roll).GetNormalized();
}

But I’m not sure it’s what you want. Try it.

That was what I initially tried, and refined a bit to get to the code I pasted in the original topic. While it seems it will work, when it gets close to 0/90/180/270 degrees, the rotation gets wonky and starts to look bad.

Before, I converted the angle to euler and did all the math, it was great, but had singularity issues (i.e. gimbal lock, objects flipping, etc.), thus I converted the rotation to quaternion.
It works great, but I can’t find a way to apply rotation steps // angle snapping directly to quaternions.
All the attempts I did using euler angles did have problems :frowning:

I’m hoping someone can aid me with this (dense) math required to manipulate it directly in quaternions :slight_smile:

Thank you for your attempts! Hopefully you can help me reach a solution :smiley:

I’m bumping this topic in hopes more people can help :slight_smile:


// set the direction of A to direction of B.
// rotator
FRotator UWatsUp::QuatRotation(UArrowComponent *Obj, FRotator RotA, FRotator RotB) {
	FQuat QuatA = RotA.Quaternion();
	FQuat QuatB = RotB.Quaternion();
	FQuat FinalQuat = QuatA.Inverse() * QuatB;
	FinalQuat = QuatA * FinalQuat;
//	Obj->SetRelativeRotation(FinalQuat);	// works fine
	return FinalQuat.Rotator();			// works fine
}
//Directional Unit Vector
FRotator UWatsUp::QuatUnitVec(UArrowComponent *Obj, FVector VecA, FVector VecB) {
	FQuat QuatA = VecA.ToOrientationQuat();
	FQuat QuatB = VecB.ToOrientationQuat();
	FQuat FinalQuat = QuatA.Inverse() * QuatB;
	FinalQuat = QuatA * FinalQuat;
//	Obj->SetRelativeRotation(FinalQuat);
	return FinalQuat.Rotator();
}

2 Likes

Hi! I’m trying to adapt a pawn to the slope of the ground but it is not working well when the slope is greater than 90 degrees (f.ex. when the pawn is moving attached to the wall). I think this thread can help me. Did you find any solution? thanks!