I’m trying to position a knife on the player’s torso. In the command line I’ve written this and for some reason the x and z axis are rotating on the same axis.
local knife = workspace.Knife
local torso = workspace.Dummy.UpperTorso
knife.CFrame = torso.CFrame * CFrame.Angles(math.rad(0), math.rad(90), math.rad(0))
Yes, this is a well known problem. Euler angles (the standard XYZ angles you’re familiar with) have infinite solutions for a given orientation. Usually this results in “Gimbal lock.”
You cannot use XYZ angles in refined cases like this. You must use a matrix or an axis angle.
So in the first, you’re rotating about Z by 45 and then about Y by 90.
In the second, you rotate about 90 on Y and then X by 45.
Both of those end up the same.
Solution:
You can explicitly control which one gets multiplied first:
-- force rotate on Z before Y (this is the default but we can make it explicit)
torso.CFrame * CFrame.Angles(0, 0, math.rad(45)) * CFrame.Angles(0, math.rad(90), 0)
-- force rotate on X before Y
torso.CFrame * CFrame.Angles(math.rad(45), 0, 0) * CFrame.Angles(0, math.rad(90), 0)
Or use fromOrientation/fromEulerAnglesYXZ, which applies rotations in Y, X, Z order.
-- always rotate Y first and then X or Z so these give different answers
knife.CFrame = torso.CFrame * CFrame.fromOrientation(0, math.rad(90), math.rad(45))
knife.CFrame = torso.CFrame * CFrame.fromOrientation(math.rad(45), math.rad(90), 0)