anatolbogun/godot-smoother-node

CharacterBody velocity slows down if FPS drops below the tick rate

Opened this issue · 8 comments

Thank you for this smoothing solution. This smoothing node really helps with removing jitter on my high refresh rate monitor, although I have noticed some extreme player movement slowdown while messing around with low frame rates.

I am able to replicate this using the test project https://github.com/anatolbogun/godot-smoother-node-test-scene

Steps:

  • In the script level2d.gd for the Level2D node, add the line Engine.max_fps = 10 to the _ready function.

  • Change the project tick rate to the default value of 60 in Project Settings -> Physics -> Common -> Physics Ticks per Second.

  • Play the scene. The character now moves very slowly.

  • Stop playing the scene.

  • Delete the Smoother node.

  • Play the scene again.

  • The character moves at normal speed again.

Is there a workaround for this?

hsandt commented

Also happened to me once, although removing and re-adding the Smoother node fixed it, oddly.

There's a connection I found but I don't understand the smoother.gd script enough to know what to change.

My normal conditions:
165 monitor max frame rate
60 physics tick per second
If I lower the the max_fps the physics feel off as we already know

If I follow the formula:
(max_fps / monitor max frame rate) * (physics tick per second) = new physics tick
then at 22 max_fps (because the math works nicely) we get:
(22 / 165) * 60 = 8
Setting the physics tick to 8 with 22 max_fps feels like the physics does under normal conditions with an uncapped frame rate but with a much lower frame rate

This is not a solution but maybe a clue towards what needs fixing

Actually can't this simply be fixed with if Engine.max_fps > Engine.physics_ticks_per_second or (Engine.max_fps == 0 and DisplayServer.screen_get_refresh_rate() > Engine.physics_ticks_per_second): on the first lines of _process and _physics_process? Don't really need interpolation if max_fps is less than or equal to physics tick per second

Hi all. Sorry, I missed the original issue from April for some reason, my apologies. Thanks for the detailed steps and suggestion for a solution.

I'm very busy right now but end of this week I should have some time to look into it.

This is a problem, I'm getting velocity speed drops when the max_fps is lowered, and it's fixed if Smoother is disabled.

Actually can't this simply be fixed with if (Engine.max_fps != 0 and Engine.max_fps < Engine.physics_ticks_per_second) or (Engine.max_fps == 0 and DisplayServer.screen_get_refresh_rate() > Engine.physics_ticks_per_second): on the first lines of _process and _physics_process? Don't really need interpolation if max_fps is less than or equal to physics tick per second

Unfortunately if the framerate drops and returns, the position is saved from when it was at a higher framerate. This might work better:

func _process(_delta: float) -> void:
	if (Engine.max_fps != 0 and Engine.max_fps < Engine.physics_ticks_per_second) or \
	(Engine.max_fps == 0 and DisplayServer.screen_get_refresh_rate() < Engine.physics_ticks_per_second):
		return
func _physics_process(_delta: float) -> void:
	if Engine.max_fps < Engine.physics_ticks_per_second or \
	(Engine.max_fps == 0 and DisplayServer.screen_get_refresh_rate() < Engine.physics_ticks_per_second):
		return

Hi all. Sorry, I missed the original issue from April for some reason, my apologies. Thanks for the detailed steps and suggestion for a solution.

I'm very busy right now but end of this week I should have some time to look into it.

Anything new? This works great but this one issue is causing all sorts of problems, with these temp solutions almost working, but still struggling if the fps is going in and out of 60.

Here's a branch/PR that will hopefully address this issue. For now, it's in the sample project repository at anatolbogun/godot-smoother-node-test-scene#1 . A big thanks to @elvisish for the suggestion, the change is pretty much exactly that code.

I also added a keyboard toggle to the sample project. With CapsLock you can toggle between Engine.max_fps 0 (unlimited) and 10.

It would be great if some people could test this, especially in your own project if you experienced this particular issue.

I'm also curious how you get to low frame rates in your projects. Is this because too much is happening and the FPS can't keep up with the target FPS? I only have this super basic sample project and a few other simple tests. I suppose I could add some code loops that can push the performance over the edge, but so far I haven't experimented with this yet.

@Midrule , regarding your comment:

temp solutions almost working, but still struggling if the fps is going in and out of 60.

Do you mean a potential jump/inconsistency when the smoothing is disabled/re-enabled by the fix? I think I can see a jump when I toggle the max_fps between 0 (physics interpolation happens), 10 (interpolation is skipped and saved properties are cleared) and back to 0. I need to think if that can be avoided, but it's probably tricky because the interpolation requires 2 frames to kick in, so the interpolation can only happen when at least 2 _physics_process property values were saved, like a position A and B.

Maybe this jump can be avoided or reduced if the module continuously keeps track of the property values, even if it doesn't apply the interpolation. I can try to move the new code block elsewhere, maybe it will help. But just to confirm if that's what you're referring to.