How do I stop camera from rotating on Z axis?

Hi,
I’m trying to make a custom camera script where you can look around using your mouse.

UIS.InputChanged:Connect(function(input)
	if (lastMousePos and input.UserInputType == Enum.UserInputType.MouseMovement) then
		local pos = UIS:GetMouseLocation()
		local yDiff, xDiff = lastMousePos.Y - pos.Y, lastMousePos.X - pos.X	
		camera.CFrame *= CFrame.Angles(math.rad(yDiff / 3), math.rad(xDiff / 3), 0)
		lastMousePos = pos
	end
end)

This is what I made but it also moves the camera crosswise which looks weird.
https://gyazo.com/20d58b4fe2d5589604202cc9672c3318

I tried to zero out the Z axis every time the CFrame changes.
It’s a bit better but still makes the camera do some weird rotation.
https://gyazo.com/357e66c2160e5dfd328769397b27504a

local function RemoveZRotation(cframe)
	local x, y, z = cframe:ToOrientation()
	return CFrame.new(cframe.Position) * CFrame.Angles(x,y,0)
end

UIS.InputChanged:Connect(function(input)
	if (lastMousePos and input.UserInputType == Enum.UserInputType.MouseMovement) then
		local pos = UIS:GetMouseLocation()
		local yDiff, xDiff = lastMousePos.Y - pos.Y, lastMousePos.X - pos.X	
		local newRot = camera.CFrame * CFrame.Angles(math.rad(yDiff / 3), math.rad(xDiff / 3), 0)
		camera.CFrame = RemoveZRotation(newRot)
		lastMousePos = pos
	end
end)

Could I get some help, please?

3 Likes

It kinda makes sense that you get some roll. Try holding out your hand flat, pitch it up by e.g. 45 deg, then yaw it on its local Y axis by 90 degrees. Your hand should end up with 0 pitch but 45 deg of roll!

To prevent this, you shouldn’t yaw on the camera’s local Y axis, but around the world Y axis. Since cf * CFrame.angles(pitch, yaw, roll) rotates on the axes relative to cf (in a specific order of pitch/yaw/roll, don’t remember which), we need to transform the yaw rotation from world space to the camera’s local space.

In code this looks like:

function pitchCFrame(cf, amount)
    --Don't transform to world space, since pitching up/down is supposed to be around the local X axis
    return cf * CFrame.Angles(amount, 0, 0) 
end

function yawCFrame(cf, amount)
    --Transform to local space, since yawing left/right needs to be around global Y axis
    return cf * cf:ToObjectSpace(CFrame.Angles(0, amount, 0))
end

You can call these functions with yDiff and xDiff from your UIS.InputChanged listener. E.g.:

UIS.InputChanged:Connect(function(input)
	if (lastMousePos and input.UserInputType == Enum.UserInputType.MouseMovement) then
		local pos = UIS:GetMouseLocation()
		local yDiff, xDiff = lastMousePos.Y - pos.Y, lastMousePos.X - pos.
		lastMousePos = pos

                camera.CFrame = pitchCFrame(camera.CFrame, yDiff)
                camera.CFrame = yawCFrame(camera.CFrame, xDiff)
	end
end)

I think this should work, don’t have Studio on this PC so can’t test it right now. Let me know if it has issues!

6 Likes

Thank you for response!
Hm, it seems like the Y axis is working fine but X axis moves my camera to completly different location. Also, I can’t rotate the camera on the X axis. I used your code but also tried to ‘invent’ something myself, sadly the camera goes crazy after I change anything.

3 Likes

Old thread but this may help someone