Godot: Sprites jitter/jump when moving in _fixed_process()

Created on 17 Aug 2017  路  45Comments  路  Source: godotengine/godot

Operating system or device - Godot version: Windows 10 - Godot 3.0 / latest

Issue description:
When I move objects at a fixed speed in fixed_process, there is occasional jitter/jumping which happens at a regular interval. When more time has passed than _fixed_process() can process (because _fixed_process() can only simulate physics in fixed step intervals), the sprite is drawn where it was at the end of the last physics update rather than where it currently is. The 'accumulated leftover', or difference between the last physics update and the current time will keep getting larger as the loops get further out of sync, until finally the 'leftover' gets greater than 1/60 and some of it can be processed by the physics engine. When this happens, the sprite will 'jump' to a more precise location.

This phenomenon is the same one that is described in the "The final touch" section of this article: https://gafferongames.com/post/fix_your_timestep/#the-final-touch
The author proposes using interpolation to draw the sprite at a position between its position at the end of the most recent physics update and the physics update before that--I think that's a reasonable approach, but it seems like then your character would always be 'behind'.

My preferred solution would be, when rendering sprites, to 'extrapolate' their position at the time of drawing by starting with what their position was at the end of the last _fixed_process() and then calculating their projected position using their last known velocity. How exactly to extrapolate the position of some sprite is subjective (what if the sprite has an acceleration, etc.) so it might make sense to have the extrapolation be implemented by the user in GDScript.

Steps to reproduce:
Play the example project with a 60hz refresh rate monitor so the game runs at 60 FPS. The 'leftover delta' that has accumulated will be printed: notice that, when it finally accumulates to ~0.16 (1/60), it will 'roll over' and an extra physics update will be performed for that frame, causing the position of the sprite to suddenly be corrected and appear as an ugly jump.

Link to minimal example project:
godot_jitter.zip

bug discussion core

Most helpful comment

@lawnjelly did you try alpha? jitter was most definitely fixed there

I tried 3.0.5 stable
3.1 alpha
and version built from source here a couple days ago.
This is on linux mint 64.

The main issue I think people are referring to here (robrtsql etc) is the apparent lack of interpolation. Jitter and other problems will always occur with no interpolation I think, unless you are using semi fixed timestep (stepping to the exact frame time in the physics with non-fixed tick)? The way to test is to put the physics fps down to a low value such as 10fps as in my example code above. With interpolation you should get smooth gameplay no matter the physics tick rate.

It is possible for users to bodge around this by doing custom interpolation in the games, but the question I would ask is, are you intending for us to do interpolation ourselves? Or is the expectation for users to put physics tick rate up to a high value and have this produce 'close enough' results?

My blog post above should help summarise:
https://www.gamedev.net/blogs/entry/2265460-fixing-your-timestep-and-evaluating-godot/

BTW, this is not a criticism, I think the engine is awesome and has a great design philosophy, I would like very much to see it succeed, and making sure us new guys have an easy way to deal with interpolation (and making it clear how to achieve) might help loads for that! :) Many thanks.

All 45 comments

This issue looks similar to https://github.com/godotengine/godot/issues/2043; is there any difference?

@Calinou This one has a concrete explanation, unlike the other. One of the two might have to be closed though...

I'm not quite sure I think extrapolating the position is a good idea. I've implemented some (rather ugly) render interpolation for my own means in Godot, and I think that a physics delay of one frame is acceptable even in quick-reaction-time games.

Extrapolation doesn't really resolve this issue but merely hides it, for example two bodies that collide may render as penetrating further than they should.

This could be done as an option, of course, to toggle between interpolation, extrapolation and none.

(Those were pasted on github somewhere, but I was unable to find them... )
Here are reference articles from irc discussion with reduz from many months ago (I think it can be used as implementation hints):
Fixed-Time-Step Implementation: http://lspiroengine.com/?p=378 (!!!)
Fix Your Timestep! How to step your physics simulation forward: https://gafferongames.com/post/fix_your_timestep/

edit: Also I would not close this one, since I think it's a lot more to the point and have some nice demo (?)

In my opinion, this is separate from https://github.com/godotengine/godot/issues/2043 because the other issue is presumably caused by driver bugs, whereas this is an 'expected jitter' caused by fixing our physics timestep.

sounds reasonable

I'm not quite sure I think extrapolating the position is a good idea. I've implemented some (rather ugly) render interpolation for my own means in Godot

@Causeless in the Godot source code? Or implemented in GDScript? I'd be interested in seeing your implementation.

In GDScript as a proof-of-concept. I intended to port it into the source or into a module later for an RTS game I'm planning. It's really not an impressive or elegant solution.

I'm thinking about how this could be added to the engine. Two options:

  • A project setting (off, interpolate, extrapolate) that works on Node2D and Spatial transform properties.
  • A new node type (TransformInterpolator or something similar) with a setting for interpolate/extrapolate, that affects every Spatial/Node2D descendants.

In any case, I think we should wait until @tagcup's-@reduz's work on 3D transforms is finished.

A third idea would be to extend Node to have an render interpolation mode settings with "Inherit/Interpolate/Extrapolate/None", under the Pause Mode setting. That might be a bit much to put onto the Node class though, considering this primarily concerns only rendering.

A new node type would allow the most flexibility, and would also potentially allow the user to explicitly define the delay in frames of data to track or implement their own interpolation modes. However, this would require the end user to be very aware of what exactly they are doing (and they'd need to explicitly add the node). I can imagine that a user who doesn't really know what they're doing could easily end up with different parts of their render frame desynced.

A project setting would avoid that, however I can think of a few cases where this would be an issue: user camera movement, player UI crosshairs or cursors etc, where the effects of either option - interpolation with an extra frame delay or extrapolation which would cause jitters - are absolutely not desired.

I don't think a project setting by itself would work for that reason, although having both a project setting as well as a node type that explicitly overrides the project settings for all its children would be fine.

This feature is a bit advanced and having it in two places can be confusing.

The node approach is somehow similar to the RemoteTransform (or sth like that) node already present: all of them would be nodes affectin others' transforms.

Without understanding how the engine's source code is structured, it's not trivial (for me, at least!) to implement this by modifying the engine, so here's a GDScript interpolation implementation. I updated the mover.gd file from the provided example project to do interpolation between the previous and current position on the sprite. That way, the actual physics is untouched but the movement appears to be smooth.

I expect this same approach should work for anything, provided that your character scene is structured in the same way. The 'sprite' can probably be replaced with any type of drawable node--in fact, I don't yet see why this wouldn't also work in 3D. If you attached a camera to your character, you'd probably want to make it a child of the drawable node, rather than the 'physics body' node.

I haven't tried to use this in a sample game yet, but the movement looks smooth (in order to guarantee smooth movement, I had to plug in my laptop to make sure battery saver was off, and turn on fullscreen).

The only problem is when the sprite reaches the edge of the screen, I "teleport" it back to the other side, and the 'interpolation' often draws the sprite in the middle of the screen when this happens. This could probably be overcome with a flag being set for every fixed process update saying whether or not the character has "teleported", and not performing the interpolation (and remembering to set the Sprite's offset/position to 0,0) in that case.

mover_script.zip

That's a pretty neat script. Thanks for sharing!

An idea to fix the teleportation; instead of using a flag (which is extra data and a little inefficient, as well as potentially error prone), just set both the previous frame position and the current position to the new teleport position.

There's a few other optimizations and simplifications that can be made. For example, rather than conditionally checking if prev_position is set, just ensure it's set to the current position in the initialization and so is never null.

Sadly, it doesn't look like my fix worked.

Rather, it works for 40 seconds or so (if you ignore one or two little jumps or temporary pauses which I can't consistently reproduce) and then suddenly it "destabilizes" or something and starts to stutter rather than moving smoothly.

Here's a sample project which shows the problem after running for 40+ seconds, updated to be compatible with newer builds of Godot 3.0.

godot_jitter.zip

I think it's worth to mention that as far as I understand this issue (the fact this issue is about jitterring caused by lack of fixed step interpolation), this problem is very much reproducible/noticeable even on 60HZ screens by setting physics fps inside project settings to something below 60hz (like 45, or 25).

Err, following up on my last update, it seems that my interpolation script DOES work--the issue I was seeing was an unrelated graphics driver bug. The problem is non-existent on a different PC.

@kubecz3k good point--I should have included that in the reproduction steps--it makes the issue easy to see.

Just giving an update here because Bullet physics has built-in interpolation support which can be used by calling the update function with certain parameters during the non-fixed tick. Given that Godot is considering dropping it's in-built 3D physics for Bullet, I think it would make sense to implement it especially given that Bullet handles the majority of the difficulty.

Just as a side note I was considering Godot for an RTS project (where simulations can run at significantly lower tickrates as latency isn't as big a concern) but instead chose a modified Urho3D largely down to this issue - although admittedly Godot isn't alone in having little support for RTS style games.

Given that Godot is considering dropping it's in-built 3D physics for Bullet, I think it would make sense to implement it especially given that Bullet handles the majority of the difficulty.

Remember that 2D physics are still using a custom engine in 3.0, and these should also be able to use interpolation.

Does this stuttering also impact/influence objects moved by forces?

No, it's purely visual as long as you're doing all physics-interfacing logic in the right place (using fixed_update() instead of update() ).

This may have been fixed now, due to a recently merged PR. Please test again.

OP project, slightly modified to current API runs smoothly at least on Linux, not a single skip.

Just the very occasional stuttering (probably related to vsync) remains.

I believe the recently merged PR Juan is referring to is https://github.com/godotengine/godot/pull/17353.

Here's a version of the minimal bug reproduction project which has been modified to work with the new API changes, like eon-s described. When I run this project (with default "physics_jitter_fix" set to 0.5, as is default), I can't see any stuttering. Woohoo! 馃帀Thanks, everyone!!

Maybe we should wait for someone with a more "real world" project to give feedback, but I'm okay closing this issue if everyone else is.

The pong game demos still do this on a Mac. Heavily in full screen. Unbearably so.

@dissidently Even in a daily/master build after the above PR?

@mhilbrunner I downloaded the latest build on the day I posted that comment, and tested with that. It behaved in the manner I've become familiar with (of Godot) in that the "jittering" was unbearable. Previously commented on this issue in chat, months prior, where others acknowledged it as a problem with Godot.

Just tried with the latest build, from here, dated June 22nd: https://godotengine.org/download/osx

And the problem is still there. It's not as frequently occurring as before, but now more jarring/significant when it does occur. Same demo to see it, the Pong template, fullscreen.

You'll need to turn on stretching in the settings, as this has been turned off since the last build I used, where it was the default. Without stretching on, you won't get a full display. I used Project, General, Display, Window, Stretch Mode = 2D, as this was disabled.

Also needed to turn on Fullscreen in same settings window.

Just tried with the latest build, from here, dated June 22nd: https://godotengine.org/download/osx

Those are stable builds made from the 3.0 branch.

By master branch, @mhilbrunner was referring to the development branch which will become Godot 3.1. You can test nightly builds made by @Calinou on https://hugo.pro/projects/godot-builds/

I tested today on the following system, and could confirm that I have no stuttering on 3.1-dev (0954c8f):

  • Mageia 6 x86_64 (Linux 4.14.44, Xorg 1.19.5)
  • Nvidia GTX 670MX with current proprietary drivers (390.59)

Running in Openbox (lightweight window manager), everything runs great. In Plasma/KWin, which is notoriously heavy and uses OpenGL itself on top of Godot, I do have some stuttering, but the test with Openbox shows that the issue comes from the DE/WM.

In Plasma/KWin, which is notoriously heavy and uses OpenGL itself on top of Godot, I do have some stuttering

Should this really make that big of a difference on half decent hardware?

In Plasma/KWin, which is notoriously heavy and uses OpenGL itself on top of Godot, I do have some stuttering

Should this really make that big of a difference on half decent hardware?

Yes, it's a driver/software issue, not related to hardware performance. https://devtalk.nvidia.com/default/topic/1029568/linux/the-situation-on-kde-kwin-plasma-performance/

Also, do tests on release mode too, editor (mostly the remote debugger) can introduce some stutter,

I was testing out the project I linked in this comment using this nightly build, and it looks like the problem might not be gone after all. I am still seeing the jitter--and my project is actually able to predict when the jitter will happen (by observing the accumulated deltas) and will print out 'SKIP!' when it happens. I'm not sure why I thought the issue fixed--I must have not been paying close attention.

I'm thinking that the issue that this PR solved might be a different one. If the goal of the PR is to ensure that there are always exactly N or N+1 physics ticks for each rendering frame, it won't eliminate the jitter problem, because 2 physics ticks happening instead of 1 is still enough to observe (at least at a physics fps of 60--I tried 180 and the tick was almost impossible to see).

So, I think Godot could still benefit from rendering interpolation. Thoughts? Has this problem gone away for everyone else?

I don't have any skip with that project, also the body needs a shape there, physics server seems to not like much bodies without shape.
I got different times without shape, with shape and with pixel snap, but no skip at all on a radeon R5 using Gnome (linux).

Thanks for the tip about the collision shape.

I've tried it out on both macOS (on a MacBook Pro with Intel HD Graphics 4000) and on Linux (Ubuntu, running XFCE, with NVIDIA GTX 1070) and I get the same results on both (with the shape). The delta that has accumulated is continuously printed out so you can see it rise. After enough delta has 'accumulated' (which is 0.01666..., or 1/60, enough to do a second physics tick with our accumulated delta), eventually my console says 'SKIP!', the sprite skips ahead, and the accumulator starts back at 0 and slowly goes up.

0.016417
0.01665
SKIP!0.016618
0.000197
0.000557

It only takes me 10 seconds of running the project to encounter the first skip--you really don't see it?

I don't see any skip, and I have let it run a couple of time across the screen, can you try to export on debug mode and check the output? If is so consistent in time, it may be something else.

Hello I am new to Godot (a couple of days), I have written a simple standard fixed timestep interpolation example, this is probably similar to the gafferongames article and lspiros, maybe it will be helpful for illustration / diagnosing, I don't know whether this can be done already with Bullet. This is how I have usually dealt with this issue.
godot_fixtimestep_interpolation.zip
It starts with fixed timestep interpolation (FIXED), press tab to toggle between naive physics on physics_process without interpolation (OLD) to see difference. Press cursors to move the ball and escape to exit. You can change the physics fps in the project settings to experiment with different rates. This solution will deal with monitors with different refresh rates and give fixed physics tick rate for reproducible behaviour.

I wrote a little more about it here:
https://www.gamedev.net/blogs/entry/2265460-fixing-your-timestep-and-evaluating-godot/
Although you could leave interpolation support to the physics engine, having in built support for interpolation in the base node (or similar result) would arguably be more powerful and easy to use (as suggested by earlier posters), and put Godot ahead of many other engines in this regard.

If you stored previous and current tick values for transform in each node, you could e.g. use a bitfield for which elements to interpolate (maybe translate, rotate quaternion, rotate euler, scale) then maybe preconstruct some lists of each of which node components to interpolate on each frame update. The math for lerping / slerping is pretty simple and no need to rely on physics engine for. Animation within a skeleton wouldn't typically need to go through this as that is usually calculated at frame time rather than tick.

Of course much of this discussion is a few months old, I suspect developers are aware of much of this and pros and cons. Maybe attempts to multithread physics are having some impact on design too.

@lawnjelly did you try alpha? jitter was most definitely fixed there

@lawnjelly did you try alpha? jitter was most definitely fixed there

I tried 3.0.5 stable
3.1 alpha
and version built from source here a couple days ago.
This is on linux mint 64.

The main issue I think people are referring to here (robrtsql etc) is the apparent lack of interpolation. Jitter and other problems will always occur with no interpolation I think, unless you are using semi fixed timestep (stepping to the exact frame time in the physics with non-fixed tick)? The way to test is to put the physics fps down to a low value such as 10fps as in my example code above. With interpolation you should get smooth gameplay no matter the physics tick rate.

It is possible for users to bodge around this by doing custom interpolation in the games, but the question I would ask is, are you intending for us to do interpolation ourselves? Or is the expectation for users to put physics tick rate up to a high value and have this produce 'close enough' results?

My blog post above should help summarise:
https://www.gamedev.net/blogs/entry/2265460-fixing-your-timestep-and-evaluating-godot/

BTW, this is not a criticism, I think the engine is awesome and has a great design philosophy, I would like very much to see it succeed, and making sure us new guys have an easy way to deal with interpolation (and making it clear how to achieve) might help loads for that! :) Many thanks.

I believe it's more appropriate to post this here than make a new issue. I experience severe jitter and stutter for a RigidBody object in a game I'm making.

This is a simple project with just a RigidBody2D with Sprite and Camera2D (with smooth movement). I give it a tiny spin at the start. This is the result:

https://streamable.com/dmu6o

According to this article, this is a combination of jitter and stutter. Stutter happens about every 1 second. It's not very noticeable in the video above. I mostly have stutter, and jitter appears when performance goes down (for the video there was only stutter, but jitter appeared when I started recording with OBS).

I've tried turning on Vsync via compositor, and I've tried setting physics FPS to 59 (so it matches my laptop's refresh rate). Nothing helps. I tried Physics Jitter Fix too but no changes, and I have no idea how I'm supposed to use that property.

I'm considering the sprite interpolation option, but the main mechanics relies on physics so I'm a bit skeptical about it if there's a way to avoid it altogether (judging by how all this works, apparently not).

@wingedadventurer Physics interpolation using @lawnjelly's smoothing add-on is purely visual, it won't affect gameplay at all.

Nice, it works right out of the box! Thanks @Calinou for share, and thanks @lawnjelly for making this addon! 鉂わ笍

I believe that this problem is solved by lawnjelly's smoothing add-on--therefore I am closing this issue!

For those stumbling upon this issue, note that there's a proposal about adding built-in physics interpolation: https://github.com/godotengine/godot-proposals/issues/671

Was this page helpful?
0 / 5 - 0 ratings