Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

[Solved] Removing Debug.Log increases framerate and causes rendering jitter

Discussion in 'Scripting' started by jusw85, Feb 16, 2017.

  1. jusw85

    jusw85

    Joined:
    Apr 21, 2016
    Posts:
    21
    I've created a simple 2D project in Unity 5.5.1f1 to recreate my problem:

    I have a gameobject which contains:
    - a sprite renderer which renders a 32x32 solid color box
    - a line renderer

    The transform is moved directly using transform.Translate(), and a script sets the positions of the line renderer between the transform and mouse point on screen.

    Without any Debug.Log statements, the game renders at ~90fps and the line jitters noticeably. I've attached a gif to demonstrate: https://giphy.com/gifs/l3q2xdNZjKrlRlYu4

    With Debug.Log statements, the game renders at ~60fps and the line lags behind the mouse point due to mouse input lag: https://giphy.com/gifs/l3q2Qwi29hWeSkG5y

    I'm measuring the fps using the script at: https://docs.unity3d.com/ScriptReference/Time-realtimeSinceStartup.html

    My question is, why is this happening, how do I prevent jitter from occurring, and how do I keep the line synchronized with my mouse point instead of lagging behind?

    Enter the Gungeon, which also uses Unity, has none of these problems:


    LineController.cs
    Code (csharp):
    1.  
    2.     void Update() {
    3.         var moveInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
    4.         transform.Translate(moveInput * moveSpeed * Time.deltaTime);
    5.  
    6.         var rawMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    7.         var lookPosition = new Vector3(rawMousePosition.x, rawMousePosition.y, 0);
    8.  
    9.         /**
    10.          * If uncommented(enabled), ~60fps and line lags behind mouse point due to mouse input lag
    11.          * If commented(disabled), ~90fps and line jitters
    12.          */
    13.         //Debug.Log("Hello world!");
    14.  
    15.         Vector3[] positions = new Vector3[] { transform.position, lookPosition };
    16.         lineRenderer.SetPositions(positions);
    17.     }
    18.  
    Camerafollow.cs
    Code (csharp):
    1.  
    2.     public GameObject target;
    3.     public Vector3 offset = new Vector3(0f, 0f, -10f);
    4.  
    5.     private void LateUpdate() {
    6.         transform.position = target.transform.position + offset;
    7.     }
    8.  
     
  2. WarmedxMints

    WarmedxMints

    Joined:
    Feb 6, 2017
    Posts:
    1,035
    Have you tried using fixedupdate instead of update and I assume the same thing happens if you build and run it rather than in the editor?
     
  3. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    I created a project similiar to what you have shown. And was getting a little bit of jitter as I was moving. Though not nearly what you show. However, moveing the LineRenderer code to LateUpate as well cleaned it up a little:

    Code (CSharp):
    1.     void Update()
    2.     {
    3.         var moveInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
    4.         transform.Translate(moveInput * moveSpeed * Time.deltaTime);
    5.    
    6.     }
    7.     private void LateUpdate()
    8.     {
    9.         var rawMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    10.         var lookPosition = new Vector3(rawMousePosition.x, rawMousePosition.y, rawMousePosition.z);
    11.  
    12.         /**
    13.          * If uncommented(enabled), ~60fps and line lags behind mouse point due to mouse input lag
    14.          * If commented(disabled), ~90fps and line jitters
    15.          */
    16.         //Debug.Log("Hello world!");
    17.  
    18.         Vector3[] positions = new Vector3[] { transform.position, lookPosition };
    19.         lineRenderer.SetPositions(positions);
    20.     }
     
  4. jusw85

    jusw85

    Joined:
    Apr 21, 2016
    Posts:
    21
    Yup, I tried a whole bunch of stuff before resorting to posting this question.

    My initial code moved via a Rigidbody2D, looked something like the following:

    Code (csharp):
    1.  
    2.     void Update() {
    3.         // grab input
    4.         // ...other stuff...
    5.         // render line
    6.     }
    7.  
    8.     void FixedUpdate() {
    9.         // ...other stuff...
    10.         rigidbody2d.velocity = moveInput.normalized * moveSpeed;
    11.     }
    12.  
    I created a separate project to isolate and recreate the issue.
    I've tried, amongst other things, rendering the line in fixedupdate, rendering the line in late update, moving the rb2d via addforce and moveposition, removing the rb2d altogether, changing the material on the line renderer, tweaking the timestep, running a built exe, using other methods to grab the world point (screenpointoray), etc.

    All scenarios still result in either jitter, or mouse input lag(which I can accept). What strikes me is how random it seems to occur. Sometimes I restart Unity editor, and the jitter goes away for awhile, but happens again later. The fact that a Debug.Log statement can toggle the behaviour suggests to me that it might be a timing issue.
     
  5. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Unity is sometimes a little weird and/or tricky.

    First of all, one of the problems you're facing can be solved completely (Jitter) but maybe both, but that depends on which delay you're takling about (I assume the first one).

    1) The one that can be seen when you (only) move the object and the line lags behind, i.e. is not exactly at the mouse's position? Can be solved. There's a mistake in the logical order.
    2) The delay which you notice when you move the mouse too quickly?

    As far as I know, the system input cannot be tracked completely in "real time" with the current Input system, as it only updates/samples input once per-frame and does not directly poll input in "real time" whenever you ask for it. All the mouse movement which occurs during the frame (until the next sample is taken) is just not tracked and it appears that you've got a sligth delay when moving your mouse to fast. Not sure if prediction techniques could help here. But I wouldn't consider this annoying.
    *Edit Check @takatoks answer below, that would eliminate this kind of delay from these mid-update-changes

    Anyways, what's causing that one specific part of the delay, and why does it cause what you describe as jitter?

    In short: You're missing an essential detail in the execution order of your game logic.
    Skip to the listing of execution order in the end if that's too much to read.


    But first, let's see why that effect, which you call jitter, appears to be more obvious, especially with higher FPS.

    => instable framerates.

    Just for example, select a moving object so that you can observe it in the inspector, the FPS in the stats window will usually increase (on all of my machines at least) but is usually more instable (you can verify that with logging).

    Contrary, If you select nothing so that the inspector is not constantly redrawn, FPS appear to be more stable and also (usually) lower. The stable framerate reduces the visual jittering effect, naturally.
    When you've got a high framerate, a peak in the frame update time can sometimes be more noticeable and that's what's causing the visual jittering effect, which (again) only occurs due to the actual mistake which let's your line appear to lag behind.

    Now assume you've got completely stable FPS rate. You wouldn't notice the jittering anymore, but there's still a problem which contributes to your input lagging behind and, in the end, will be the reason the jitter effect can actually occur.

    The camera plays an important role in your setup and your game logic, it's something you may not think about unless you face effects as those described in your post.

    You're executing your game logic in the following order.
    1) You retreive mouse movement input in Update and move the object in update. That's correct.
    2) From now on you can retreive the start position for your LineRenderer. (You're actually doing that in 4, that's totally okay as the object has finished moving).So that's correct.
    3) You retreive the mouse position (still) in Update and transform it into world space coordinates in order to get the LineRenderers end-position. Is that correct? Wait...
    4) You set the LineRenderers positions. Well, 2) was correct, but 3 might be wrong... So this might be wrong as well
    5) You set Camera's position (in LateUpdate), as it depends on the tracked final position of the tracked object Nothing wrong with it.

    It starts to get messed up in step 3.
    Think about it... You're using the camera to transform the mouse's screen position into world space coordinates. But the camera has still to be moved later on... For the rendering part, you've actually polled the end position too early.
    It'll be a position that was calculated using the camera's old position. So there'll be tiny offset which might be your "delay" unless you're talking about the other part of it, which I mentioned above.

    Now finally, I hope you're still encouraged to try this order:
    1) move the object with the mouse axis input, when it's done, your LineRenderer's start position is ready to be used
    2) move the camera here (LateUpdate or ensure the Update is called after the LineControllers Update) - I'd say keep LateUpdate
    3) now retreive the end position using the camera's new position
    4) set the LineRenderers positions

    The line should always be on point, except for the mouse position changes which occur during 2 input samples.
     
    Last edited: Feb 17, 2017
  6. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    The problem of losing mouse position in between frames could also be gotten around by implementing your own cursor. You disable the OS's cursor, and create your own cursor that you move during Updates. This will naturally mean your cursor's position will always match Input's position
     
    Suddoha likes this.
  7. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Oh damn ye, that's a good point and the third thing to do.
     
  8. jusw85

    jusw85

    Joined:
    Apr 21, 2016
    Posts:
    21
    Holy crap everyone, thanks for all your help, it works beautifully!
    Superb explanation Suddoha, these are nuances you won't learn from tutorials until you're hit with these weird issues.

    In the end, I solved it using what takatok posted earlier. The reason why it wasn't initially working, and what I did to fix it, was to setup the script execution order so the line rendering script runs after the camera move. So the order of execution is:
    - Player move Update
    - Camera follow LateUpdate
    - Get position of end point and render line in LateUpdate

    Good point on the custom cursor as well, gonna try it.

    Gonna mark this as solved!
     
    fffds likes this.
  9. fffds

    fffds

    Joined:
    May 28, 2018
    Posts:
    1
    thanks it helped me