Time.deltaTime Not Constant: VSync CameraFollow and Jitter

Are you testing with a multiple monitor setup by any chance? Then this is a fairly old issue. The 2 ms is an as fast as you can render scenario and the 31 ms balances that to the correct average. It’s not that there are any other variations. There are just these spikes. So you have three types of frame really, 1/60, “as fast as you can” and (2/60 - “as fast as you can”).

It would be nice if this finally got fixed, because VR setups are generally multiple monitor setups by design.

Hello everyone,

OK so I’ve been spending a couple of days on this, performing little experiments inside and outside Unity to try and figure out what has been going on. I won’t say I’ve got to the bottom of everything, but I discovered some stuff which I’ll share with you. If anyone else has some more findings I’m keen hear it too!

The first thing I have discovered is there is a big difference between Editor and Standalone Player on Windows. In the standalone player, the code calls timeBeginPeriod(1) whereas in the Editor it does not. For the difference, have a read of this:

Now if you think about it, this makes sense, because in the Editor you are typically multitasking, maybe you are at a Game Jam, you want your battery to last as long as possible. In the Standalone you are saying “I want the game to be as smooth as possible”. So that’s why animation is particularly uneven in the Editor.

In standalone, I didn’t get to the bottom of the occasional 1-frame glitching (although it does seem to be happening a lot less for me recently), but I think I can explain the variance in the deltaTime. I think it’s just inherent timing inaccuracy.

For this I took a standard DX9 program, with a Present call, and added this code to measure the time delta:

    if (GetAsyncKeyState(VK_F1) & 0x8000)
    {
        LARGE_INTEGER qpft = {0};
        QueryPerformanceCounter(&qpft);
        long long now = qpft.QuadPart;
        static long long prevTime = 0;
        long long delta = now - prevTime;
        double msec = (double)delta / 2435.778;

        HWND hwnd = FrameWnd;
        if (hwnd)
        {
            char text[128] = {0};
            sprintf(text, "PresentFrame msec = %8.4f", msec);
            SetWindowTextA(hwnd, text);
            prevTime = now;
        }
    }

Sure enough the frame delta varied in just the same way: 16.88, 15.77…
So I think it’s just inherent to the PC/Windows system, not a Unity problem per se.

I’d be very curious if someone else can reproduce (or not reproduce!) my results with a non-Unity program.

I have heard that timing is a lot more consistent on PS4, which makes sense in an environment where there is a lot less going on in terms of other processes.

1 Like

Yes I have 2 monitors.

That’s right, it has nothing to do with Unity, I have just posted this as I have found this interesting. I have tested this on iMac from 2011.

I don’t know how you count your 2%, post your equation please. Using your 8.333 it’s still 5%
(8.75-8.333)/8.333 * 100 = 5%
It’s the maximum difference, but we are talking here about the worse case not the average case.


X axis is each Update sample point
Y axis is Time.deltaTime
5.6.1f1

If anybody is reading/watching this thread would you mind creating a blank new project and a blank scene with this script. What kind of Time.deltaTime variation do you see (both in the editor and when building an executable).

using UnityEngine;
using System.Collections.Generic;
public class FPS : MonoBehaviour
{
    private List<float> listDeltaTime = new List<float>();
    private const int pixelWidth = 256; //for texture2D
    private const int pixelHeight = 128; //for texture2D
    private Texture2D texture2D;
    private const float deltaTimeMax = 0.05f; //for texture2D
    private static readonly Color colorDarkGrey = new Color(0.3f, 0.3f, 0.3f);
    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
        for (int i = 0; i < pixelWidth; i++)
        {
            listDeltaTime.Add(0.01f);
        }
        texture2D = new Texture2D(pixelWidth, pixelHeight);
        texture2D.filterMode = FilterMode.Point;
    }
    private void Update()
    {
        listDeltaTime.RemoveAt(0);
        listDeltaTime.Add(Time.deltaTime);
        RefreshTexture2D();
    }
    private void OnGUI()
    {
        float deltaTimeAve = Average(listDeltaTime);
        float deltaTimeMin = Mathf.Min(listDeltaTime.ToArray());
        float deltaTimeMax = Mathf.Max(listDeltaTime.ToArray());
        GUI.Label(new Rect(10f, 10f, 200f, 20f), "DeltaTime (Average) = " + (deltaTimeAve * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 30, 200f, 20f), "FrameRate (Average) = " + (1f/ deltaTimeAve).ToString("0"));
        GUI.Label(new Rect(10f, 50, 200f, 20f), "Time.deltaTime = " + (Time.deltaTime * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 70f, 200f, 20f), "deltaTimeMin = " + (deltaTimeMin * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 90f, 200f, 20f), "deltaTimeMax = " + (deltaTimeMax * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 110f, 200f, 20f), "% Variation = " + ((deltaTimeMax/ deltaTimeMin -1f) * 100f).ToString("0.0") + "%");
        GUI.DrawTexture(new Rect(0f, 200, Screen.width, texture2D.height*2), texture2D);
    }
    private void RefreshTexture2D()
    {
        Color[] pixels = texture2D.GetPixels();
        for (int i = 0; i < pixels.Length; i++)
        {
            pixels[i] = Color.black;
        }
        texture2D.SetPixels(pixels);
        float deltaTimeMin = Mathf.Min(listDeltaTime.ToArray());
        float deltaTimeMax = Mathf.Max(listDeltaTime.ToArray());
        int yMin = GetY(deltaTimeMin);
        int yMax = GetY(deltaTimeMax);
        for (int i = 0; i < pixelWidth; i++)
        {
            texture2D.SetPixel(i, yMin, colorDarkGrey);
            texture2D.SetPixel(i, yMax, colorDarkGrey);
        }
        for (int i = 0; i < pixelWidth; i++)
        {
            int y = GetY(listDeltaTime[i]);
            texture2D.SetPixel(i, y, Color.white);
        }
        texture2D.Apply(false);
    }
    private static int GetY(float deltaTimeIn)
    {
        return Mathf.Clamp(Mathf.RoundToInt(deltaTimeIn / deltaTimeMax * pixelHeight), 0, pixelHeight - 1);
    }
    private static float Average(List<float> listFloatIn)
    {
        float average = 0f;
        for(int i = 0; i < listFloatIn.Count; i++)
        {
            average += listFloatIn[i];
        }
        average = average / listFloatIn.Count;
        return average;
    }
}

I typically see 50-100% Time.DeltaTime variation (jitter) in the .exe build (Windows). What do you guys see?

Any idea how to fix this Unity jitter issue? Still unsure why a blank project with Vsync enabled sees 100% Time.deltaTime variation that causes all this jitter.

Please. Anybody with a Windows machine mind running that script really quick and seeing what Time.deltaTime jitter variation you have?

I’m not sure what exactly you’re trying to prove and furthermore how you do it, but I ran your script and in editor I get 4-10% variation. In build I get 60-120% jitter. Win7.

1 Like

Thanks for testing. Appreciate it.

It must be related to my machine. In build…
-I get 20-100% jitter.
-My friend only gets 5-7%.
-You get 4-10%

I do not know what could be causing my machine to be so bad. I have no programs running and it’s a new high-end machine (GeForce 1070, SSD).

It’s impossible for me to make a smooth game when a blank Unity project has ~100% Time.deltaTime variation!

Also its strange. Moving my mouse has a massive effect on jitter. If I hold my cursor still the Time.deltaTime variation is much smaller.

On a fresh reboot closing all programs and tasks holding my mouse still I get 5%. Moving mouse I get 30%.

And your friend probably only has one.

I just tried it in 2017.1. I get 5-25% in editor. In a build I get like over a 1000% variation:

3145702--238894--upload_2017-7-15_1-52-33.png

Also note I have two monitors

1 Like

Anybody have any luck figuring out how to fix this Time.deltaTime variation that causes visual jitter?

My only thoughts are that all VR work going on is probably going to shine a light on anything like this. Those platforms have very specific frame timing goals.

One thing you need to be aware of when running builds to test is that you should not have the Unity editor also running in the background. Easy mistake to make and does the pauses you guys are talking about. It also does that to netflix running in the foreground.

For me the editor is a piglet that bounces around leaving a complete mess.

1 Like

I get noticeable jitter in Time.deltaTime even on device (an old iPad). I have one counter that’s counting the frames that are being rendered and it’s a rock-solid 60 per second. Next to it is a number showing me 1 / Time.deltaTime. You’d expect that to stay stable at 60 too, but it’s constantly vibrating between 57 and 63, and on occasional frames it dips to under 45 for no apparent reason. No frames are dropped, it’s just a constant 5% variance with the odd 30% slower deltaTime.

Every frame I’m calculating and visualizing an object’s velocity (distance / deltaTime), and it’s fairly smooth despite the variance. (Hence why most games, including my own, look fine with it) But I’m also calculating its acceleration (velocity / deltaTime), and that compounded error makes for noticeable noise even when damped.

For sensitive values I’m going to have to write my own “.quantizedDeltaTime” to round off deltaTime to exactly 90/60/30/15fps and base my math on that instead.

1 Like

Yes I’m also considering filtering/locking the deltaTime (instead of using the varying time.deltaTime). My only worry is that if frames start to drop or slow down then doing this would create many unintended consequences.

Since this deltaTime variation occurs on multiple (all?) platforms and regardless of loading (it occurs with a simple blank project) I’m surprised that everybody isn’t experiencing this issue.

1 Like

Everybody.
Sadly, recently devs don’t even care about system integration stuff. Nobody. Check Steam for example.
I experience justters and stutters with every single Unity game. In Unreal games I have another issue: resolution scale. And Source games (Valve) seem smooth as… baby skin. Spelunky is also smooth. Even in INSIDE I has some stuttering, on an i7/nVidia 970 / 16 G DDR4.

Now I do have issues with timing. Getting 200 FPS with VSYNC off and getting 60/60 dropping in half (30/60) with VSYNC On. I have no idea what happens, actually, but on 120hz monitor it is unacceptable to have 72 and even 48 fps lockdowns with no reason.

About system integration, I posted https://fogbugz.unity3d.com/default.asp?975924_otd1ouli7el4jvi0 - hopefully they will address this because it does not happen for me in Source games, and the scene isn’t that huge.

I can basically get perfect timing only on 60/60 (60 hz). Why I have 120hz monitor if the game just jitters all over the place.

As of the above code: ~100-200 jitter with two monitors on.
~15-30 jitter with one monitor only.
[and smoother experience]

Ugh.

I was thinking of creating a SmoothTime.deltaTime script. Something along the lines of
1: Access the monitor vsync rate (i.e. 60Hz, 120Hz). Is there a way to do this? Calculate vSyncDeltaTime = 1/VsyncRate (i.e. 16.67ms for 60Hz or 8.33ms for 120Hz).
2: If time.deltaTime is ~= vSyncDeltaTime then SmoothTime.deltaTime would return exactly vSyncDeltaTime.
3: Else in the event of dropped frames/slowdown then SmoothTime.deltaTime wold return the closest rounded whole multiple interval of vSyncDeltaTime. (i.e. for a 60Hz monitor it would return exactly 16.67ms (no dropped frame), 33.33ms (1 dropped frame), 50.00ms (2 dropped frames), etc.

Do you think some bandaid like this could solve our jitter problems? See any issues with it?

I think this could improve jitter for manually moved objects. However things that are automatically moved by Unity (i.e. rigidbody physics) I believe rely internally on Time.deltaTime and therefore would jitter (unless you detach the object’s visual mesh from the rigidbody and do a bunch of fancy compensation calcs?).

Issue still exists 2017.2.0f3. I just bug reported
https://fogbugz.unity3d.com/default.asp?977641_r0jbe37tl5p0h0sk

If anybody is reading/watching this thread would you mind creating a blank new project and a blank scene with this script. What kind of Time.deltaTime variation do you see (both in the editor and when building an executable).

using UnityEngine;
using System.Collections.Generic;

public class FPS : MonoBehaviour
{
    private List<float> listDeltaTime = new List<float>();

    private const int pixelWidth = 256; //for texture2D
    private const int pixelHeight = 128; //for texture2D

    private Texture2D texture2D;

    private const float deltaTimeMax = 0.05f; //for texture2D

    private static readonly Color colorDarkGrey = new Color(0.3f, 0.3f, 0.3f);

    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
        for (int i = 0; i < pixelWidth; i++)
        {
            listDeltaTime.Add(0.01f);
        }

        texture2D = new Texture2D(pixelWidth, pixelHeight);
        texture2D.filterMode = FilterMode.Point;
    }

    private void Update()
    {
        listDeltaTime.RemoveAt(0);
        listDeltaTime.Add(Time.deltaTime);
        RefreshTexture2D();
    }

    private void OnGUI()
    {
        float deltaTimeAve = Average(listDeltaTime);
        float deltaTimeMin = Mathf.Min(listDeltaTime.ToArray());
        float deltaTimeMax = Mathf.Max(listDeltaTime.ToArray());

        GUI.Label(new Rect(10f, 10f, 200f, 20f), "DeltaTime (Average) = " + (deltaTimeAve * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 30, 200f, 20f), "FrameRate (Average) = " + (1f/ deltaTimeAve).ToString("0"));
        GUI.Label(new Rect(10f, 50, 200f, 20f), "Time.deltaTime = " + (Time.deltaTime * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 70f, 200f, 20f), "deltaTimeMin = " + (deltaTimeMin * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 90f, 200f, 20f), "deltaTimeMax = " + (deltaTimeMax * 1000f).ToString("0.000") + "ms");
        GUI.Label(new Rect(10f, 110f, 200f, 20f), "% Variation = " + ((deltaTimeMax/ deltaTimeMin -1f) * 100f).ToString("0.0") + "%");

        GUI.DrawTexture(new Rect(0f, 200, Screen.width, texture2D.height*2), texture2D);
        GUI.Label(new Rect(200f, 180f, 400f, 20f), "X-Axis: Sample             Y-Axis: Time.deltaTime");
      
    }

    private void RefreshTexture2D()
    {
        Color[] pixels = texture2D.GetPixels();
        for (int i = 0; i < pixels.Length; i++)
        {
            pixels[i] = Color.black;
        }
        texture2D.SetPixels(pixels);

        float deltaTimeMin = Mathf.Min(listDeltaTime.ToArray());
        float deltaTimeMax = Mathf.Max(listDeltaTime.ToArray());
        int yMin = GetY(deltaTimeMin);
        int yMax = GetY(deltaTimeMax);

        for (int i = 0; i < pixelWidth; i++)
        {
            texture2D.SetPixel(i, yMin, colorDarkGrey);
            texture2D.SetPixel(i, yMax, colorDarkGrey);
        }

        for (int i = 0; i < pixelWidth; i++)
        {
            int y = GetY(listDeltaTime[i]);
            texture2D.SetPixel(i, y, Color.white);
        }
        texture2D.Apply(false);
    }

    private static int GetY(float deltaTimeIn)
    {
        return Mathf.Clamp(Mathf.RoundToInt(deltaTimeIn / deltaTimeMax * pixelHeight), 0, pixelHeight - 1);
    }

    private static float Average(List<float> listFloatIn)
    {
        float average = 0f;
        for(int i = 0; i < listFloatIn.Count; i++)
        {
            average += listFloatIn[i];
        }
        average = average / listFloatIn.Count;
        return average;
    }
}

@Zullar With VSync. Editor: ~15.435 ms / ~17.253 ms (~10%). Standalone build: ~16.349 ms / ~17.075 ms (~5%).
Without VSync. Editor: ~4.510 ms / ~13.447 ms (~200%). Standalone build: ~2.631 ms / ~3.222 ms (~25%).

1 Like

@nxrighthere Thanks for running. I wonder why you see such less jitter than I do. For your standalone build you see 5%, but I see around 120% when moving mouse. What kind of hardware you running? Windows 10? 1 monitor or 2? Does moving your mouse affect the % jitter?