0
\$\begingroup\$

Sorry about the click-bait, I know there are many many reasons why Quaternions and Bases are better than using Euler-Angles. Anyone on a 5 second google search could easily know why!

But I am trying my hardest to use Quaternions, and most the time I love them! They are a dream! But in specific instances like I am having now, I keep wondering "Are there times I can use Euler-Angles over Quaternions?".

I set up the logic for the rotation of a compass in the UI two ways. One way with Euler-Angles that took just a second and is short, and the other way with Quaternions that took me a while longer to set-up because I kept having problems with the discontinuity of interpolation angles. And so the compass would jump from 160 to -160 instead of going from 160 -> 180 -> -160 (the interpolation was taking the long way around).

I would like you to take a look at the code, and tell me if this would be a time that using semi-Euler's is better than Quaternions, or if the way I set up my Quaternion rotations is in-efficient or needlessly complex! I am really trying my hardest to use Quaternions and Bases for everything because I see their benefits!

P.S.: I still get the jumping between 160 and -160 degrees, any help there would be appreciated.

EULER-ANGLES:

float compassAngle = Vector3.Forward.SignedAngleTo(playerCamera.GlobalTransform.Basis.X, Vector3.Up);
compassInst.Rotation = new Vector3(0, compassAngle, 0);

QUATERNIONS/BASES:

Quaternion forwardRot = new Quaternion(Vector3.Forward, 0.0f).Normalized();
Quaternion playerCamRot = playerCamera.GlobalTransform.Basis.GetRotationQuaternion().Normalized();
        
if(playerCamRot.Dot(forwardRot) < 0){
    forwardRot = -forwardRot;
}
        
Quaternion targertRotComp = playerCamRot.Slerp(forwardRot, 0.1f);
        
compassInst.GlobalTransform = new Transform3D(new Basis (targertRotComp), compassInst.GlobalTransform.Origin);
```
\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

Simple rule: If you're only rotating on one axis, use Euler angles.

If you're using multiple axes, then the decision is a bit less simple.


Assuming your Euler code is correct, then I think that code doesn't work because it's using Slerp incorrectly. That function gives you a value between two rotations, but you don't want an intermediate rotation. You just want the target rotation.

I think the correct quaternion solution would be to transform the quat from player space into UI space (Vector3.Forward.SignedAngleTo(...) is doing a similar transformation for Euler). Likely something that uses operator*:

Composes these two quaternions by multiplying them together. This has the effect of rotating the second quaternion (the child) by the first quaternion (the parent).

Possibly something like compassInst.GlobalTransform = Basis.FLIP_Z * playerCamera.GlobalTransform.Basis.GetQuaternion() but I'm not certain what rotation you should rotate by the camera rotation.

\$\endgroup\$
2
  • \$\begingroup\$ I love this answer! Im not able to give up-votes yet, but when I am, you know I'll be back to give one! I love the "Simple rule" you gave me, something to go off of! All that being said, I want the compass to rotate around the y-axis only, so going by your rule, I know that Euler angles are completely fine here. But I am a curious cat, how would you have the Quaternion rotate on one axis (the Quaternions weren't rotating on one axis in that code, but I was willing to live with it)? \$\endgroup\$
    – ZenPyro
    Commented Mar 11 at 22:20
  • \$\begingroup\$ Quaternion interpolation takes the shortest path. If you were seeing rotation outside the one axis you wanted, then the start and end quaternions differed by more than just that one axis. \$\endgroup\$
    – DMGregory
    Commented Mar 11 at 22:58
0
\$\begingroup\$

I only suggest doing euler angles for an first person camera, where your pitch is clamped and your roll is always zero. You keep the pitch and header separately and combine them every frame. (Though I would recommend to keep them as sin/cos pairs instead of actual angles so you never have to deal with the wrapping point for the heading).

You get the long way around because the quaternions you were interpolating between were nearly a full turn apart. Each 3D orientation has 2 possible quaternions that can represent it (sometimes called double cover). If you always want the shortest (in 3D) rotation between objects then you will need to check the dot product between the quaternions and if it is negative (meaning the orientations are more than half a turn apart) you negate one of the quaternions.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .