What space do CFrames default to (object or world)? Experiencing an oddity with model turning

Recently, I was discussing with another individual about a certain issue regarding CFrames. They came to me stating that they were only turning their object on X and Y axis. I myself am confused by what’s happening and seek an answer, so I’m posting here regarding that.

Image of the camera in a tilted stance:
image

The cameras are being appropriately turned using CFrame.Angles, inputs in radians and turning only along horizontal and vertical axis (up-down, left-right, in simple terms). That being said, it seems that the camera makes odd twisting movements such as the above.

A GIF of what’s happening while the camera is being utilised:
https://gyazo.com/3af44e33b1851a21305227b8d8665d11

As for the assembly of the camera, it is like so:
image

The red block represents the PrimaryPart which serves as the basis for determining where the camera model should be aimed at, while the red ball represents what the CurrentCamera CFrame is set to.

Perhaps its an issue in the way the assembly is created, or what inputs are being applied in the CFrame.Angles method? Maybe it’s in object-space as opposed to world space? Not too sure.

To note, the CFrame.Angles statement looks like this:


If there is not information accompanying this thread to solve this specific problem, then what I’d like to know is what kind of math would be applicable here in order to ensure that my camera is turning in an appropriate mannerism. I’ve created a rough assembly to demonstrate what I seek.

image
(Assembly appearance)

image
(Surface normals for PrimaryPart)


(Camera needs to be able to move vertically, horizontally or do both at the same time. Don’t worry about clamping, I can handle that. What matters is being able to solve the rotation issue.)

5 Likes

Is your problem to do with the camera becoming tilted as if turning your head sideways?

If so, the goal here is to always keep the rightVector of your Camera Model’s PrimaryPart perpendicular to the global y axis, [0, 1, 0]. Your use of CF.Angles is causing the rightVector to lose that orthogonality to [0, 1, 0] which causes the unwanted tilting.

There is a neat way to solve this whilst avoiding any cross products (to obtain perpendicular vectors).

I’m going to assume your oCFrame variable is the initial CFrame of the PrimaryPart which is kept constant throughout the scripts execution.

This solution will work by utilising CFrame.fromEulerAnglesYXZ. If we take a new CFrame (CFrame.new()) and first rotate around it’s upVector (which is 0, 1, 0 for a new CFrame), it’s rightVector will still be perpendicular to the global y-axis after rotation. Then if we rotate around it’s rightVector, the rightVector is unchanged as rotation is performed around itself. So now, these two rotations are enough for up/down & right/left movement of the camera whilst maintaining the orthogonality between rightVector and the global y-axis.

All together, this is doing:
CFrame.new()*CFrame.Angles(0, y, 0)*CFrame.Angles(x, 0, 0)
which is the same as
CFrame.fromEulerAnglesYXZ(x, y, 0).

Great… now all that’s left is to make it start with your initial CFrame of oCFrame.
First, acquire it’s euler angles.
local oX, oY, oZ = oCFrame:ToEulerAnglesYXZ()

Problem: If your initial CFrame, oCFrame, starts off with a bit of twist (i.e. oZ isn’t 0), then you will need to change your oCFrame so that oZ is 0. You don’t want any twist propagating later on.

Finally, bring it all together by changing the line where you set the camera’s CF.

CameraModel:SetPrimaryPartCFrame( CFrame.fromEulerAnglesYXZ(oX + math.rad(CFX), oY + math.rad(CFY), 0) + oCFrame.p)

oCFrame.p is added at end to ensure it’s position stays at the initial CF’s position.

5 Likes

An alternative that assumes you want to rotate about the global y axis (0,1,0) is to use CFrame.fromAxisAngle(Vector3.new(0,1,0), r) for the yaw, and CFrame.Angles for the pitch.

CFrame.fromAxisAngle(Vector3.new(0, 1, 0), y)*CFrame.Angles(x, 0, 0)

is the same as

CFrame.fromEulerAnglesYXZ(x, y, 0)