Why doesnt this CFrame tween function work?

So i was doing a learning excersize as im currently trying to understand how CFrames and matrices works in general. I ended up writing some tweening function using delta time. Im not intrested in having it working, that said i could fix this by using other approaches. I just want to understand why this doesnt work.

Code
local RunService = game:GetService("RunService")


local Part = workspace.Part
local Target = workspace.Target

local function TweenTo(CFramee, Time)
	local Diff = Part.CFrame:Inverse() * CFramee
	local StartTime = time()
	print(StartTime)
	local StartCFrame = Part.CFrame
	
	RunService:BindToRenderStep("Tween", 300, function(Step)
		local Scalar = math.clamp((time() - StartTime)/Time, 0, 1)
		Part.CFrame = Part.CFrame * CFrame.new():Lerp(Diff, Step/Time)
		
		if Scalar == 1 then
			Part.CFrame = StartCFrame * Diff
			RunService:UnbindFromRenderStep("Tween")
		end	
	end)	
end


TweenTo(Target.CFrame, 10)

This is how it currently looks:
https://gyazo.com/692175bd950aa3518c7583fabb9f0a4e
https://gyazo.com/abab9e6f8eb60cf0476dda87555acc4d

I understand this does not directly answer your question, but why not use TweenService instead? This essentially saves you the hassle of developing your own system and enables you to customise the transitions using EasingStyle.

Well, my goal here isnt to achieve good results. My goal is to get a better understanding of CFrames. I mean what would i learn from using TweenService that i already know how to use. This is after all just a learning excersize.

Here's how I would do it:
local renderPriority = Enum.RenderPriority.Camera.Value - 1
function tweenParts(partA, partB, duration)
	local cfA, cfB = partA.CFrame, partB.CFrame --start and end CFrames
	local t0 = tick() --start time
	
	RunService:BindToRenderStep("Tween", renderPriority, function()
		local t = tick()
		local a = math.min(1, (t-t0)/duration) --how much to lerp between A and B, as a number from 0 to 1
		partA.CFrame = cfA:Lerp(cfB, a)
		
		if a >= 1 then
			RunService:UnbindFromRenderStep("Tween")
                        --a is guaranteed to reach 1, so no need to set partA.CFrame to cfB
		end
	end)
end
Here's how I would fix your way of doing it:
local function tweenTo(partA, partB, duration)
	local Diff = partA.CFrame:Inverse() * partB.CFrame
	local StartTime = time()
	local StartCFrame = partA.CFrame
	
	RunService:BindToRenderStep("Tween", 300, function(Step)
		local Scalar = math.clamp((time() - StartTime)/duration, 0, 1)
		partA.CFrame = StartCFrame * CFrame.new():Lerp(Diff, Scalar)
		
		if Scalar == 1 then
			partA.CFrame = StartCFrame * Diff
			RunService:UnbindFromRenderStep("Tween")
		end	
	end)	
end

There was one major issue: you were using Step/Time as your alpha value for CFrame:Lerp, which is wrong. I changed it to be Scalar, which makes more sense.

2 Likes

I did try that approach before, and yes it did work. But i just wanna know why the tween function that i made didnt work. My understanding is that CFrame.new():Lerp(Diff, Step/Time) simply gives you a part of Diff. Where the part size is based on the amount of time that elapsed since the last frame and the time to complete the tween in. So if i add parts of Diff i should eventually get to the CFrame of the blue part.

The add up will stop once Scalar reach 1

Step in this case is not how much time has elapsed since you called the function, but how much time has elapsed since the last frame. That means it’s going to be about 0.0166, every frame. That means the part never gets lerped very far.

You calculate scalar, but never actually use it anywhere.

This was a learning excersize, I had been using scalar for previus approaches. I realize that step is the time elapsed since the last frame, also i do increments.