Why use :lerp()?

Hello! I’m new at roblox scripting and I was learning how to make that the character’s face follow the player’s mouse position, after a few researches, I found this topic :

Code :

local RunService = game:GetService("RunService")

local Player = game.Players.LocalPlayer
local PlayerMouse = Player:GetMouse()

local Camera = workspace.CurrentCamera

local Character = Player.Character or Player.CharacterAdded:Wait()
local Head = Character:WaitForChild("Head")
local Neck = Head:WaitForChild("Neck")

local Torso = Character:WaitForChild("UpperTorso")
local Waist = Torso:WaitForChild("Waist")

local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local NeckOriginC0 = Neck.C0
local WaistOriginC0 = Waist.C0

Neck.MaxVelocity = 1/3

RunService.RenderStepped:Connect(function() 
	local CameraCFrame = Camera.CoordinateFrame
	
	if Character:FindFirstChild("UpperTorso") and Character:FindFirstChild("Head") then
		local TorsoLookVector = Torso.CFrame.lookVector
		local HeadPosition = Head.CFrame.p
		
		if Neck and Waist then
			if Camera.CameraSubject:IsDescendantOf(Character) or Camera.CameraSubject:IsDescendantOf(Player) then
				local Point = PlayerMouse.Hit.p
				
				local Distance = (Head.CFrame.p - Point).magnitude
				local Difference = Head.CFrame.Y - Point.Y
				
				Neck.C0 = Neck.C0:lerp(NeckOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, 0), 0.5 / 2)
				Waist.C0 = Waist.C0:lerp(WaistOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 0.5, 0), 0.5 / 2)
			end
		end
	end	
end)

after trying to understand the code, I found it that I can’t understand well the algorithm by my own.

Why do we use :lerp() here and how can I understand the algorithm?

Neck.C0 = Neck.C0:lerp(NeckOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, 0), 0.5 / 2)
				Waist.C0 = Waist.C0:lerp(WaistOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 0.5, 0), 0.5 / 2)

Any help is appreciated! Thanks!

Well step one would be to format it better across multiple lines and probably breaking it out into more separate statements and variables. One liners like those are just pointlessly unreadable.

I’m guessing lerp is used to smooth out the movement in this case. Instead of snapping instantly to the right orientation it gradually moves there over time.

E.g.

b = a:lerp(c, 0.5)

sets b to be the halfway- value between a and c. If you put in 0 it’s 0% of the way from a to c (i.e. it’s just a), if you put it to 1 it’s 100% of the way so it’s just c. Lerp works on Vector3s and CFrames, and you can write a lerp function to work with plain numbers.

If you have a variable that is the desired CFrame, you can see how lerping results in gradual movement to the desired CFrame when this is done repeatedly:

Waist.C0 = Waist.C0:lerp(desiredWaitC0, 0.25)

Every time it moves C0 25% of the way to the desired C0. Over time it gets closer and closer.

1 Like

Thanks! That!s really helpful! I have understood the lerp function more! But how do we get the direction from this line of code?

CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, 0)

What does it mean?

First format it properly instead of all this one-liner stuff. Here I also added temporary comments just to show where the three angle components are calculated:

Neck.C0 = Neck.C0:lerp(
    NeckOriginC0 * CFrame.Angles(
        -(math.atan(Difference / Distance) * 0.5), --X
        ( --Y
            ((HeadPosition - Point).Unit):Cross(TorsoLookVector) --Y
        ).Y * 1,  --Y
        0 --Z
    ), 
    0.5 / 2
)

Remove all the unneeded parentheses that just make it more confusing (there’s also a multiply by 1 and an unnecessary divide in there):

Neck.C0 = Neck.C0:lerp(
    NeckOriginC0 * CFrame.Angles(
        -(math.atan(Difference / Distance) * 0.5), 
        (HeadPosition - Point).Unit:Cross(TorsoLookVector).Y,
        0
    ), 
    0.25
)

Now break it out into separate variables so the names say something about what each calculation is for. This simplifies some of the statements so much that it makes sense to put them back on single lines again:

local Pitch = -(math.atan(Difference / Distance) * 0.5)
local Yaw = (HeadPosition - Point).Unit:Cross(TorsoLookVector).Y

local TargetAngles = NeckOriginC0 * CFrame.Angles(Pitch, Yaw, 0)

Neck.C0 = Neck.C0:lerp(TargetAngles, 0.25)

Now it’s actually possible to see how the angle calculation is done, and making sense of it is just a matter of knowing the math. Drawing a diagram can be helpful here. Ask away if you’d like an explanation of the math that’s used here.

2 Likes

Yes please, an explanation would be useful for me. After searching the dev hub I still can’t under stand the math. (By the way sorry for disturbing you a lot of times :sweat_smile: :bowing_man: )

Lerp is essentially something called Linear interpolation - Wikipedia, in it’s simplest form mathematics between it can be expressed with a number line.


We can express the notations a and b with numbers

a = 0
b = 1

Now we can actually represent an equation to give us a fraction between those two points. Which is…
a+(b-a) * t -- Universal formula for 1D Linear interpolation
The variable t represents that fraction I was talking about.

Before explaining :lerp() I think showing an example would be nice, where t=1/2.
(0)+( (1) - (0) ) * (1/2) -- Which equals 0.5

So :lerp() using what we know, is essentially linear interpolation on the CFrame coordinate of the object, which CFrame is the local position of the object on it’s own plane. It uses 3D and much more lengthy algorithm compared to the one I showed, but in simple terms, this is essentially what it is.

1 Like

I explained it here

The math uses several approximations to measure the angle towards the mouse so it’s not as simple:

1 Like

Thanks! It made me understand the lerp function really well ! Also thanks for your example, it’s very useful! :smile:

Alright I will check it out! Thanks! :slightly_smiling_face: