Jittery :Lerp Camera using BindToRenderStep

I am currently making a isometric camera for a game, and I realized that my camera has slightly jittery movements when I move my character around: (Hard to notice in the video, but it is there!)

Here is the relevant code:

	self._updateCamera = function(deltaTime: number)
		if self._originPart then
			local originPosition: Vector3 = self._originPart.Position + Vector3.new(0, self._height.Value, 0)
			local approximateFPS: number = 1 / deltaTime
			local fpsRatio: number = LERP_ALPHA * (60 / approximateFPS)

			local cameraPosition: Vector3? = if originPosition
				then originPosition + Vector3.new(self._xDepth.Value, self._yDepth.Value, self._zDepth.Value)
				else warn("[IsometricCamera] Camera point does not exist!")

			if cameraPosition then
				camera.CFrame =
					camera.CFrame:Lerp(CFrame.lookAt(cameraPosition, originPosition), math.clamp(fpsRatio, 0, 1))
			end
		end
	end

-- Setting the camera
	camera.CameraType = Enum.CameraType.Scriptable
	camera.FieldOfView = DEFAULT_FOV

	RunService:BindToRenderStep(BIND_RENDER_NAME, Enum.RenderPriority.Camera.Value + 1, self._updateCamera)

I’ve tried using RenderStepped, but seemed to replicate the same results. I reckon that it has to do something with a delay in the rendering resulting in the previous frame being calculated. Again, I am not too sure and would appreciate help and any code examples :slightly_smiling_face:

1 Like

Just an idea but try using Heartbeat.

Unfortunately, Heartbeat shouldn’t work because it only runs after the frame is rendered. (Which is why I went with RenderStepped and BindToRenderStepped)

I have also tested it, and the jittery results remain.

Yeah, that was just an idea since it’ll render specifically to that client’s runtime. I’ll look into your problem though and see what I can dig up.

1 Like

Sometimes i use TweenService, just a thought tho

Use this instead of the built in Lerp function.

Make a function that says :

local function lerp(a, b, t)
	return a + ( b - a ) * t
end

So now, the code should look like this.

local function lerp(a, b, t)
	return a + (b - a) * t
end

self._updateCamera = function(deltaTime: number)
	if self._originPart then
		local originPosition: Vector3 = self._originPart.Position + Vector3.new(0, self._height.Value, 0)
		local approximateFPS: number = 1 / deltaTime
		local fpsRatio: number = LERP_ALPHA * (60 / approximateFPS)

		local cameraPosition: Vector3? = if originPosition
			then originPosition + Vector3.new(self._xDepth.Value, self._yDepth.Value, self._zDepth.Value)
			else warn("[IsometricCamera] Camera point does not exist!")

		if cameraPosition then
			local camCFrame = lerp(camera.CFrame, CFrame.lookAt(cameraPosition, originPosition, math.clamp(fpsRatio, 0, 1))
			
			camera.CFrame = camCFrame
		end
	end
end

-- Setting the camera
camera.CameraType = Enum.CameraType.Scriptable
camera.FieldOfView = DEFAULT_FOV

RunService:BindToRenderStep(BIND_RENDER_NAME, Enum.RenderPriority.Camera.Value + 1, self._updateCamera)

Your welcome.

This usually occurs when there’s a visual update after the camera has been positioned.

Try setting the RenderPriority to Last.

Just as a note, I think your priority value may be incorrect as well.

RunService:BindToRenderStep(BIND_RENDER_NAME, Enum.RenderPriority.Camera.Value + 1, self._updateCamera)

If Camera == 200, 201 may still equal Camera.

1 Like

Can confirm, I am also experiencing this problem.

Tried all of the following without any luck:

  • Using Stepped, RenderStepped and Heartbeat.
  • Getting and using the Stepped and RenderStepped deltas.
  • Using many different RenderPriorities (including before camera).
  • Getting the delta from a separate thread.
  • Using a custom lerp function (although I am almost certain the issue lies with RunService).

I am lerping the position of a part and incorporating the delta in the speed calculation.

I have also ruled out the issue been the camera and determined it’s an issue with the part movement.

The problem is that every 5-6 seconds there will be a period of micro stuttering. I assume it has something to do with tasks been scheduled at that point in the frame?

I am going to have to do some exploring with the MicroProfiler but I don’t think there is much I can do to solve it.

Any support or ideas would be much appreciated.
Thanks

I’ve created a demo that shows the micro stuttering with a stationary camera and a lerping part:
RunServiceJitterDemo.rbxl (37.6 KB)

It’s most noticeable on a 60hz monitor and in a live experience.

You should see after a few seconds some jittering then it will return to smooth for a few seconds before repeating.

Scripts can be found in StarterPlayer\StarterPlayerScripts.