Smooth Vehicle Camera

Hello, I’ve been trying to make a custom smooth camera for my vehicle but somehow when I set the camera cframe to a camera part cframe to make it follow, it looks have it has a “glitch” effect, I use lerp by the way, does someone know a solution for making the camera move a basepart smoothly when that basepart is in moviment?
Sorry for my bad english.

Video:

My code part:

RunService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value - 1, function(deltaTime)
   Camera.CFrame = Camera.CFrame:Lerp(CameraPart.CFrame, 5 * deltaTime)
end)
5 Likes

It seems like you are on the right track with using lerp to smoothly interpolate the camera’s CFrame towards the target position. However, the “glitch” effect you’re experiencing might be due to the high interpolation factor you are using, a large interpolation factor can cause sudden jumps in the camera movement.

local RunService = game:GetService("RunService")

local Camera = game.Workspace.CurrentCamera
local CameraPart = -- Replace this with your camera target (basepart)

local cameraSpeed = 0.1 smoother movement)

RunService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value - 1, function(deltaTime)
    local newCFrame = CameraPart.CFrame
    local currentCFrame = Camera.CFrame

    Camera.CFrame = currentCFrame:Lerp(newCFrame, cameraSpeed)

end)
3 Likes

This is the same thing I did, still has the same result as the video I showed on. If you try out making a vehicle and then make a smooth camera transition you will have the same result, I want to make a high speed to make it actually locked on the car but with a smooth transition as like that video:

So, my problem is that, the higher speed, the more “glitch” it does cause.

2 Likes

Try using .RenderStepped instead. Might give you more speedy updates?

3 Likes

Ah I see, my mistake. I changed the code a bit to make it less glitchy, hopefully this does the job.

local RunService = game:GetService("RunService")

local Camera = game.Workspace.CurrentCamera
local CameraPart = -- Replace this with your camera target (basepart)

local cameraSpeed = 10 -- Adjust this value to control the camera's smoothness (higher value means smoother movement)

local lastCFrame = CameraPart.CFrame

RunService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value - 1, function(deltaTime)
    local targetCFrame = CameraPart.CFrame
    local currentCFrame = Camera.CFrame

    -- Use lerp to smoothly interpolate the camera's CFrame
    Camera.CFrame = currentCFrame:Lerp(targetCFrame, math.min(1, deltaTime * cameraSpeed))

    -- Apply additional smoothing using prediction
    local predictedCFrame = currentCFrame:Lerp(lastCFrame, math.min(1, deltaTime * (cameraSpeed * 5)))
    Camera.CFrame = Camera.CFrame:Lerp(predictedCFrame, math.min(1, deltaTime * (cameraSpeed * 5)))

    lastCFrame = CameraPart.CFrame
end)

I added additional step using prediction to help smooth out the camera’s movement. The cameraSpeed controls the general smoothness of the movement, while the higher speed in the prediction part (cameraSpeed * 5) helps to react more quickly to fast changes in movement.

So you probably need to fine-tune the cameraSpeed and the prediction factor to get the desired smoothness while maintaining a locked-on feel. Experiment with different values to find the best balance and it should do the job.

3 Likes

I understood the problem when I was thinking, its not the camera or the part, its the logic that the camera is moving to the part, basically, the vehicle moves from one side, position to the other, the camera will try its best to reach the same cframe that the camera part is, but when it is too far or close.
It will still try to return and as the vehicle moves, it will interfere with the move and end up throwing the camera’s cframe back again, giving a “glitch” feeling, but everything is happening because the Camera’s CFrame is going back and forth very fast, TweenService wouldn’t help, even because it would be deoptimized, the The only way would probably be to lock the position of the camera to the camera part, and thus just changing the rotation, I think this is the “best” way.
Even because it is strange, confusing to think of a way to “calculate the next trajectory of Camera’s CFrame” and it would be necessary to create a type of distance so that the “Camera’s CFrame” never exceeds and only stays within that distance, it would be something like that, now the problem would be here…
How would we fix the movement of the camera Camera to CameraPart even if the vehicle is moving?
Well, I still don’t know, probably because I’m not very advanced in scripting and I couldn’t think of a solution for that, because it’s more likely that we should just “stop a connection” from the Camera always going to the CameraPart previously so that so we start a new connection but that the camera does not suffer interferences in the displacement and that it does not “fall” from the position that is “backwards” too quickly, and that it only remains the same speed, even in any circumstances.

2 Likes

By what you are saying, if you identified the core issue correctly, then that leaves me one last thing to try. When the camera is following a moving vehicle, its constant attempt to reach the target CFrame (CameraPart’s CFrame) causes rapid fluctuations and a glitchy feeling.

To address this issue, you can indeed lock the camera’s position to the CameraPart’s position while only updating its rotation. This approach ensures that the camera follows the vehicle’s rotation smoothly without interfering with its movement. (if this is not what you want, just let me know)

local Camera = game.Workspace.CurrentCamera
local CameraPart = game.Workspace.CameraPart -- Replace this with the part you want the camera to follow

local function updateCamera()
    if not CameraPart then
        return
    end

    local targetPosition = CameraPart.Position
    local currentCF = Camera.CFrame
    local targetCF = CFrame.new(targetPosition, targetPosition + CameraPart.CFrame.lookVector, CameraPart.CFrame.upVector)

    Camera.CFrame = CFrame.new(currentCF.Position, targetPosition) * CFrame.new(0, 0, -10)

    -- Uncomment this line if you want the camera to always look at the CameraPart
    -- Camera.Focus = CFrame.new(targetPosition)
end

-- Call the updateCamera function in the RenderStepped event to smoothly update the camera's rotation
game:GetService("RunService").RenderStepped:Connect(function()
    updateCamera()
end)

So the changes I made should only modify the camera’s rotation based on the CameraPart’s position. The camera’s position is locked to a certain distance from the CameraPart (in this case, -10 units along the CameraPart’s forward axis), and its rotation smoothly follows the rotation of the CameraPart.

You can adjust the distance value or add extra features, like having the camera always look at the CameraPart, by uncommenting the corresponding lines in the script.

2 Likes

Sadly still did not worked, besides, it also bugs all the camera when it is too close to the CameraPart, i’ve tried everything even AlignPositions and AlignOrientations but did not worked, it still has the same glitchy effect, your code works good sometimes when it is too far away from the car, but when it does start getting closer, has the glitchy effect. If you think you can make a vehicle and then make the “base” for the camera stops glitching, this would be a big help for my game and knowledge.

1 Like

I will see what I can do, but making a glitch-free camera system for a vehicle can be very extensive and is probably beyond the scope of a simple script.

3 Likes

Thank you for trying to help me, i appreciate your help and i’m really gratefull. If you don’t mind, to make the “things” simple, do you know how to make some sort of camera like at the Roblox “walltap.”?

Its a bit laggy, but I hope you can see it.
This is the game: walltap. [TOUGE + CARS] - Roblox

You cant move the camera with the Right Mouse Click Hold while at the car camera point of view by the way.

3 Likes

A long time ago, I remember having a similar issue with a custom camera using lerp, and I found this to be the solution after a lot of research. I forgot why it works, but it doesn’t hurt to try.

local lastPhysicsDeltaTime = 0
local lastFrameDeltaTime = 0

local function getAccurateAlpha(scale)
	return 1 - ((scale and scale or 1) / 1e+12) ^ math.clamp((lastPhysicsDeltaTime - lastFrameDeltaTime), 0.005, 0.05)
end

RunService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value - 1, function(deltaTime)
	Camera.CFrame = Camera.CFrame:Lerp(CameraPart.CFrame, getAccurateAlpha())
	lastFrameDeltaTime = deltaTime
end)

coroutine.wrap(function()
	while true do
		local discard
		discard, lastPhysicsDeltaTime = RunService.Stepped:Wait()
	end
end)()
2 Likes

It lags (glitches) when I am at high speed, but does not lag (glitches) too much when I am at low speed.