Clamping camera X rotation

  1. What do you want to achieve? Keep it simple and clear!
    I want to limit camera to rotate mostly to one side than other, like in this video:


    I need to make It make camera rotatation don’t go to the left completely and turn almost all the way around to the right.

  2. What is the issue? Include screenshots / videos if possible!
    Basically it looks like this:

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried doing this in BaseCamera module that is in PlayerModule:

function BaseCamera:CalculateNewLookCFrameFromArg(suppliedLookVector: Vector3?, rotateInput: Vector2): CFrame
    local currLookVector: Vector3 = suppliedLookVector or self:GetCameraLookVector()
    local currPitchAngle = math.asin(currLookVector.Y)
    local currPitchAngleX = math.asin(currLookVector.X)
    if player.Character and player.Character.Humanoid:GetAttribute("Gripping") then
        if MAX_X == math.rad(90) and MIN_X == math.rad(-90) then
            local rX,rY,rZ = workspace.CurrentCamera.CFrame:ToOrientation()
            MAX_X = math.rad(rX + 45)
            MIN_X = math.rad(rX - 10)
        end

        MAX_Y = math.rad(30)
        MIN_Y = math.rad(-60)
    else
        MIN_Y = math.rad(-80)
        MAX_Y = math.rad(80)
        MAX_X = math.rad(90)
        MIN_X = math.rad(-90)
    end
    local yTheta = math.clamp(rotateInput.Y, -MAX_Y + currPitchAngle, -MIN_Y + currPitchAngle)
    local xTheta = math.clamp(rotateInput.X, -MAX_X + currPitchAngleX, -MIN_X + currPitchAngleX)
    local constrainedRotateInput = Vector2.new(xTheta, yTheta)
    local startCFrame = CFrame.new(ZERO_VECTOR3, currLookVector)
    local newLookCFrame = CFrame.Angles(0, -constrainedRotateInput.X, 0) * startCFrame * CFrame.Angles(-constrainedRotateInput.Y,0,0)
    return newLookCFrame
end

i believe (correct me if im wrong) that

CFrame:ToOrientation()

returns angles in radians but when you do

local rX,rY,rZ = workspace.CurrentCamera.CFrame:ToOrientation()
MAX_X = math.rad(rX + 45)
MIN_X = math.rad(rX - 10)

it looks like your assuming that it returns degrees. that could the problem.

1 Like

Hm,. yes, you are right. But it doesn’t even limit the camera now.

There’s probably a better way to do this, but it works and what this does is that it limits the X axis

local Camera = workspace.CurrentCamera

local X_Min = -30
local X_Max = 30

game:GetService("RunService").RenderStepped:Connect(function()
    local CameraPitch,_,_ = Camera.CFrame:ToOrientation()
    local XInDegrees = math.deg(CameraPitch)
    
    local ClampedX = math.clamp(XInDegrees,X_Min,X_Max)
    
    local dif = XInDegrees - ClampedX
    
    if dif > 0.1 or dif < -0.1 then
        Camera.CFrame *= CFrame.Angles(math.rad(-dif),0,0)
    end
end)
1 Like

NVM, I forgot to turn the degree into radian too, but it still works like at the first video.

Let me try that out and I’ll let you know how it goes.

It limits camera rotatation based on up and down movement, and I want to limit it going to the left completely and turn almost all the way around to the right.

This works, but how would I make it limit the camera rotation correctly?

so i think the reason why his script is clamping the y instead of the x is because ToOrientation (i actually just found this out) is apparently mimicking the ToEulerAnglesYXZ instead of the ToEulerAnglesXYZ. the difference being the y and x are flipped. i have no clue why roblox decided to make it output in yxz form instead of xyz form but it is what it is i guess so bassically just change

local CameraPitch,_,_ = Camera.CFrame:ToOrientation()

to

local _,CameraPitch,_ = Camera.CFrame:ToOrientation()

and now it should work perfectly.
anyway i tried testing this in studio and to my suprise… it didnt work.
so after lots of random testing and looking around on the documentation page i finally realized that in this line

Camera.CFrame *= CFrame.Angles(math.rad(-dif),0,0)

if you swap the 1st and second params so it looks like this

Camera.CFrame *= CFrame.Angles(0,math.rad(-dif),0)

it works. i have no clue why CFrame.Angles seems to be using yxz format because on the documentation it actually says it should be zyx but in game it says xyz but actually its yxz so honestly i have no idea anymore which it is but all you need to know is that the second of these two lines makes it work for some reason.

TLDR:
this works

local Camera = workspace.CurrentCamera

local X_Min = -30
local X_Max = 30

game:GetService("RunService").RenderStepped:Connect(function()
	local _,CameraPitch,_ = Camera.CFrame:ToOrientation()
	local XInDegrees = math.deg(CameraPitch)

	local ClampedX = math.clamp(XInDegrees,X_Min,X_Max)

	local dif = XInDegrees - ClampedX

	if dif > 0.1 or dif < -0.1 then
		Camera.CFrame *= CFrame.Angles(0,-math.rad(dif),0)
	end
end)

I thought you meant the Pitch/Up and Down Axis. Since, the post title said X rotation… so… I was confused since X is Pitch in Orientation. Anyways, here’s what you wanted.

local Camera = workspace.CurrentCamera

local Y_Min = -30
local Y_Max = 30

local Player = game.Players.LocalPlayer
local Character = Player.Character
local Root = Character.HumanoidRootPart

game:GetService("RunService").RenderStepped:Connect(function()
    local _,RootYaw,_ = Root.CFrame:ToOrientation()
    local RootYawInDeg = math.deg(RootYaw)
    
    local Y_CalculatedMin = RootYawInDeg + Y_Min
    local Y_CalculatedMax = RootYawInDeg + Y_Max
    
    local _,CameraYaw,_ = Camera.CFrame:ToOrientation()
    local YInDegrees = math.deg(CameraYaw)
    
    local ClampedY = math.clamp(YInDegrees,Y_CalculatedMin,Y_CalculatedMax)
    
    local dif = YInDegrees - ClampedY
    
    if dif > 0.1 or dif < -0.1 then
        Camera.CFrame *= CFrame.Angles(0,math.rad(-dif),0)
    end
end)

Make sure to only use this when the Character’s Root Can’t rotate left and right or else it’ll look weird… (example, when climbing, sitting, or when the humanoid has autorotate off.) since the Rotation Limit is related to the Character HumanoidRootPart.

It should look like this after you apply it, there’s a little bit of jitter when the camera reaches the rotation limit but I’ll leave it to you to fix it.

When I rotate to the limit, it just makes my camera glitch and it doesn’t let me move it to left or right at all. maybe cause of what limits I’ve set?

This kinda worked, but when i tried tweaking the limit so it was able to go to the right more than left, this happens:

basically I set max to 10 and minimum to 70

            local _,RootYaw,_ = HumanoidRootPart.CFrame:ToOrientation()

            local RootYawInDeg = math.deg(RootYaw)

            local Y_CalculatedMin = RootYawInDeg + -70
            local Y_CalculatedMax = RootYawInDeg + 10

            local _, CameraYaw,_ = Camera.CFrame:ToOrientation()
            local YInDegrees = math.deg(CameraYaw)

            local ClampedY = math.clamp(YInDegrees, Y_CalculatedMin, Y_CalculatedMax)

            local Difference = YInDegrees - ClampedY

            if Difference > 0.1 or Difference < -0.1 then
                Camera.CFrame *= CFrame.Angles(0,math.rad(-Difference),0)
            end

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.