Prevent camera shaking when reaching max and min orientation

runService:BindToRenderStep("LimitOrientation", Enum.RenderPriority.Camera.Value, function()
    local rX, rY, rZ = camera.CFrame:ToOrientation()
    local limY = math.clamp(math.deg(rY), 45, 135)
    print(limY)
    camera.CFrame = CFrame.new(camera.CFrame.p) * CFrame.fromOrientation(rX, math.rad(limY), rZ)    
end)

Is there any way for me to prevent camera shaking when it reaches the max and min orientation?

  1. CFrame::ToOrientation is an alias for CFrame::ToEulerAnglesYXZ so you should be doing rY, rX, rZ = CFrame:ToOrientation()

  2. I think it is easiest to just fork the CameraModule and edit the MIN_Y and MAX_Y locals.

Do a play test and copy the PlayerModule from your player’s PlayerScripts then stop the play test and paste it into StarterPlayerScripts. From here you can make changes to the CameraModule.

ex. Only allow rotation from -30 to 30 degrees

And if you want to also limit the X axis you need to add some new locals like MIN_X and MAX_X and apply the following changes to BaseCamera::CalculateNewLookCFrameFromArg

function BaseCamera:CalculateNewLookCFrameFromArg(suppliedLookVector: Vector3?, rotateInput: Vector2): CFrame
    local currLookVector: Vector3 = suppliedLookVector or self:GetCameraLookVector()
    local currPitchAngle = math.asin(currLookVector.Y)
    local yTheta = math.clamp(rotateInput.Y, -MAX_Y + currPitchAngle, -MIN_Y + currPitchAngle)
    local currYawAngle = math.asin(currLookVector.X)
    local xTheta = math.clamp(rotateInput.X, -MAX_X + currYawAngle, -MIN_X + currYawAngle)
    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

Forking the camera module isn’t an option in my case because I need to be able to switch between the player’s normal camera and a ball camera (hence why I’m using BindToRenderStep).

You could try limiting it before and after the camera. If done at the correct time your code should work, it uses the same principle as every camera shake module I’ve read.

runService:BindToRenderStep("LimitOrientation", Enum.RenderPriority.Camera.Value-1, function()
    local rX, rY, rZ = camera.CFrame:ToOrientation()
    local limY = math.clamp(math.deg(rY), 45, 135)
    print(limY)
    camera.CFrame = CFrame.new(camera.CFrame.p) * CFrame.fromOrientation(rX, math.rad(limY), rZ)    
end)
runService:BindToRenderStep("LimitOrientation", Enum.RenderPriority.Camera.Value+1, function()
    local rX, rY, rZ = camera.CFrame:ToOrientation()
    local limY = math.clamp(math.deg(rY), 45, 135)
    print(limY)
    camera.CFrame = CFrame.new(camera.CFrame.p) * CFrame.fromOrientation(rX, math.rad(limY), rZ)    
end)

You might only need one of those two, probably the one with the Enum.RenderPriority.Camera.Value+1 priority.

I think the problem might be that your code is set to the same priority as the regular camera positioning, so it’s a toss up which one runs first.

What is stopping you from adding a flag to check if you are currently on ball camera or not?

ex.

function BaseCamera:CalculateNewLookCFrameFromArg(suppliedLookVector: Vector3?, rotateInput: Vector2): CFrame
    local min_x, max_x = MIN_X, MAX_X
    local min_y, max_y = MIN_Y, MAX_Y
    if isBallCam then
        min_x, max_x = BALL_CAM_MIN_X, BALL_CAM_MAX_X
        min_y, max_y = BALL_CAM_MIN_Y, BALL_CAM_MAX_Y
    end
    local currLookVector: Vector3 = suppliedLookVector or self:GetCameraLookVector()
    local currPitchAngle = math.asin(currLookVector.Y)
    local yTheta = math.clamp(rotateInput.Y, -max_y + currPitchAngle, -min_y + currPitchAngle)
    local currYawAngle = math.asin(currLookVector.X)
    local xTheta = math.clamp(rotateInput.X, -max_x + currYawAngle, -min_x + currYawAngle)
    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
1 Like

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