Clarifying the ambiguities of rotation in Unity

So this might be a long one, I am trying to assimilate all the information about rotations in Unity.

Euler angles: What I know is that euler angles are a way of representing the rotation of an object with respect to its parent or the world axes. The two problems with them are, there are multiple euler angles for any rotation, and they suffer from gimbal locks.---------------------------------------------------

The first problem, I think I understand, but please add or correct whatever you need to: So unity applies rotations in the ZXY order according to its docs, so the euler angle values are usually according to this order. But since it is not the only order of getting to the required orientation, other orders can be applied too. Hence the lack of uniqueness of a euler triplet. This makes any situation where we need to read their values to progress dangerous. But any situations where they only need to be incremented or decremented from, may be fine…unless we run into the second problem which is gimbal locks.--------------------------------------------------------------------------------------------------------------

Here is my limited understanding of gimbal locks: Gimbal locks occur when a degree of freedom is lost due to certain rotations. What I dont understand is why are rotations treated as gimbals? Why must there be a hierarchy of axes to decide rotation order, with Z affecting X and Y, X affecting Y and Y not affecting the other two. The rotation gizmos in unity dont act like gimbals and a rotation around one of the axis changes the orientation of the other two axes accordingly for all three axes, thus always keeping the axes mutually perpendicular. So why is it that a gimbal lock situation must ever arise? -----------------------------------------------------------------------------------------------------------------------------

Finally, I went on this journey hoping to understand rotations better because of a problem Im facing in my project. I am trying to make a ghost playable character, that has 3 dimensional motion similar to the free roam cameras in games like counter strike where after you die you can explore the entire map using the free roam camera.---------------------------------------------------------------------------------------------

Mouse movement in the vertical and horizontal axes should make the ghost look in that direction so the z axis of the ghost should face in the direction I am looking, and then with the arrow keys if i press forward, the ghost moves along that new z direction and similarly the new x and y directions using the different keys I have assigned. Now the problem is when I wrote a look script for the ghost, I rotate the ghost around its x and y axes based on Mouse Y and Mouse X input. Then I change the ghosts direction using the quaternion multiplication operator such that ghost.rotation *= Quaternion.Euler(xRot,yRot,0) . ------------------------------------------------------------------------------------------------

But the issue is this causes the ghost to also tilt along its z axis which I do not want. I found the parenting solution where the parent is used for horizontal looking and the ghost is its child and looks in vertical. But I wanted to understand why this issue arises, hence the whole journey which has brought only more questions so far. -----------------------------------------------------------------------------------------------------------------------

If someone took the time to clarify these things for me, I would be really really grateful!

Well, rotations in 3d are a way more complex beast compared to 2d. The first thing you have to keep in mind that Euler angles do not represent a single orientation but a consecutive execution of 3 seperate rotations. There are generally two ways how you can imagine a certain set of eulerangles and how they actually affect an object.

First it’s important to define the reference axis of the rotation we talk about. Hopefully it should be clear that local rotations are rotations that are relative to the coordinate space of the parent object while world space rotations are relative to the world coordinate space. So even for some deeply nested object when we talk about the worldspace orientation / rotation we simply mean a rotation that is relative to the worldspace.

The first way you can imagine euler angles is that you apply the 3 rotations based on the used order (ZXY in Unity) around the reference axis in that order. We assume that before we apply the rotation the object is simply aligned with the reference space. The the x, y and z axis are aligned which would equal a euler angle rotation of (0, 0, 0). For example if we have a rotation (45,90,10) it means you start with the object being aligned with the reference space. Now you rotate the object 10 degrees around the Z axis of the reference space. After that we will rotate the object around the X axis of the reference space and finally we rotate the object around the Y axis of the reference space.

When you think about this order you do not really see the gimbals as you assume to grab the object, rotate it around an axis and then release it in order to grab it again and rotate around another axis. However there’s another way you can imagine the exact same rotation hierarchy. If you consider the objects own local space axis the order is actually in reverse. So the first rotation is around the Y axis. Since in the beginning the object is aligned with the reference space the local y axis and the reference space Y axis is the same. However the X rotation that follows is now around the already rotated local X axis of the object you’re rotating. In our example The first rotation was 90° around Y. This will rotate the object clockwise 90° when viewed from above. That means the local Z axis of the object now points in the same direction as the x axis of the reference space. Likewise the local X axis is now pointing into the “-z” direction of the reference space. Now we rotate around this rotated local space x axis by 45°. This will make the local space z axis to point at a 45° angle downwards. In the end we rotate the 10° around the now tilted local space z axis.

This has the exact same effect as we explained earlier. The euler angles always represent a gimbal system, no matter how you view it. When using the local axis you could imagine starting with the outermost gimbal (Y) and then insert the other gimbals in between before doing the other rotations. When viewing the rotations from the outside around the reference space axis you would start with the innermost gimbal (Z). Once the innermost rotation has been applied you add the next gimbal wrapping the first one and rotating this one. Finally you add the outermost gimbal and doing the final rotation around Y. In any case you have this fix ordering of gimbals.

Don’t get confused on the euler angles wikipedia page. Yes there are many different ways how you could order the gimbals. However Unity only uses this one hierarchy. Completely independent from this ordering there are always multiple ways to represent the same rotation / orientation. The easiest example to wrap your head around is imagine the rotation (0,180,0). So the object is simply turned around so it looks backwards. Instead of this 180° rotation around y you can also totate 180° around the x axis (180,0,0). You are also looking backwards but your view is upside down. Now just apply another 180° around the local z axis and the view is correct again and absolutely identical. So (0,180,0) is the same as (180,0,180). However there are many more examples and also much more complex examples because it’s not always just adding / subtracting 180°.

Yes gimbal lock is an orientation when the middle axis of the euler angles order (in the case of Unity that’s the x axis) is ±90° or close to that. In this case the local z axis is aligned with the reference space y axis… So the rotations around Y and Z are essentially around the same axis. Just try it inside Unity and set the X rotation to 90 and change the Y and Z rotations in the inspector. You will notice that both angles will perform the same rotation. This is where you lost one degree of freedom.

The next important thing to realise is, Unity does not use euler angles to represent rotations. Unity uses quaternions. Any combinations of rotations in 3d space can be combined into a single rotation around a non axis aligned rotation axis. That’s in essence what a quaternion represents. It defines an arbitrary rotation axis and how much to rotate around that single axis. So a quaternion can do all rotations you may want to do at once. There are ways to convert euler angles to a quaternion and backward. However this conversion may not be what you might expect. Think of the example above. When you set an euler angle combination of (180,0,180) it gets converted into a quaternion. When you read back the euler angles you may get (0,180,0). That’s why read-modify-write operations on eulerangles are not recommended and can cause weird issues.

A quick note about relative rotations. If you apply relative rotations to an already rotated object you may cause rotations around unwanted axes. If you only apply relative rotations around two axis, say the world Y and world X axis you can cause a rotation around Z. Just think about this:

rotate -90° around X so the object is looking straight up
rotate 90° around Y so the object is still looking up but is now rotated 90°
rotate 90° around X so the object is again looking in the original direction but is now rotated 90 around Z.

Keep in mind that applying relative rotations does not mean that you just add or subtract values to the euler angles. Since relative rotations are not aligned with the actual object that is already rotated they cause rotations around other objects.

An important note about the Untiy editor: The Unity editor actually uses euler angles in the inspector which the editor stores seperately to avoid certain issues with quaternion to euler angles conversion. However at runtime the only thing that matters is the quaternion representation.

About the rotation gizmos inside the Unity editor.
Those gizmost have two orientation modes: local and global. Note that the 3 gizmos do not represent the euler angle axes. If they did you would always only change one euler angle value when you rotate one of the gizmos. However try this: Rotate a cube 45° around x. In local mode you can rotate the cube around the local y axis (the green gizmo). However that is not one of the euler angles axes. When you rotate around that axis you will notice that all 3 euler angles values will change. If you switch the gizmo mode to global the y axis is now aligned with the actual y axis of the euler angles, however not the z gizmo. If you now rotate the z gizmo you will notice the same behaviour. The gizmos in the editor are there for convenience, not to represent the euler angles gimbal hierarchy. Keep in mind that the gimbal lock orientation does not prevent a certain rotation since you can represent all orientations with euler angles. However in order to reach a certain orientation from a current orientation there might not be a simple solution and it would require all 3 euler angle values to be changed. In real life such issues with mechanical gimbal systems (like a mechanical gyroscope) we usually use a 4th gimbal which with some clever math can change the gimbal orientation whenever it is close to a lock position without actually rotating the system.

Long story short: In most cases when you have any kind of FPS camera you want to use absolute rotations and a clear simple hierarchical order of your rotations. Most FPS games have 360° freedom around the world space up axis to freely turn around and about ±90° rotation around the local x axis. In space games like space engineers there are no limits on the rotation axes. However in 3d space when using the jetpack you actually have 3 axes you can rotate around. So besides the two mouse axis you also have the E and Q buttons to rotate around Z. You need those because, as mentioned earlier when having actual free 3d rotations without any world space alignment you can cause z rotation just by combining relative x and y rotations. In most FPS games you have a clear up / down orientation which you want to keep.

The easiest solution is to completely seperate those two rotations. So you have your player / ghost object that only rotates around the Y axis and is always parallel to the ground. As a child you attach the camera which you only around the local x axis. You usually clamp the local x rotation between -+90°

As for the movement of your ghost you simply use the forward vector of your camera to move the parent object around.

ps: Sorry I think this answer got a bit too long already ^^.