transform.localEulerAngles resulting in incorrect values

I notice that if I try to set the localEulerAngles to something like (0, 0, 90) for example, it is possible to end up with any value that where (value %= 360) == 90.

For example, if I set localEulerAngles.z in the inspector to something like -1000 and run code to set it to 90f, it ends up showing -990 while localEulerAngles.z returns the correct value of 90f.

Is this intended behaviour? Is there something else I should write in my code to fix this display issue?

Here is an quick example of where I encouter the problem:

public class ExampleClass : MonoBehaviour
{
    void OnDrawGizmosSelected() {
        if (EditorGUI.actionKey) {
            var e = transform.localEulerAngles;
            e.z = RoundToNearest(e.z, 90f);
            e.z %= 360f;
            transform.localEulerAngles = e;
        }
    }
}

Should I perhaps go ahead and file a bug report?

This is not a bug.

Unity stores rotations as Quaternions. Euler angles are merely a convenient representation for the UI.

When you write to localEulerAngles, Unity converts the value you give to a quaternion before applying it to the transform. Later, to display the value in the inspector, the quaternion is comverted back into euler angles.

This conversion is not unique There are infinitely many sets of Euler angles that can represent the same quaternion. So sometimes the one you get back out is not the one you put in.

1 Like

I would typically expect converting from a quaternion to the euler angles to use the values 0 to 360. For some reason Unity is holding onto a prefered result, based on what the previous euler angles were.

How can I tell Unity to generate the euler angles, but without any prior notion as to what the preferred set would be?

Out of curiousity, what is the reason you care about what values are displayed in the editor?

There are plenty of annoying little things (and some major) in Unity.

A simply display issue like this is confusing. I’ll just have to remember that if I either:
want to get back exactly what is shown in the editor I cannot just do transform.rotation.eulerAngles
or store a value outside of the usual set of 0 to <360,
as I cannot rely on the inspector.

While I currently am a solo developer, I can see where this could be super confusing for team members less experienced with Unity and its quirks.

I believe that the inspector should either show exactly what the value would be if used, or remember which set of numbers is used when read/written.

1 Like

My guess is because even though the euler angles you enter into the inspector are only used by the transform after conversion to a quaternion, they are actually serialized as euler angles the way you typed them for inspector purposes. Unity probably bases future inspector representations of the angle on previous values entered, to avoid certain visual annoyances. Maybe otherwise you’d see things like angles continually flipping between 180 and -180, 270 and -90, etc. Might get irritating. Just a guess.

As far as displaying the angle without any bias from what is entered into the inspector, just create a script which outputs localEulerAngles to the inspector panel every frame. My guess is you’ll see the output as even more nonsensical than the current behavior you are seeing. But it might actually help with what you’re trying to do.

Some insight into why it behaves this way: There is an extra hidden property of Transform called m_LocalEulerAnglesHint. It’s set when you input a value manually into the Transform inspector, to hide the ugly Quaternion and give you clean values when working with Euler angles in the inspector. This value gets reset to the converted value if the rotation is set in any way other than through the inspector.

The behavior outlined in the OP is almost certainly an artifact of this conversion process. Since you’re initially retrieving the converted value (not the clean Euler angle from the inspector), your x and y will most likely have “strange” values. This will persist through the set, and probably color the way it gets converted in the future (even though the ending rotation is the same).

In my workflow, I have developed a policy of not paying attention to the Euler angles displayed in the inspector, and more generally speaking to converted Euler angle values at all. Instead, I work with visualizations of rotations via Debug.DrawRay or gizmos, which give me a much more intuitive understanding of the behavior of the underlying Quaternion.

Thanks. I will check out that hidden property.