Euler angles are a way to represent the rotational orientation of an object in 3-dimensional space, using three angles. The order in which these angles are applied is important, as different orders of these rotations lead to different final orientations.
Roblox uses “intrinsic XYZ” Euler angles (equivalent to “extrinsic ZYX”), meaning that the rotations happen in object space, in the order XYZ, for CFrame rotations. The
BasePart/RotVelocity property uses extrinsic XYZ angles instead.
Understanding Euler angles
Euler angles represent a series of rotations in different axes. Let’s assume we apply the euler angles 30°, 60°, and 45° to a brick. We can visualize this as a sequence of simple rotations:
- Rotate the brick in its X axis by 30°
- Rotate the brick in its Y axis by 60°
- Rotate the brick in its Z axis by 45°
An important thing to note here is that rotations are done relative to the bricks position at each step. At step two, the brick is tilted - the Y axis is no longer vertical.
If we reverse the order, we can use absolute axes
- Rotate the brick in the world Z axis by 45°
- Rotate the brick in the world Y axis by 60°
- Rotate the brick in the world X axis by 30°
Converting Euler angles to a CFrame
To actually do this rotation in roblox, you would use
math.rad to convert your angles to radians, and
CFrame.Angles to create the CFrame.
part.CFrame = CFrame.Angles(math.rad(30), math.rad(60), math.rad(45))
It’s worth noting that in general:
CFrame.Angles(x, y, z) == CFrame.Angles(x, 0, 0) * CFrame.Angles(0, y, 0) * CFrame.Angles(0, 0, z)
Converting a CFrame to Euler angles
Roblox provides a method to convert a CFrame to Euler angles,
local x, y, z = part.CFrame:toEulerAnglesXYZ()
However, this is generally not the right solution to the problem you are trying to solve. Some common cases for which this is the wrong solution:
Getting only the rotational part of a CFrame
Sometimes, you might want to copy the rotation of one brick, and apply it to another, without moving the second brick. An obvious approach is
local x, y, z = part1.CFrame:toEulerAnglesXYZ() local rotation = CFrame.Angles(x, y, z) part2.CFrame = rotation + part2.Position
While this method works, it is terribly inefficient, and prone to rounding errors. A much better approach is
local rotation = part1.CFrame - part1.Position part2.CFrame = rotation + part2.Position
To get only the rotational part, you can just subtract the position!
Finding the heading of a part
You might want to show the angle the player is driving a vehicle at (0 - 360°) in a GUI.
local direction = part1.CFrame.lookVector local heading = math.atan2(direction.x, direction.z) heading = math.deg(heading)
Extracting Euler Angles
Given CFrame matrix, the Euler angles can be extracted from the CFrame like the following demonstrates.
local sx, sy, sz, m00, m01, m02, m10, m11, m12, m20, m21, m22 = matrix:components() -- m12 = −cos Y sin X -- m22 = cos X cos Y -- => -m12 / m22 = sin X / cos X ]] local X = math.atan2(-m12, m22) -- m02 = sin Y local Y = math.asin(m02) -- m01 = −cos Y sin Z -- m00 = cos Y cos Z -- => -m01 / m00 = sin X / cos X ]] local Z = math.atan2(-m01, m00)
- Tait–Bryan angles, the technical name for the class of Euler angles used by Roblox