Understanding Euler rotation

I thought I understand Euler rotation, but I’m learning that it’s doing some things I do not, in fact, understand. :slight_smile:

Let’s say that I want to rotate an object around its Y axis some degree amount between 0 and 360. I would think that I would do something like this:

this.entity.setLocalEulerAngles(0,135,0);

But that doesn’t actually set the object to 0, 135, 0. It actually sets the object to 180, 45, 180. Upon further investigation, I learned that these conversions happen on-the-fly:

0-90 degrees y … 0, 0–90, 0 (exact value mapping)
90-180 degrees y … 180, 90–0, 180 (90 assigned as 90, 180 assigned as 0)
180-270 degrees y … 180, 0–-90, 180 (180 assigned as 0, 270 assigned as -90)
270-360 degrees y … 0, -90–0, 0 (270 assigned as -90, 360 assigned as 0)

I haven’t bothered to investigate values in excess of 360.

I’m sure this is proper/correct (I’m guessing it has to do with gimbal lock), I’m just wondering what I should do to get predictable assignment (i.e. if there’s a conversion going on, I’d rather do it myself before assignment so that it assigns the exact values I specify).

Oh, also, I created a test project that shows this.

https://playcanv.as/p/LDugg8Yy/

It’s more of the restriction of sin/cos/tan functions IIRC. The rotation of an entity is represented by a quaternion rather than eulers but isn’t exactly human readable so any operations to rotate the entity by eulers is converted to a quaternion first.

From the engine source

        /**
         * @function
         * @name pc.Quat#setFromEulerAngles
         * @description Sets a quaternion from Euler angles specified in XYZ order.
         * @param {Number} ex Angle to rotate around X axis in degrees.
         * @param {Number} ey Angle to rotate around Y axis in degrees.
         * @param {Number} ez Angle to rotate around Z axis in degrees.
         * @returns {pc.Quat} Self for chaining.
         * @example
         * var q = new pc.Quat();
         * q.setFromEulerAngles(45, 90, 180);
         */
        setFromEulerAngles: function (ex, ey, ez) {
            var sx, cx, sy, cy, sz, cz, halfToRad;

            halfToRad = 0.5 * pc.math.DEG_TO_RAD;
            ex *= halfToRad;
            ey *= halfToRad;
            ez *= halfToRad;

            sx = Math.sin(ex);
            cx = Math.cos(ex);
            sy = Math.sin(ey);
            cy = Math.cos(ey);
            sz = Math.sin(ez);
            cz = Math.cos(ez);

            this.x = sx * cy * cz - cx * sy * sz;
            this.y = cx * sy * cz + sx * cy * sz;
            this.z = cx * cy * sz - sx * sy * cz;
            this.w = cx * cy * cz + sx * sy * sz;

            return this;
        }

If you want to purely work in euler angles, I recommend storing the angles yourself and manipulating them.

Ah okay, that makes sense. Thanks for the information!

So, I was just using euler angles because I wanted to rotate only the Y axis and it made sense in my mind to do it that way. Would it be better practice to use quaternions for that? I haven’t directly interacted with quaternions very much and am not really sure what their practical direct usage is (that is, skipping eulers altogether and just working with quats).

Nah, I would just keep the rotation in eulers and store it locally in the entity script somewhere. The model viewer starter project/template does something similar as it has to deal with limits of pitch and rotation.

Quaternions have several advantages over eulers, most notably not having gimbal local and applying multiple rotations is a lot easier. Some more information here: https://www.gamedev.net/resources/_/technical/math-and-physics/quaternion-powers-r1095