Update/FixedUpdate motion stutter (Note: This is NOT a novice deltaTime question)


The Problem


Why does the motion stutter in an incredibly simple Unity game? This is a problem that has been plaguing me for years in game development (not just in Unity, but in XNA as well). Please note that I have a solid understanding of Time.deltaTime; this isn’t the typical noob question about how to get smooth motion (although I’d love it if someone has an easy answer).

I’ve played around extensively with turning VSync on and off, and I’ve tried a hundred different variations and combinations of Update/FixedUpdate/LateUpdate code, and no matter what I do, I cannot achieve perfectly smooth motion in a simple Unity game. The closest I can get to smooth motion is using Update() with VSync OFF; with those settings, I get over 400fps and mostly smooth motion (not 100% perfect though).

Is there any way to get perfectly smooth motion in a Unity game? I’m trying to make a basic 2D game, and compared to old NES games (like Mario or Zelda), the motion in Unity is always jerky and never as smooth.


Example


Take a look at this sample game (Unity Web Player required):

http://s3.amazonaws.com/picobots/assets/unity/jerky-motion/JerkyMotion.html

VSync is ON, which locks the frame rate to ~60fps (synced to my monitor’s refresh rate, which is actually 59.xxx Hz).

This game has 10 cubes and 1 orthographic camera.

There are 4 different scripts that move the camera. Only 1 script is enabled at a time, and you can switch between them using your keyboard. All 4 scripts exhibit jerky motion to varying degrees.


Code


1. Update (using Time.deltaTime)

This is the smoothest of all four options (although it’s close between this and LateUpdate), but every 1-2 seconds there is a “hiccup” in the motion. You can see the motion stutter and the moving cubes pause/jump slightly. Note: You need an eagle eye to see this. Look closely!

void Update()
{
	transform.position = new Vector3(
		transform.position.x + (2f * Time.deltaTime),
		transform.position.y,
		transform.position.z
	);
}

2. FixedUpdate (using Time.deltaTime)

The motion stutter is very apparent using FixedUpdate. Instead of smooth movement, I see an almost constant subtle jerkiness to the motion. The cubes wobble as they move.

void FixedUpdate()
{
	transform.position = new Vector3(
		transform.position.x + (2f * Time.deltaTime),
		transform.position.y,
		transform.position.z
	);
}

3. FixedUpdate (using a static value)

Same problem as #2.

void FixedUpdate()
{
	transform.position = new Vector3(
		transform.position.x + 0.04f,
		transform.position.y,
		transform.position.z
	);
}

4. LateUpdate (using Time.deltaTime)

Similar to #1.

void LateUpdate()
{
	transform.position = new Vector3(
		transform.position.x + (2f * Time.deltaTime),
		transform.position.y,
		transform.position.z
	);
}

An Even Simpler Example


Some of the comments (rightly) expressed concern about memory allocations and garbage collection, so here’s an even simpler example project that also exhibits the problem (standalone PC or Mac application):

http://s3.amazonaws.com/picobots/assets/unity/jerky-motion/JerkyMotion.zip

10 cubes, 1 orthographic camera, 1 script (with absolutely no allocations).

As @Eric5h5 mentions in the forum thread, you will unavoidably create stutter when doing transformations in FixedUpdate(): FixedUpdate is framerate independent, and therefore completely unrelated to your framerate. The stutter will be most visible the closer your framerate comes to the actual physics/fixed time step (Note as Time.deltaTime is identical to Time.fixedDeltaTime in FixedUpdate(), and the latter’s default is 0.02, your examples 2 and 3 will be absolutely identical), because it will create an “interference pattern” between the different call intervals - the one being a fixed time interval, the other being a not-so-fixed number-of-frames interval, which might well mean that there are two or three consecutive frames rendered without any FixedUpdate() called inbetween, even with VSync enabled, or sometimes two consecutive FixedUpdate() calls without a call to Update(), if there was some reason that rendering got delayed.

Concerning the stutter when using Update: Time.deltaTime is not perfect. In addition, it will contain the time the previous frame took to render, since the current time is of course unknown. So there might arise discrepancies from that, which unfortunately result in visible stutter (which is of course least visible at very high framerates with VSync off). So for example, you have a very smooth constant framerate with say Time.deltaTime==0.01, 100fps. For some reason (task switching, background process, stupid Windows OS programming), your graphics card has a hiccup, and the current frame is delayed by a few ms. Time.deltaTime for that fram will still be 0.01, but the frame takes longer to display, so your object lags behind. Entering Update() again, Time.deltaTime now contains the larger framtime of the previous frame, so you will create a larger motion. But your actual rendering time may have returned to normal. so your object jumps ahead. I don’t think there is really anything you can do against that - not in Unity, and probably not outside Unity, unless you have 100% control of your GPU process management so that you can predict the rendering time of a frame with absolute certainty.

Note there also is Time.smoothDeltaTime, which is supposed to be a smoothed version of Time.deltaTime. Maybe it will have better behaviour in your case. But IIRC the results were usually worse, since then the frame time is averaged by some formula, so the frame time will even less realisticly represent your actual frame time for any particular frame.

Also note that there is Application.targetFrameRate, which might help you in your experiments by trying to enforce a certain framerate (it will propbably not resolve any stuttering issues, though).

First of all, no, local value type variables are placed on the stack, not on the heap. The GC is only relevant for the heap memory. All memory for local variables are allocated when you enter a function and removed when you leave it. All those is placed sequential on the stack. The GC only cares about references. Value types are never GC collected. Note: an array for example is a reference type even when it contains value types.

When i run your little test project i can’t see any hiccup on Update or LateUpdate (which is essential the same since it runs at the exact same rate with the exact same deltaTime).

FixedUpdate can cause visual fluctuations in the movement speed since it runs probably at a different rate than your visual update (the Update function).

FixedUpdate is ment to have accelerated movement to always behave the same way, so it’s caluclated mathematically the same way. Linear movement can be lineary scaled with Time.deltaTime, but any polynomial function with a degree higher than 1 can’t be made frame-independent by scaling it linearly with Time.deltaTime. That’s what FixedUpdate is good for. It is executed a fix amount of times per second. This ensures that the calculations come to the same result, no matter on which machine it’s executed.

FixedUpdate is ment for more complicated physics calculations. You won’t see a hiccup in an accelerated movement.

That’s why you usually use Update for almost everything. Update(and LateUpdate) is called before every visual frame. Note that if vsync is off, a visual frame might not be seen by you because the monitor isn’t fast enough. The image is produced, but not displayed. Usually there’s no reason to run without vsync.

So my advise is:

  • Use Update for linear movement
  • Use FixedUpdate for any accelerated or higher order calculations that depends on a constant rate.

ps: If you see hiccups in your Unity app, it doesn’t need to be Unity that is producing those. Do you have any additional plugins active (flash[including youtube & co], acrobat reader, …), maybe in another tab? I’ve seen a lot influence from other applications / browser-plugins. Even some websites have crazy javascripts running in the background. Some are refreshing their content silently every few seconds…

pps: Time.deltaTime always returns the fix timestep when used in FixedUpdate, so if you haven’t changed your physics-timestep in the project settings there should be no difference between 2 and 3. I can’t see a difference :wink:

One thing I noticed on my old 2008 laptop, if there’s something selected in the scene (i.e. the inspector is showing something), the whole game lags, including cases of stuttering motion.

If the inspector is not showing anything, it increases framerate and neutralizes stuttering motion.

This doesn’t happen on newer machines as far as I noticed (even when comparing the same version of Unity, on the same project).

Also if you have more than one scene/game view on display, that obviously slows down framerate as Unity has to draw more than one camera.

Hi, i am doing the same thing right now…
if my understanding is right, velocity depicts the positional transformation that will happen in 1s.
therefore if we look on the positional difference between two physics frames it is (velocity*Time.fixedDeltaTime).

knowing that, my approach was to determine where the last fixed update happened, to smooth out a model in update. Therefore the rigidbody&colliders would have to be separated from the actual visible object.

I just used the Time.fixedTime (gets you the time the last fixed Update started, you can also store Time.time in FixedUpdate if you want -since i found they are not always 100% the same) and the current velocity of the Object, to smooth out the model in Update(). Because that is the time your camera will take a ‘picture’ of the scene:

flaot lerpFactor = (Time.time - Time.fixedTime)/Time.fixedDeltaTime;
modelTransform.position = theRigidbody.position + ( theRigidbody.velocity * Time.fixedDeltaTime*lerpFactor );
//lerp is also possible, just lerp between the 2 positions of the steps
//you may recognize that Time.fixedDeltaTime cancels out between velocity and 
//lerp Factor, i left it just for to make it lerpable too, e.g. if using slerp and stuff

about the lerpFactor:
Time.time gives you the current time of this Update() frame. If you subtract this time-progress from the time-progress of the last fixed frame, you get the time that has passed since it (note that this can’t be more than fixedDeltaTime). theRigidbody.position during the time we look at it will still be the same position it had during the last Fixed frame since theRigidbody only gets moved in these frames.
Dividing that by fixedDeltaTime we get a factor from 0to1 that says: 0-100% of the time between 2 fixedUpdates have passed at this moment;
Knowing the velocity we can determine where the Rigidbody should be at this very exact moment by transforming the models position to the position + the fraction of velocity that will determine its position in the next physics frame.

maybe it helps, maybe im completely wrong, maybe it’s the same as the extrapolate setting :D, didn’t test it enough… so please correct me if you see the flaw

You can try that, i did not use it however, i would have to rewrite lot of stuff then. maybe in future.

-also, try switching between 59 and 60Hz

just tried at a different desktop and the hiccups completely vanished for me, i finally wrote a little testscene:
http://forum.unity3d.com/threads/162694-SmoothMovementTest-should-help-eliminate-Hiccup-sources

I set QualitySettings.vSyncCount = 0; and my stutter problems were fixed. It defaulted to 1, and this introduced a periodic annoying stutter.

Whew, I finally solved this one for my game after searching everywhere with no luck. The issue for me was that my camera functions were in LateUpdate while my other things were happening in FixedUpdate. With this setup, the difference in the frame rates of these two functions caused lerps to stutter. If I moved my camera functions to FixedUpdate with everything else, then The stutter goes away but my camera functions would align themselves to look at the object’s previous position. That’s because even if all the forces have all been applied to your rigidbody’s, their movement and new position isnt calculated until after FixedUpdate. That problem meant that if the object was moving very fast (its a space game) then the camera would lag behind and the object would go offscreen even with the camera set to LookAt the object in ghat same FixedUpdate method.
The solution I came up with is to keep your camera updates in FixedUpdate and inside you camera’s update functions, add the target’s position to its velocity times delta time:
Vector3 updatedPosition = object.GetComponent().position +object.GetComponent().velocity * Time.deltaTime;
Then base all your camera’s positions and LookAt’s on thiz updated position. You don’t have to change any frame rates or anything like that. One note though, I don’t use Update or FixedUpdate on individual scripts, instead I use a single script to call designated update methods on all my other scripts so I can control the order in which things get updated.

Old question , I still got here while looking up same problem and this seems to be up in the google search.

I think what happens is … what was described which is:
The update and the vsync happens 60 times a second.
The fixed update and all physics happens 50 times a second.
Why was this chosen … duno.

Still this means that few times a second there will be a moment when the eye expects the next frame object position and gets the last frame one instead.

I believe that when it says physics happens 50 times a second it means that fully. There is no rigid body movement at all. Everything freezes for a frame.

Simple solution was to sync the fixed update to the framerate , means fixed timestep = 0.01666667
This means:

  1. little more calculations made by the physics engine.
  2. always smooth at 60hz.
  3. a bit more precise physics

Other solutions given do effectively the same (compensating for the difference inside monobehaviours) but inside c#. Upping the fixed rate moves the calculations to the engine which is running in fully compiled c++ I believe.
In my experience this does not seem to be much more resource consuming than compensating in c#.

As well with this method is simple-ish to adjust to other framerates during the run time.
Time.fixedDeltaTime = new value

I guess one does not want to run physics at 144hz. Still 72hz would be okish and smoother than 50hz. So if the detected framerate is too large then run physics engine at half or 1/3 of that. So the even if we skip frames in physics we always skip same amount (1 or 2). It will be way smoother then the mismatch of 50hz and 60hz it is by default when the skip happens only every 5-6 frames.

To change physics “refresh” rate via menu follow the documentation:

change 0.2 into 1/60 ~ 0.01666667

I believe that this would work in during runtime:

// Sets to 60 fps
Time.fixedDeltaTime = 0.01666667f;

I experienced the same thing in a very simple 2D game. I think I maybe found a solution. I also used Time.deltaTime in the Update function to multiply the movement and make it frame rate independant.

If you look at the documentation it says: ‘The time in seconds it took to complete the last frame’. Now the problem is that this time varies a lot. Unitys e.g. physics engine comes into schedule from time to time and increases the deltaTime a lot. The overall time to calculate the frame can still be very low, but the differences to the previous frame can be very high. That means if you use this value to multiply the movement of your object, it will stutter.

My solution was to calculate an average of the deltaTime from the last e.g. 30 frames (30 was the first try and it worked quite well) and use this average value for multiplication in my update function. Result is a perfect smooth game :slight_smile: I do not have my code here at the moment, if requested I can supply that later.

I have seen similar issues as far back as I can remember. There are two tricks I know that help.

Change the speed until you no longer see the issue.
Don’t use a uniform speed.

Is it not possible you are seeing the collision between the absolute number of pixels in the display versus the frequency you moving across them. I notice the player is running with anti-aliasing off, does the problem appear less with it on?

All that having been said I downloaded and ran your example. Its fine on my machine when output as an executable, but the web player version creates the same jerky results as your online examples.

On a last note for out 2D game we user a catchup smoothing solution for panning the camera to the player. This helps eliminate motion sickness as well as creating a non uniform movement that fools the eye.

Hope something in all that might prove useful.

Time.deltaTime is for the previous frame.
If you use this for your motion, but your current frame takes a significantly different
time to render (more or less time). you’ll see the hiccup.

Set Time.MaximumDeltaTime to a value close to or a little higher than your average frame time.
Also, you can try keeping your own moving average of Delta Time as your usable T.

Alright, I ran into this issue trying to create a simple snake game. I searched high and low to no solid answer. So I put some deep thought into why it might be stuttering. I managed to solve it for myself, so i figured i would toss my findings on here so other may try.

My Theory:

What i believe the issue to be in this case, is that the rate your screen draws at is much greater than the fixed time, as well as at variable rates. So no matter what the frame rate, if it is a fair amount higher, than it will stutter since you can have something move 1 unit in 5 frames, then 1 unit in 10 frames which will obviously not look smooth.

My Answer:

The only thing i could think of at this point is try to match that frame rate. So i simply changed the max frames to 50 using Application.targetFrameRate. It seems to have eliminated the stutter. At least the best i have seen so far.

I hope this helps some people with similar issues who want to use FixedUpdate for some simple fixed movement scripts.

I solved my stutter issue by setting Application.targetFrateRate = -1, and made sure to turn vSync off (set Quality settings to “Fastest”. For iOS i set the framerate to 60. This completely eliminated my stuttering issue.

@theremin Hate to say this as you provide a good case and it does indeed look like unity is tearing up your tiles / sprite / jpg or whatever.

It’s not.

You need to calculate what speed to move your object that matches the refresh rate of the screen, anything that falls in a non-matching units per frame will tear. We think unity can do anything, but actually this is an old technique that was used since 8bit consoles.

Let’s say your scrolling background is moving at 1 unit per second, at 1:1 zoom, with 100px per unit. Your screen is refreshing at 60hz. So we need to figure out if 100 pixels can move in one second and if the refresh will draw them all. (using Time.deltaTime in update)

100 / 60 = 1.6 – you are moving sub pixels per refresh, this is causing your tearing.
However if you then make the movement speed 0.6 units per second, 60 / 60 = 1 – no sub pixels, no tearing.

Hope this helps! Good old math to the rescue!

(also contrary to comments here, just using “V sync count > every V blank” will give you baby bottom smooth scrolling with a bit of the technique above, using time.deltaTime * unit speed in update.)

Could solve my stuttering by not mixing Update() and FixedUpdate(). Everything should be moved in Update() or FixedUpdate() but don’t mix it.
I’m using Update() because it matches rendering framerate and is the usual way of updating. just don’t use the FixedUpdate()- bullsh*t.

There are a bunch of different reasons this stuttering could be happening. I compiled a short video showing all the fixes that I know of. I hope this helps someone.

Stuttering Video

I was having a similar issue! My game have a bunch of rigidbodies that accelerate each FixedUpdate, using Unity physics. And a camera that was moving using regular transform update. I tried a lot of solutions but always getting the weird jittering effect on the rigidbodies. I then added one rigidbody to the camera and changed the movement code to update velocity instead of position. Works fine!

The problem was occurring because of Vector3.Lerp, when too close.