How to make lerp consistent for all fps when using renderstepped

Hey, I have this first-person view model where one of the things I’m utilizing is a position offset, which works fine when I’m running at 60 fps, but consistently gets a lower speed or alpha value when using a higher fps. Of course, that is because the delta time is “1/fps”, but if I try to use a formula that increases the alpha value for a higher frame rate, it just results in the lerp being super laggy. Does anyone know how to resolve this issue? Otherwise, I will just have to cap the fps at 60.

Here is the renderstepped part of my script:
(ignore the last but with the movement detection)

service = RenderStepped.PreRender:Connect(function(dt)
	local moved = false
	local noisemovment = false
	local newposition = character:WaitForChild("HumanoidRootPart").CFrame
	local lerpFactor = 1-math.pow(0.5,10*dt)
	
	local camFrame = game:GetService("Workspace").CurrentCamera.CFrame
	local newposition = newposition:toObjectSpace(initialPosition)
	local cccf_data = camFrame:toObjectSpace(lastCameraCF)
	local x, y, z = cccf_data:ToOrientation()
	
	if shooting then
		X, Y , Z = x, y, z
	else
		X, Y , Z = 0 ,0 , 0
	end
	
	script.Parent.HumanoidRootPart.CFrame = camFrame + camFrame.LookVector * 3 + camFrame.UpVector * 3+ camFrame.RightVector * 3 
	
	--//swayoffset position
	local targetCFrame = CFrame.new(cccf_data.Position/(6+lower_offset_effect))
	postionOffset = postionOffset:Lerp(targetCFrame,dt*4)
	print(dt*4)
	script.Parent.HumanoidRootPart.CFrame = workspace.CurrentCamera.CFrame * postionOffset
	
	--//swayoffset rotation
	swayOffset = swayOffset:Lerp(CFrame.Angles(math.sin(x * 3.5) * mult, math.sin(y * 3.5) * mult, 0), 0.1) 
	local characterCFrame = script.Parent.HumanoidRootPart.CFrame
	local localSwayOffset = characterCFrame:toObjectSpace(characterCFrame * swayOffset)
	script.Parent.HumanoidRootPart.CFrame = characterCFrame * localSwayOffset
	-- Update cumulativeRotation
	cumulativeRotation = cumulativeRotation:Lerp(CFrame.Angles(X*mult*2, Y*mult*2, Z*mult*2), 0.1)
	 
	-- Update lastCameraCF with cumulative rotation
	lastCameraCF = workspace.CurrentCamera.CFrame * cumulativeRotation + workspace.CurrentCamera.CFrame.LookVector * xvectorvalue

	-- Apply cumulative rotation to the camera's CFrame
	workspace.CurrentCamera.CFrame = lastCameraCF
	
	--movrement detection
	if math.abs(newposition.z) > 0.005 or math.abs(newposition.x) > 0.005 then
		moved = true
		falsecounter = 0
	else
		falsecounter += 1
	end

	if moved == true or falsecounter < 6 then
		noisemovment = true
	end
	initialPosition = character.HumanoidRootPart.CFrame
	if not isAnyAnimationPlaying() then
		if noisemovment and not walkPlaying then
			walk:Play()	
			walkPlaying = true
		elseif not noisemovment and walkPlaying then
			walk:Stop()
			idle:Play()
			walkPlaying = false
		end
	elseif walkPlaying then
		walk:Stop()
		walkPlaying = false
	end
end)
1 Like

“dt” is returned by the renderstepped, which is the time between frames. Multiply the lerp function by DT

cframe:Lerp(…) * dt

but I can’t multiply a vector with a number


postionOffset = postionOffset:Lerp(targetCFrame,4)*dt

i believe you can multiply the speed. postionOffset = postionOffset:Lerp(targetCFrame,4*dt)

But that is exactly what I’m already doing in the script. However, as you can see in the video, the amount of position offset isn’t the same for all frame rates when using:
postionOffset = postionOffset:Lerp(targetCFrame,4*dt)

Have you tried applying the lerpfactor to all your lerp formulas such as cumulativeRotation which is still being lerped by 0.1?

for this other formula it doesn’t matter cause it’s using mult which works fine for rotation, but it doesn’t work for 3d vectors thought.

Doing * dt * 60 should work.

I’m a bit confused, do you mean like this?
postionOffset = postionOffset:Lerp(targetCFrame,dt * 60 )

Kind of. You usually use the actual alpha you want, followed by the thing I said in the reply.

Like this:

postionOffset = postionOffset:Lerp(targetCFrame, 0.1 * dt * 60)

use while loop instead, you can make while loop run at specific speed

local FPS = 60
while true do
    -- code
    task.wait(1/FPS)
end

EDIT:
In FPS settings post they gave example of code to use

local RunService = game:GetService("RunService")

local DEGREES_PER_SECOND = 60

-- delta is the number of seconds since the last PostSimulation call
RunService.PostSimulation:Connect(function(delta)
    script.Parent.CFrame *= CFrame.Angles(0, math.rad(DEGREES_PER_SECOND) * delta, 0)
end)

When I tried using a while loop, it made everything super laggy. I guess that’s because the while loop doesn’t update at the exact frame rate, so the update of the loop will be out of sync with every rendered frame of the game, causing major lag. Even if the loop is updated at 1000Hz, it still lags.

I also tried using “RunService.PostSimulation,” and that also caused the viewmodel to be laggy. Do you know if there is anything I could use with PostSimulation for 3D vectors to make it look smooth? (The smooth rotation already works fine.)

Using this doesn’t really solve the issue, there is still a difference in the amount of position offset for different frame rates.

The problem with your code is that you use (delta-time) directly as a rate multiplier in the . When the frame rate (FPS) increases, it decreases, which slows down the animation. The solution is to switch to using the speed in units of “units/second” rather than “units/frame”.

Instead of multiplying by a number that represents speed, enter separate variables for the rate of position change and rotation. These variables will represent the speed in units/second. Then, in each iteration, multiply these velocities by to get the change for the current frame.(wrote through a translator)

Okey, I’m not sure how exactly I should do this could you maybe show some an example of some code?

Add speed variables: Outside the function, add two variables:

local swaySpeed = 4 --idk
local rotationSpeed = 10 --idk

Change this:

postionOffset = postionOffset:Lerp(targetCFrame,dt*4)

To this:

postionOffset = postionOffset:Lerp(targetCFrame, swaySpeed * dt)

replace this:

swayOffset = swayOffset:Lerp(CFrame.Angles(math.sin(x * 3.5) * mult, math.sin(y * 3.5) * mult, 0), 0.1)

With this:

swayOffset = swayOffset:Lerp(CFrame.Angles(math.sin(x * 3.5) * mult, math.sin(y * 3.5) * mult, 0), rotationSpeed * dt)

I can’t promise that it will work, but it’s a logical solution (sort of)

1 Like

I hope you understand that the numbers need to be adjusted to their values, right?

have tried it out but it doesn’t sadly it doesn’t fix anything, cause for the position offset doing this:
postionOffset = postionOffset:Lerp(targetCFrame, 4* dt)
and this:

local swaySpeed = 4
postionOffset = postionOffset:Lerp(targetCFrame, swaySpeed* dt)

gives the same result and yes I have tried using different values for swaySpeed.

local  Time = 0
repeat 
    Time += RunService.Heartbeat:Wait() -- lerping with time, it needs 1 second to complete
    positionOffset = positionOffset:Lerp(targetPosition, Time)

until Time >= 1

how should it be implemented in the script, cause this doesn’t work:
local targetCFrame = CFrame.new(cccf_data.Position/(6+lower_offset_effect))

RunService.RenderStepped:Connect(function(dt)
        
	local  Time = 0
	repeat 
		Time += RunService.Heartbeat:Wait() -- lerping with time, it needs 1 second to complete
		postionOffset = postionOffset:Lerp(targetCFrame,dt*4)
		

	until Time >= 1
	
	print(dt*4)
	script.Parent.HumanoidRootPart.CFrame = workspace.CurrentCamera.CFrame * postionOffset
	
	
	local localpostionOffset = workspace.CurrentCamera.CFrame:toObjectSpace(workspace.CurrentCamera.CFrame * postionOffset)
end)
1 Like