Rotator Oddities when incrementing Pitch small amounts across 360 range, Yaw/Roll go to 180 occasionally (of their own volition)

Dear Friends at Epic,

I am trying to rotate objects within my in-game editor using the mouseDelta ( I am literally dragging the mouse around to change the rotation)

I am just doing Pitch at the moment for testing.

I am smoothly rotating the object along its Pitch value over a full 360 range.


I’ve noticed that at about 90 and about 270, as I am incrementally adjusting the pitch,

the yaw and roll will set themselves to 180, causing a lockup during the smooth rotation that often forces me to switch the direction I am moving the mouse to get the object to keep rotating in the SAME direction and not get stuck.

I noticed this also when I was trying to set the rotation of my Directional Light, the Sun, just smoothly incrementing the yaw was causing a hitch in the rotation at High noon of about 90 degrees.

#Repro
You can even observe this for yourself in the Editor, grab the Sun, and start rotating it along one axis (pitch for example), while the F4 properties window is open.

You’ll notice that the other rotation values (yaw and roll) that you are not trying to edit will be editing themselves as you try to rotate the light along a single axis.

In the editor this works fine and there is no hitch, but when I am only adjusting a single rotation component like pitch via the C++, it is resulting in weird behavior

Why is this happening?


Can you explain to me why this behavior happens and how to avoid it?

It is making my ability to smoothly incrementally rotate objects very difficult :slight_smile:

Here’s my code:

//this function is running PER-TICK, resulting in smooth appearance of rotation
//except at 90 and 270 when the yaw and roll, which SHOULD be 0
//go to 180 all of a sudden (and then back to 0)
//Z
	if (VictoryPC->IsInputKeyDown(EKeys::Z))
	{
		//CTRL - Rotation - Pitch
		if (VictoryPC->PlayerInput->IsCtrlPressed())
		{
			
			//get the Actor Rotation
			FRotator RV_Rot = VictoryPC->SelectedSMA->GetActorRotation();
			
			//Increment the Pitch by MouseDelta ( a small number averaging 0-2 per tick)
			RV_Rot.Pitch		+= VictoryPC->MouseDeltaX;
			
			//Passing Each Component for Precision
			//(I get same behavior using VectorQuantizedNormal)
			SERVER_RotateSMA(
				RV_Rot.Pitch, RV_Rot.Yaw, RV_Rot.Roll, 
				VictoryPC->SelectedSMA
			);
			return;
		}
		
	}

//Doing the Rotation on the server so replicated movement works happily
void AVictoryPower::SERVER_RotateSMA_Implementation(
	float P, float Y, float R,	
	AStaticMeshActor * VSMA
) {
	if (!VSMA) return;
	//~~~~~~~~~~~~~~
	
	FRotator RV_Rot = FRotator(P, Y, R);
		
	VSMA->SetActorRotation(RV_Rot);
}

#What the issue isnt

It has nothing to do with the network

I had the same problem rotating the Sun locally

It has nothing to do with mousedelta

I was rotating the sun by holding the up arrow on my keyboard and continually adding to the pitch value each tick


Hope you can help me out with this, it’s making rotators difficult for me to use :slight_smile:

Rama

#Update

When I forcibly zero out the yaw and the roll so that they dont switch to 180 at pitch=90 and pitch=270

then the smooth rotation process using mouse delta simply stops at 90 or 270 and will not continue

what is the internal functioning of FRotators that 90 and 270 cause so much excitement,

and how do I smoothly rotate an object along a single Rotator component without any hitches or direction reversals required using mouse delta?

Thanks!

:slight_smile:

Rama

#Found Quaternion Solution

I found a way around this using Quaternions

But I have presented this post to you to give you an idea of how others might react when they first try to use ActorRotation and the method in my first post

:slight_smile:

Quaternion Solution for Incremental Rotation

FTransform TheTransform = GetTransform();
TheTransform.ConcatenateRotation(DeltaRotation);
SetActorTransform(TheTransform);

I do not consider this post as having been resolved because people should not have to use quaternions to do what I am trying to do in the first post, Standard manipulations of

GetActorRotation() to (change the rotation) to SetActorRotation()

should have the intended effect, in my opinion

But I am very happy with working solution, just wanted to bring this to your attention

:slight_smile:

Rama

Is what youre experiencing gimbal lock?

Thank you for asking Daniel!

I dont think so because I see a similar pattern in the editor when rotating along a single access.

I experienced gimbal lock in ue3 only via RLerp, and here in ue4 I am just adding values directly, there’s no interpolation going on

If it was gimbal lock I dont think I’d be observing a very systematic pattern of the yaw and roll being set to 180 at pitch= 90 and 270 in what seems to be a very deliberate pattern.

Again, thanks for asking :slight_smile:

Rama

Im witnessing similar in the editor but only on the pitch component, it happens in world and local space.

the pitch has definitely been my focus as well, for the Sun and also what I was testing, so it definitely sounds like something Epic might want to take a look at :slight_smile:

Rotating using rotator can cause gimbal lock, but also there is conversion happening between quaternion and rotator if you’re using rotator. Internal representation of rotation is quaternion, so if you use rotator, we have to convert and when we convert, there is a point where flip happens, and that is 270 degree of pitch.

Our original plan for this was to prevent users from using +/- operators of rotators since it’s a misleading operation when you think of gimbal lock, but we’ve decided to leave it because if we remove +/- operators, people will use +/- for each component(pitch, yaw, roll).

Current tentative plan is to convert internal rotation to use rotator/quaternion to avoid this conversion issue. I’d recommend using quaternion until then.

Thanks,

–Lina,

What I find odd is its locking even rotating on a single axis, I thought that the rotator could be reorientated for the case of 1 or 2 axis to avoid gimbal lock and the only place its unavoidable is a full 3 rotation axis cumulative addition/subtraction. Thats when the quat is required but then the 4th axis becomes something of a transform in relation to world space, that on a pivot (not a full 3d rotation) you can fudge a rotator that only requires the single world transform coord to be 2 complete rotations in world space much like pointing a vector at another.

Thanks Lina!

I am finding FQuats pretty easy to work with, though I still find it easiest to set the Rotator as I want it to be using FRotator and then convert to FQuat :slight_smile:

But as long as you all have some kind of plan to address this further I’m very excited to see what you come up with!

:slight_smile:

Rama