Rotating a CFrame by a set of angles the correct way


This problem is in most cases trivial, solved with CFrame*CFrame.Angles(x,y,z)
However, this solution proves to be inadequate for performing rolls and tilts beyond 90 degrees with an aircraft: The direction of rotation will be briefly reversed, causing a jolt in the manoeuvre and possibly preventing it entirely.

This bug occurs as a result of storing angles above 180 degrees as negatives: It means that every 180 degrees of a turn will have a sign switch, which will cause an unexpected result with the maths.

Anyone know how I can solve this? Unfortunately, when the angles are stored in a CFrame, I can’t do anything about them being negative; they’re converted to the buggy signed format when the CFrame is created.

It turns out that what I was encountering was a bug with BodyGyro, CFrames are fine.


This article might be useful for you.


That got me some odd results, certainly nothing useful.


AxisAngles are probably better for your use case.

Try those, instead of CFrame.Angles


That’s what the last answer said.


I’m pretty rusty when it comes to this stuff, but CFrame.Angles shouldn’t have any problems with continuity. ROBLOX doesn’t actually store any angles; it only stores the resulting matrices. It sounds to me like you’re using CFrame.toEulerAnglesXYZ, which would cause the problems you describe.

As the name suggests, toEulerAnglesXYZ computes the angles as if they were applied about the X-axis first, then the Y- and Z-axes. What you need is YZX angles, which will work as long as no one tries to pitch the aircraft 90 degrees up or down. I wrote some code to do this:

local _, _, _, m00, m01, m02, m10, m11, m12, m20, m21, m22 = cframe:components()
local Y = math.atan2(m20, m00)
local Z = math.asin(m10)
local X = math.atan2(m11, -m12)
-- replicate cframe given Y,Z,X
cframe = CFrame.Angles(0,Y,0)*CFrame.Angles(0,0,Z)*CFrame.Angles(X,0,0)

You should always check to make sure that the magnitude of m10 is sufficiently less than 1 (say less than 0.999). That would indicate the orientation being vertical, which screws things up.

I haven’t done this in awhile, but I believe the above code should work.


I said though that the problem I was having occurs with a 90 degree pitch. Clearly, I want to be able to use a 90 degree pitch.


Okay, but there’s no reason you should need 90 degree pitches. You can’t have 90 degree turns, rolls, and tilts at the same time, at least not with Euler angles. If you limit one of these rotations to be at most 90 degrees minus a small amount, you can have a full range of motion in the other two, provided that you choose the right coordinate system.

If you wanted a full range of motion with no discontinuities, the best idea I could think of is to have a fourth axis of rotation, but that’d make things complicated as you’re dealing with redundant degrees of freedom.