Fadetime happens faster visually at higher fps

I eventually got round to recreating the old roblox legacy animator inside modern roblox huzzah!
One of the many smaller issues I’m facing is the fact that if you are not 60fps then the fadetime will look as if it goes ‘fast’

just wondering if theres any smart people out there that can help; ive printed out my trackweight value 0-1 and it seems to be the same each fps;

visually the fadetime happens so fast!

60fps;

more than 60fps (240+);

I’ve provided the relevant code you should need.
It’s literally the exact same as the c++ variant so I’m not quite sure why it appears to ‘fade’ faster on higher fps

call;

if kfTime >= newAnimation.Length then
				if newAnimation.Looped then
					newAnimation.animStart = tick() --// restart
				elseif not newAnimation.Looped and not newAnimation.ended then		
					newAnimation:Stop(autoFadeTime)
				end
			end

anim step

local now = tick()
		local kfTime = newAnimation:getKeyframeAtTime(now)
		local trackWeight = newAnimation:getWeightAtTime(now)
		if newAnimation.ended or not newAnimation.isPlaying then
			kfTime = newAnimation.Length
		end
		
		if newAnimation.ended and newAnimation.name == "GetUp_PanicStart" then -- will pass btw!!
			local fadeOutAlpha = ((now - newAnimation.fadeStartTime) / (newAnimation.fadeEndTime - newAnimation.fadeStartTime))
			--warn(trackWeight )
			trackWeight = math.lerp(newAnimation.fadeStartWeight, newAnimation.fadeEndWeight, fadeOutAlpha)
			--warn("2; " .. trackWeight)
		end
		
		local newPoses = newAnimation:apply(jointPoses, newAnimation.lastKeyframeTime, kfTime, trackWeight)
		newAnimation.trackweight = trackWeight
--// reweight based on trackweight
			ipose.weight = helper.lerpF(0.0, ipose.weight, trackweight)
			ipose.maskWeight = helper.lerpF(1.0, ipose.maskWeight, trackweight)

fadestarweight and fadeendweight are 0 or 1

fadestarttime and fadeendtime are tick() and tick() + fadeTime respectively;

I’m completely baffled why it appears this way.

1 Like

LerpF is your default lerp function a + (b-a) * t
I’m genuinely just confuseddd why it does this on 240 fps but works fine on 60?!!!

On 240fps, you’re seeing more updates per second, so each fade step looks way smaller, and the change looks faster/smoother.

Doesn’t exactly make sense 2 me but also makes sense?
My friend gave me a 60fps limiter and it worked wonders; just wondering if i can fix this visual problem in anyway?

1 Like

I don’t understand what you mean. I don’t see an issue. When you are running at higher frame rates, the fade time seems to move too quickly. This happens because the time between frames is smaller at higher frame rates, making the fade complete faster than expected. I think that’s what you’re talking about, no?

noo ive printed trackweight on both fps and they both reach 1 at the same time but for some reason higher fps makes the fade complete faster yet the trackweight is still just 0.8 and it can be finished visually?!!

Higher FPS just means more updates per second. So even if your trackWeight is the same, the fade looks faster because it’s updating more often. It’s just how FPS works. Fix your timing to sync with the actual fade, not the FPS. I don’t think you’re understanding something.

in my head; it should still be the same length as 60fps visually; just smoother!
but when i look at it it appears to complete the fade quicker then it is supposed to it literally is speeding up time which is impossible

1 Like

The fade should look smoother at higher FPS, but the actual time for the fade is still the same. If it’s completing quicker, you’ve messed up your timing somewhere. FPS just updates it more frequently, but the total duration of the fade shouldn’t change. You’re probably syncing it wrong.

Again; printing out my trackweight alpha it returns 0 - 1 properly on both 60fps and higher fps, I’m completely lost what the problem is.

Well, if the trackweight is still going from 0 to 1 correctly, then it’s not the issue with the fade duration. It sounds like you’re not syncing the fade right with the time. FPS is just updating more often, but it shouldn’t be affecting the fade. Maybe try checking your timing logic again.

You did not provide enough code, and I do not understand what is going on in the code that you provided. But what is likely happening is that this code is running sixty times per second when the framerate is sixty frames per second. When the framerate increases to 120 frames per second (twice as many frames as 60), the code runs twice as many times per second, which makes it fade two times faster. What you should do is multiply the linear interpolation alpha (some people call it the interpolation theta) by the amount of time that has passed since the last frame. What I mean is, the number that is between 0, and 1 in the linear interpolation.

ok lets simplify this

local fadeTime = 2
local now = tick()
local startWeight = 0
local endWeight = 0
local startTime = now
local endTime = now + fadeTime

while task.wait() do
	local alpha = math.clamp((tick() - startTime) / (endTime - startTime), 0, 1)
	local weight = (startWeight + (endWeight - startWeight)) * alpha -- lerp
	print(weight)
	
	if alpha >= 1 then
		break
	end
end

essentially what my code is doing is this; i dont know why it is finishing faster visually on higher fps yet the value remains properly set as the alpha increases

and i’ve tried multiplying the thingy but it made it way longer, my autofadetime is 0.6

function newAnimation:getWeightAtTime(t, dt)
		if t >= newAnimation.fadeEndTime then
			return newAnimation.fadeEndWeight
		elseif t <= newAnimation.fadeStartTime then
			return newAnimation.fadeStartWeight
		else 
			--local interval = (newAnimation.fadeEndTime - newAnimation.fadeStartTime)
			--return ((time - newAnimation.fadeStartTime) / interval) * newAnimation.fadeEndWeight + ((newAnimation.fadeEndTime - time) / interval) * newAnimation.fadeStartWeight
			local alpha = math.clamp((t - newAnimation.fadeStartTime) / (newAnimation.fadeEndTime - newAnimation.fadeStartTime), 0, 1)
			return math.lerp(newAnimation.fadeStartWeight, newAnimation.fadeEndWeight, alpha * dt)
		end
	end

By multiplying the alpha with dt, you’re making the fade time dependent on the FPS, which makes it look faster at higher FPS. You should use the alpha value on its own, without multiplying it by dt, so the fade time stays the same across different FPS and appears consistent.

1 Like

multiplying it was a suggestion made by the other person. Do you understand?

it shouldn’t be fading two times as fast because I’m using tick() and tick() + fadetime

see stop;

function newAnimation:Stop(fadeTime)
		fadeTime = fadeTime and math.max(fadeTime, 0) or 0.100000001
		if fadeTime < 0 then
			--for i, anim in pairs(animator.activeAnimations) do
			--	if anim == newAnimation then
			--		table.remove(animator.activeAnimations, i)
			--	end
			--end
			fadeTime = 1/100000000000 --// ensure that motorposes are reset
		end
		
		local currentTime = tick()
		newAnimation.fadeStartWeight = newAnimation:getWeightAtTime(currentTime)
		warn(newAnimation.fadeStartWeight)
		newAnimation.fadeStartTime = currentTime
		newAnimation.fadeEndTime = currentTime + fadeTime
		newAnimation.fadeEndWeight = 0
		newAnimation.fadeLastT = currentTime
		--print(newAnimation.fadeStartWeight)
		--warn("fade start weight above!")
		newAnimation.ended = true
		newAnimation.isPlaying = false
	end

Here’s how I would do this:

local runService = game:GetService("RunService")
local fadeTime = 1
local now = os.clock()
local startWeight = 0
local endWeight = 1
local startTime = now
local endTime = now + fadeTime
local totalTime = endTime - startTime

local startTime = os.clock()
local alpha = 0
while true do
	local deltaTime = task.wait() -- try doing task.wait(1/10) to simulate a framerate of 10 frames per second. -- runService.Heartbeat:Wait()
	alpha = math.clamp(alpha + deltaTime/totalTime, 0, 1)
	local weight = startWeight*(1-alpha) + alpha*endWeight -- lerp
	print(weight)

	if alpha >= 1 then
		break
	end
end
print(os.clock() - startTime) -- This should be roughly equal to the fadeTime variable even when the framerate is not 60fps give or take a tiny fraction because it can't be 100% perfect.

No. If the interpolation is not dependent on the framerate, it’s speed will change depending on the framerate. If you multiply the alpha by the deltatime, then it will slow down the linear interpolation to account for this higher framerate or it will speed it up if the framerate is too low, so in theory (and in practice) it should finish at roughly the same speed.

1 Like

I’ll look at this tomorrow; thanks,

1 Like

Oops, my bad. You’re right. Multiplying by dt keeps the fade time the same, no matter the FPS. That’s on me.

2 Likes

well i tried it this morning and it gave the exact same result;

	local totalTime = newAnimation.fadeEndTime - newAnimation.fadeStartTime
			local alpha = math.clamp(newAnimation.fadeLastT + (dt/totalTime), 0, 1)
			newAnimation.fadeLastT = alpha
			local newWeight = newAnimation.fadeStartWeight * (1-alpha) + alpha * newAnimation.fadeEndWeight
			return newWeight

I’m not quite sure what’s going on or if Im just gonna have 2 live w it