[Solved] Correct way to set Euler angles for Actor in C++

Hi!
I want to postion several planes at some coordinates from C++ code. Planes surely will have Euler angles (roll, pitch, yaw).

I successfully position planes with lat/lon coordinates:

glm::dvec3 recalcAircraftCoordinates = this->cesiumGeoreference->TransformLongitudeLatitudeHeightToUnreal(glm::dvec3(aircraftLongitude, aircraftLatitude, aircraftHeight));
FVector UEAircraftCoordinates = FVector(recalcAircraftCoordinates.x, recalcAircraftCoordinates.y, recalcAircraftCoordinates.z);

But I can’t rotate them correctly. It works fine around CesiumGeoreference Origin. But if I put plane on the other side of the Globe it appears turned upside down.
I tried this option:

// aircraftRotation(Pitch deg, Yaw deg, Roll deg) ??
FRotator aircraftRotation(0.0f, 0.0f, 0.0f)
FRotator UEAircraftRotation = this->cesiumGeoreference->TransformRotatorEastNorthUpToUnreal(aircraftRotation, UEAircraftCoordinates);

Then i thought that maybe it is better to use quaternions:

glm::dquat qAircraftRotation(aircraftRotation.Quaternion().W, aircraftRotation.Quaternion().X, aircraftRotation.Quaternion().Y, aircraftRotation.Quaternion().Z);
glm::dquat qUEAircraftRotation = this->cesiumGeoreference->TransformRotatorEastNorthUpToUnreal(qAircraftRotation, recalcAircraftCoordinates);
FRotator UEAircraftRotation(FQuat4d(qUEAircraftRotation.x, qUEAircraftRotation.y, qUEAircraftRotation.z, qUEAircraftRotation.w));

But still nothing helps.
What am I missing?

Best regards,
Nikita

Hello @nikkitta!

I think the ENU-conversion functions seem broken. I opened this draft PR as a first attempt to start fixing the API: Fix broken euler angles and quaternion conversions by nithinp7 · Pull Request #983 · CesiumGS/cesium-unreal · GitHub.

As a workaround in the meanwhile, you can use the ComputeEastNorthUpToUnreal function, which returns a 3x3 rotation matrix from East South Up (not a typo) to Unreal. The incorrect naming of this function and others should be fixed in the linked PR as well.

Let me know if that doesn’t work for you either, or if you run into any further issues!

-Nithin

Hi Nithin, thanks for the quick reply!

I’m ashamed to admit it, but I’m confused about the transformations with matrices in Unreal. In theory, having a 3x3 rotation matrix (M), I should multiply it by the aircraft’s rotation vector (M * aircraftRotationAsFRotator). But I don’t understand how to do it in terms of FMatrix/FRotator.
For now I’m just summing up M.Rotator() and aircraftRotationAsFRotator:

FMatrix UEaircraftRotationMatrix = this->cesiumGeoreference->ComputeEastNorthUpToUnreal(UEAircraftCoordinates);
FRotator UEAircraftRotation = UEaircraftRotationMatrix.Rotator() + aircraftRotation;

At zero Euler angles I get the correct result at any point on the globe, that’s a win.
But if I set any angle of aircraftRotation to 30.0f (for example) I get a different rotation of the 3D model in space depending on the geographical location.

That is also a question - does Cesium use the same fileds from FRotator constructor like (Pitch, Yaw, Roll)? I mean the Unreal’s FRotator.Pitch is the Cesium’s Pitch, and so on.

I’m not sure if you can just add the rotators together like that. Try converting your aircraftRotation to an FMatrix (I think this function might help FRotationMatrix | Unreal Engine Documentation) and then multiply the two matrices. You can convert the result back to a rotator.

You could also try converting both the ESUtoUnreal matrix and your aircraft rotator to quaternions, multiply them, and then convert the result back to rotators.

Regarding your second question, the ESU coordinate system (again mislabeled as ENU in the function names currently) assumes the same conventions as Unreal’s coordinate system. Notably, it is left-handed and the euler angle rotation order is the same (yaw, pitch, then roll). Just like Unreal yaw is around the Z-axis (Up), pitch is around the Y-axis (South), and roll is around the X-axis (East). It doesn’t make much sense in a world space like ESU or Unreal world to talk about “pitch”, “yaw”, and “roll”, but that’s how the math should work out! So for example, if you wanted to rotate to face the North pole, you might use an ESU rotator of (0 pitch, -90 yaw, 0 roll).

Let me know if this works for you!

Thank you, it works now!
Waiting for proper fix for TransformRotatorEastNorthUpToUnreal :slight_smile:

Firstly I tried to use FMatrix multiplication as you proposed, but unfortunately it also failed with the plane positioned on the other side of the Globe.

I got to the success with quaternions and here is the full code, hope it will help someone:

double roll = 30.0;
double yaw = 0.0;
double pitch = 0.0;
// It is strange, but I checked visually and that’s the order you get for the 3D model. (Roll, Yaw, Pitch).
// With positive values you get following rotations:
// Roll - plane rotates left (counterclockwise while looking from the back)
// Yaw - plane rotates right (clockwise while looking from top)
// Pitch - plane “wants” to go up in the sky
FRotator aircraftRotation(roll, yaw, pitch);
FVector UEAircraftCoordinates = …; // Plane position in UE coordinates
FMatrix UElocalPlaneRotationMatrix = this->cesiumGeoreference->ComputeEastNorthUpToUnreal(UEAircraftCoordinates);
FQuat4d UEAircraftRotationQuat = UElocalPlaneRotationMatrix.ToQuat()* aircraftRotation.Quaternion();

FRotator UEAircraftRotation = UEAircraftRotationQuat.Rotator();

FActorSpawnParameters SpawnInfo;
AAircraftActor* aircraft = GetWorld()->SpawnActor(AAircraftActor::StaticClass(), UEAircraftCoordinates, UEAircraftRotation, SpawnInfo);

I also want to point out that by experiment I got a different order of Euler angles. See comments in the code above.

@Nithin_Pranesh if there are any objections or comments, I will gladly listen to them. Thanks a lot for the quick help!

1 Like