Jittering effect when tweening Camera in RenderStepped

Hi! This is my first post here; really trying to dig my feet into Roblox game development and (at least so far) I’m hooked. Bear this in mind too as I’m sure my code isn’t exactly “good” by most people’s standards, but I’m always willing to learn! ^^

I’m currently facing an issue wherein I am attempting to have a delayed/smoothed camera effect utilizing a tween, but this is resulting in jitter. I’ve read through various different threads which have suggested a few variety of fixes, of which include calculating the interpolation in RenderStepped and then applying it in Stepped or Heartbeat. Switching to either of these not only does not remove the jitter, but they also affect the way the camera sits for some reason! Unfortunately I haven’t found any solution yet that works or that I understand.

Here is my code:

-- Camera
local Camera            = game.Workspace.CurrentCamera
	  Camera.CameraType = Enum.CameraType.Fixed
	  
local CameraPart              = Instance.new("Part", Camera)
	  CameraPart.Name         = "CameraPart"
	  CameraPart.Anchored     = true
	  CameraPart.Transparency = 1
	
-- Player
local Player    = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
	  
-- Variables
local Zoom = 40
local Tilt = -60

-- Initialize the stuff
rootPos = Character.HumanoidRootPart.Position
CameraPart.Position = Vector3.new(rootPos.x, rootPos.y + Zoom, rootPos.z + Zoom/1.75)

RunService.RenderStepped:Connect(function()
	if Character then
		if Character:FindFirstChild("HumanoidRootPart") then
			
			rootPos = Character.HumanoidRootPart.Position
			game:GetService("SoundService"):SetListener(Enum.ListenerType.ObjectCFrame, Character.HumanoidRootPart)
			
			-- Handles camera position
			local CameraTarget = { Position = Vector3.new(rootPos.X, rootPos.Y + Zoom, rootPos.Z + Zoom/1.75) }
			local CameraSmooth = TweenService:Create(CameraPart, TweenInfo.new(.3), CameraTarget):Play()

			Camera.CFrame = CFrame.new(CameraPart.Position) * CFrame.Angles(math.rad(Tilt), 0, 0)
			
		end
	end
end)

Camera.CameraSubject = CameraPart

Here’s a video demonstrating my issue:

1 Like

The camera is constantly being tweened every frame, which causes that jittering effect.

Instead, use a formula like this:

local Speed = 5
...
local target = CFrame.new(rootPos.X, rootPos.Y + Zoom, rootPos.Z + Zoom/1.75)
Camera.CFrame += (Camera.CFrame - target) / Speed

Code Changes:

‌-- Camera
local Camera            = game.Workspace.CurrentCamera
	  Camera.CameraType = Enum.CameraType.Fixed
	  
local CameraPart              = Instance.new("Part", Camera)
	  CameraPart.Name         = "CameraPart"
	  CameraPart.Anchored     = true
	  CameraPart.Transparency = 1
	
‌-- Player
local Player    = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
	  
‌-- Variables
local Zoom = 40
local Tilt = -60
+	local Speed = 5

‌-- Initialize the stuff
rootPos = Character.HumanoidRootPart.Position
CameraPart.Position = Vector3.new(rootPos.x, rootPos.y + Zoom, rootPos.z + Zoom/1.75)

RunService.RenderStepped:Connect(function()
	if Character then
		if Character:FindFirstChild("HumanoidRootPart") then
			
			rootPos = Character.HumanoidRootPart.Position
			game:GetService("SoundService"):SetListener(Enum.ListenerType.ObjectCFrame, Character.HumanoidRootPart)
			
			-- Handles camera position
-				local CameraTarget = { Position = Vector3.new(rootPos.X, rootPos.Y + Zoom, rootPos.Z + Zoom/1.75) }
-				local CameraSmooth = TweenService:Create(CameraPart, TweenInfo.new(.3), CameraTarget):Play()
-				
-				Camera.CFrame = CFrame.new(CameraPart.Position) * CFrame.Angles(math.rad(Tilt), 0, 0)
+				local target = CFrame.new(rootPos.X, rootPos.Y + Zoom, rootPos.Z + Zoom/1.75)
+				Camera.CFrame += (Camera.CFrame - target) / Speed
			
		end
	end
end)

Camera.CameraSubject = CameraPart

Actual code:

-- Camera
local Camera            = game.Workspace.CurrentCamera
	  Camera.CameraType = Enum.CameraType.Fixed
	  
local CameraPart              = Instance.new("Part", Camera)
	  CameraPart.Name         = "CameraPart"
	  CameraPart.Anchored     = true
	  CameraPart.Transparency = 1
	
-- Player
local Player    = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
	  
-- Variables
local Zoom = 40
local Tilt = -60
local Speed = 5

-- Initialize the stuff
rootPos = Character.HumanoidRootPart.Position
CameraPart.Position = Vector3.new(rootPos.x, rootPos.y + Zoom, rootPos.z + Zoom/1.75)

RunService.RenderStepped:Connect(function()
	if Character then
		if Character:FindFirstChild("HumanoidRootPart") then
			
			rootPos = Character.HumanoidRootPart.Position
			game:GetService("SoundService"):SetListener(Enum.ListenerType.ObjectCFrame, Character.HumanoidRootPart)
			
			-- Handles camera position
			local target = CFrame.new(rootPos.X, rootPos.Y + Zoom, rootPos.Z + Zoom/1.75)
			Camera.CFrame += (Camera.CFrame - target) / Speed
			
		end
	end
end)

Camera.CameraSubject = CameraPart
2 Likes

This did wonders, thank you so much!

In adapting it to work with the code that I had, instead of using a CFrame I used a Vector3 and applied that to the CameraPart’s position rather than the Camera itself. (This was necessary as I also have code which affects the Camera orientation and any direct-Camera implementation I tried kind of made it freak out :P) Additionally I found that the speed needed to be set to a negative number or else the camera would quite literally fling itself off into space at exponential speeds. Though I’m certain my camera implementation isn’t the most elegant, this was a very simple fix and I appreciate you offering advice so quickly!

1 Like

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