Missing CFrame.fromEulerAngles constructor

There is no mention of the fromEulerAngles constructor

Page URL: https://create.roblox.com/docs/en-us/reference/engine/datatypes/CFrame

2 Likes

Is it perhaps this?

No, there is a constructor named fromEulerAngles that takes 3 numbers and an optional RotationOrder.

1 Like

Thanks for the report! We’ll follow up when we have an update for you.

Thanks so much for calling this out. I’ve added the missing constructor here: CFrame | Documentation - Roblox Creator Hub

Thank you for adding this to the documentation, though it seems the rotation order described doesn’t align with the rotation orders described for fromEulerAnglesXYZ and fromEulerAnglesYXZ.

On the rotation order page it says Enum.RotationOrder.ZYX applies rotation orders in the order Z,Y,X which is the same as described in the fromEulerAnglesXYZ constructor.

print(
	CFrame.fromEulerAngles(1,2,3,Enum.RotationOrder.ZYX)
	==
	CFrame.fromEulerAnglesXYZ(1,2,3)
) -- false
print(
	CFrame.fromEulerAngles(1,2,3,Enum.RotationOrder.XYZ)
	==
	CFrame.fromEulerAnglesXYZ(1,2,3)
) -- true
print(
	-- X,Y,Z order
	CFrame.Angles(0,0,3)*CFrame.Angles(0,2,0)*CFrame.Angles(1,0,0)
	==
	CFrame.fromEulerAngles(1,2,3,Enum.RotationOrder.ZYX)
) -- true

From these tests it seems that Enum.RotationOrder.XYZ is doing Z,Y,X order not Enum.RotationOrder.ZYX, and that Enum.RotationOrder.ZYX is actually doing X,Y,Z order. The rotation orders described on the documentation for RotationOrder and fromEulerAngles should be reversed to match the orders described on fromEulerAnglesXYZ and fromEulerAnglesYXZ.

Also, I just noticed that there is a method ToEulerAngles that takes an optional RotationOrder (default Enum.RotationOrder.XYZ) to complement fromEulerAngles.

local x,y,z = CFrame.fromEulerAngles(.5,.6,.7):ToEulerAngles(Enum.RotationOrder.XYZ)
print(
	CFrame.fromEulerAngles(x,y,z,Enum.RotationOrder.XYZ)
	==
	CFrame.fromEulerAngles(.5,.6,.7,Enum.RotationOrder.XYZ)
) -- true

Hi FindFirstChild, thanks for the response and the sample code – – it’s been helpful in trying to get this all sorted out. My takeaway isn’t quite the same as yours, though. My understanding is that the rotation order descriptions on the CFrame page are incorrect and that the ones on RotationOrder are accurate, as one would intuitively hope based on their names.

A variation on your last code sample, where you manually force a particular rotation order, seems to demonstrate this point, but maybe I’m missing something:

local cframe4 = CFrame.fromEulerAnglesXYZ(1, 2, 3)
local cframe5 = CFrame.fromEulerAnglesYXZ(1, 2, 3)
local cframe6 = CFrame.fromEulerAngles(0, 2, 0) * 
	            CFrame.fromEulerAngles(1, 0, 0) *
	            CFrame.fromEulerAngles(0, 0, 3)

print(cframe4 == cframe6) -- false
print(cframe5 == cframe6) -- true

For the fromEulerAngles() calls, we can actually specify any Enum.RotationOrder and get the same result, because of the zeroes and how we’re forcing Y, X, Z order in the multiplication/composition statements.

local cframe4 = CFrame.fromEulerAnglesXYZ(1, 2, 3)
local cframe5 = CFrame.fromEulerAnglesYXZ(1, 2, 3)
local cframe6 = CFrame.fromEulerAngles(0, 2, 0, Enum.RotationOrder.ZYX) *
	            CFrame.fromEulerAngles(1, 0, 0, Enum.RotationOrder.YZX) *
	            CFrame.fromEulerAngles(0, 0, 3, Enum.RotationOrder.ZXY)

print(cframe4 == cframe6) -- false
print(cframe5 == cframe6) -- still true, even with the random enums

Am I misunderstanding something important here? My current plan is to run through the CFrame page, un-reverse all the rotation orders, and add the missing method that you pointed out, but I wanted to check in first and see what you thought. Thanks again!

See Contradictory fromEulerAnglesYXZ Documentation - #3 by NPh_rd

It appearing backwards is the result of the different ordering between roll pitch yaw and euler angles if I remember correctly.

Thanks for the extra context. I did… perhaps too much digging into this and basically came to the conclusion that the technical, mathematical way of approaching rotation order isn’t especially helpful and obscures the information we want to present, which is just, “What does this function do?” I added a bunch of examples that demonstrate equivalency and the behavior of the functions and removed a lot of the “applies the rotations in a given order” statements that were so rooted in matrix math.