Up to date
This page is up to date for Godot
If you still find outdated information, please open an issue.
Using 3D transforms¶
If you have never made 3D games before, working with rotations in three dimensions can be confusing at first. Coming from 2D, the natural way of thinking is along the lines of "Oh, it's just like rotating in 2D, except now rotations happen in X, Y and Z".
At first, this seems easy. For simple games, this way of thinking may even be enough. Unfortunately, it's often incorrect.
Angles in three dimensions are most commonly referred to as "Euler Angles".
Euler angles were introduced by mathematician Leonhard Euler in the early 1700s.
This way of representing 3D rotations was groundbreaking at the time, but it has several shortcomings when used in game development (which is to be expected from a guy with a funny hat). The idea of this document is to explain why, as well as outlining best practices for dealing with transforms when programming 3D games.
Problems of Euler angles¶
While it may seem intuitive that each axis has a rotation, the truth is that it's just not practical.
The main reason for this is that there isn't a unique way to construct an orientation from the angles. There isn't a standard mathematical function that takes all the angles together and produces an actual 3D rotation. The only way an orientation can be produced from angles is to rotate the object angle by angle, in an arbitrary order.
This could be done by first rotating in X, then Y and then in Z. Alternatively, you could first rotate in Y, then in Z and finally in X. Anything works, but depending on the order, the final orientation of the object will not necessarily be the same. Indeed, this means that there are several ways to construct an orientation from 3 different angles, depending on the order of the rotations.
Following is a visualization of rotation axes (in X, Y, Z order) in a gimbal (from Wikipedia). As you can see, the orientation of each axis depends on the rotation of the previous one:
You may be wondering how this affects you. Let's look at a practical example:
Imagine you are working on a first-person controller (e.g. an FPS game). Moving the mouse left and right controls your view angle parallel to the ground, while moving it up and down moves the player's view up and down.
In this case to achieve the desired effect, rotation must be applied first in the Y axis ("up" in this case, since Godot uses a "Y-Up" orientation), followed by rotation in the X axis.
If we were to apply rotation in the X axis first, and then in Y, the effect would be undesired:
Depending on the type of game or effect desired, the order in which you want axis rotations to be applied may differ. Therefore, applying rotations in X, Y, and Z is not enough: you also need a rotation order.
Another problem with using Euler angles is interpolation. Imagine you want to transition between two different camera or enemy positions (including rotations). One logical way to approach this is to interpolate the angles from one position to the next. One would expect it to look like this:
But this does not always have the expected effect when using angles:
The camera actually rotated the opposite direction!
There are a few reasons this may happen:
Rotations don't map linearly to orientation, so interpolating them does not always result in the shortest path (i.e., to go from
0degrees is not the same as going from
360, even though the angles are equivalent).
Gimbal lock is at play (first and last rotated axis align, so a degree of freedom is lost). See Wikipedia's page on Gimbal Lock for a detailed explanation of this problem.
Say no to Euler angles¶
The result of all this is that you should not use the
rotation property of Node3D nodes in Godot for games. It's there to be used mainly in the editor, for coherence with the 2D engine, and for simple rotations (generally just one axis, or even two in limited cases). As much as you may be tempted, don't use it.
Instead, there is a better way to solve your rotation problems.
It is also possible to access the world coordinate transform via the
A transform has a Basis (transform.basis sub-property), which consists of three Vector3 vectors. These are accessed via the
transform.basis property and can be accessed directly by
transform.basis.z. Each vector points in the direction its axis has been rotated, so they effectively describe the node's total rotation. The scale (as long as it's uniform) can also be inferred from the length of the axes. A basis can also be interpreted as a 3x3 matrix and used as
A default basis (unmodified) is akin to:
var basis = Basis() # Contains the following default values: basis.x = Vector3(1, 0, 0) # Vector pointing along the X axis basis.y = Vector3(0, 1, 0) # Vector pointing along the Y axis basis.z = Vector3(0, 0, 1) # Vector pointing along the Z axis
// Due to technical limitations on structs in C# the default // constructor will contain zero values for all fields. var defaultBasis = new Basis(); GD.Print(defaultBasis); // prints: ((0, 0, 0), (0, 0, 0), (0, 0, 0)) // Instead we can use the Identity property. var identityBasis = Basis.Identity; GD.Print(identityBasis.