- Home /
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).
Do you have pro? Have you tried looking at the profiler for spikes? Garbage Collection hit perhaps? Or is it all too simple for that ?
It may be garbage collection hit - try having a single global or static Vector3 that is only instantiated once and then copy the transform position into it, modify it, and then set it back to the transform. Each of your cases you are allocating a new Vector3 every frame.
Perhaps the problem is the fast frame rate of the scene when locked to VSYNC is such that we occasionally run too far ahead of the GPU and must occasionally wait (in the engine). It may be that a more complex scene would not stutter like this simple one does. I haven't tried accessing synchronization functionality in Unity yet, but perhaps you could introduce your own frame rate limiting system to make sure the game is running at 60 fps (and not artificially capped at 60 fps by vsync waits). If Unity is double buffered, or triple buffered internally it is still the case that submitting such a simple scene so quickly could cause the CPU to race ahead and need to throttle occasionally.
@mortoc - no even that wastes a Vector3 doesn't it? The one that used to be the transform.position before _targetPosition was copied into it (being a value type it's copied and the old one discarded right?)
Hi,
I submitted this as a bug report and the result was:
"I've been looking and this seems to be a pretty fundamental problem with the OSX web player.
As you surmised, it's related to frame-rates, although not specifically to FPS capping. The jitter comes from several different interactions between our web player's ti$$anonymous$$g code, the browser's plugin handler, and the graphics drivers.
Properly fixing the issue could take a few weeks, or even longer. Once a fix is found, the changes would have to go through our release process, so it's impossible to predict a resolution date.
I understand that this really sucks. To help you try to work around this, I took some tools from this thread: http://forum.unity3d.com/threads/162694-Smooth$$anonymous$$ovementTest-should-help-eli$$anonymous$$ate-Hiccup-sources
After some fiddling, I found that turning off vsync and setting a framerate of 61 FPS seemed to $$anonymous$$imize the issue for me. However, the issue is heavily dependent on hardware, OS and browser - what smooths things out on OSX/Chrome may make it worse on Windows/Firefox."
Answer by Wolfram · Jun 26, 2012 at 11:01 PM
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).
If you are experiencing regular hiccups (for example, each second), check your other running stuff: a clock widget would spring to $$anonymous$$d. Or even a Windows Task $$anonymous$$anager with the "Process" tab open. It took us a while at some point in the past, figuring out that the task manager was causing regular hiccups, even when our app was running fullscreen and the task manager therefore was not visible.
This is amazing information, thank you. It seems like I'm basically out of luck. I'm still left wondering how all of these other game developers get their games to run perfectly smooth (even on my system!)... But I guess not everybody does. Two examples come immediately to $$anonymous$$d: Fez really stuttered on my Xbox, and the title screen of SophieH's game here (where the pink clouds are floating past) also exhibits the same stuttering behavior: http://www.sophiehoulden.com/games/UVP4/
Ah well, maybe I just need to deal with it :) Thanks again for your response.
Just saw your comment: That's also a great point. I still have to look into what other programs are running (@Bunny83 also mentioned that in his answer). I've rebooted a few times, but I'll try to dig a little deeper and kill every process I can.
I'm still left wondering how all of these other game developers get their games to run perfectly smooth
Remember it will very much depend on the type of motion, as @Bunny83 explained: some examples that shouldn't show any noticeable stuttering (which doesn't necessarily mean that there is no stuttering!) include a rolling ball that slowly comes to a stop, a walking character, a panning 3rd person camera, or leaves and twigs bending in the wind. As these are all non-linear motions, your brain will be much less sensitive to any inconsistencies in the movement. On the other hand stuttering in moving clouds, a slowly driving car, or other types of linear motions will be much more noticeable, especially since there is a (relatively fixed, but marginally fluctuating) "constant" ratio between animation progression and framerate.
It would be interesting if you see games/game engines that do not generate stuttering linear animations.
@Wolfram: That's an excellent point. Hmm... Well, one that springs to $$anonymous$$d that I played recently (which is excellent by the way!): Home by Benja$$anonymous$$ Rivers ( http://homehorror.com ). I'm not sure what he used to develop it, but it's a side-scroller and there are no blips or hiccups in the motion at all. (Just reconfirmed.) $$anonymous$$aybe I'll have to e-mail him to ask him about it :)
Answer by Bunny83 · Jun 26, 2012 at 11:13 PM
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 ;)
@Bunny83: Thanks for the response! Very helpful information. I also can't see a difference between 2 and 3, but I just wanted to be thorough :) So you don't see the hiccup in #1, even after letting a few cubes go by? Again, it's not constant; it's just an occasional hiccup that only occurs every 1-3 seconds. As far as I can tell, not everyone sees it on their system. It's smooth for some people and not for others. Just out of curiosity, what is your video card?
@there$$anonymous$$: On this PC it's even a quite old NVidia GeForce 8600 GTS (256$$anonymous$$B) with two monitors ;). I still have FireFox 4.0 here and the plugin container is disabled since it causes a lot of trouble in the past. Don't know if it's better in the current version.
Have you tried a standalone build?
Thank you for taking the time to answer this. I was doing my movement logic in fixed update, ins$$anonymous$$d of update, and it was causing me so many headaches. Only wish it hadn't taken me 6 hours to find your post :)
Answer by AnomalusUndrdog · May 06, 2013 at 07:20 AM
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.
God... Thank you! I'm also using an old laptop, but I've never noticed that with older versions of Unity. I was turning crazy. Thanks again, you made my day!
Thank you! I was testing the scene and the stats indicated 100+fps but the camera look was definitely jittery, but having nothing selected in scene view fixed it! Thanks again!
Fast forward to 2018. Deselecting everything within Unity didn't fix the very noticeable jitter for me, but then I tried running a release build and that was completely smooth. I'm guessing it probably still has something to do the development tools.
Answer by jankymidget · Jul 29, 2015 at 07:52 AM
I set QualitySettings.vSyncCount = 0;
and my stutter problems were fixed. It defaulted to 1, and this introduced a periodic annoying stutter.
Thank you. Putting this in my player movement script helped smooth out the jumpiness issue.
void Start () { QualitySettings.vSyncCount = 0; } void Update () { var x = Input.GetAxis ("Horizontal") * Time.deltaTime * speed; transform.Translate (-x, 0, 0); }
This is identical to turning vsync off entirely: https://docs.unity3d.com/ScriptReference/QualitySettings-vSyncCount.html
Answer by Vystyk · Nov 01, 2015 at 01:28 PM
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.
A managed model like yours is really a good solution, it's something unity was just talking about and you can already see huge improvements in the performance !, check it out here:
This answer need more attention, I resolved this issue by using the same technique, after a LOT of trial and error
Your answer
Follow this Question
Related Questions
Frame dependant game. Using update vs fixed update. 3 Answers
FixedUpdate limits: consistant 0.01 s on mobile devices? 1 Answer
Exact difference between fixedDeltaTime and deltaTime? 3 Answers
FixedUpdate performance doubts 2 Answers
Placing Input.GetkeyDown() inside FixedUpdate() slows down the rate I can fire at 1 Answer