SmoothMovementTest, should help eliminating Hiccup sources

Hi, dont know if this thread belongs here but it may be of interest for some people:

i was tinkering around a bit with Unity’s Rigidbody interpolation modes and wanted to create a little testing scene… i added some options for vsync and frame rate limitation… i was able to get a hiccup free movement (with vsync of course). Any thoughts or feedback on the topic of “smooth object movement” or this little package i made, are welcome :smile:

1112386--48943--$Capture.PNG

Try it here:
http://marrt.elementfx.com/index.html?file=SmoothMovementTest.unity3d

or download the package V1.2:
1112386–61840–$SmoothMovementTest.unitypackage (69.7 KB)

Original Thread that bugged me:

Notes:
don’t expect smooth movement in standalone without vsync

  • single frames WILL be dropped and/or others WILL be shown for 2 screen cycles, this is very noticeable in my testsetupdon’t expect smooth movement in the editor, any time
  • various reasons i don’t really know much about but who cares about editor smoothness anywaydon’t expect smooth movement in webplayer if the browser or VGA caps the framerate:- http://forum.unity3d.com/threads/153008-Unity-3-5-6f4-generates-lower-FPS-in-WebPlayer**ONLY expect smooth movement if the following conditions are met:**
  • vsync is set to 1 (or 2 for every 2nd frame, but 2 will appear jerky even if no frames are dropped)- the framerate isn’t capped below your screen refresh rate by any means (e.g. webplayer caps at 50 for me, so i only have smoothness when i manually set the screen refresh rate of my hardware screen <= 50)- the object or camera -position, is updated in Update. If your object has a rigidbody it will only change position in Fixed Update (if unity-interpolation doesn’t work, try my manual interpolation)
5 Likes

Its bad that nobody has replied so far since this is an important fix for an annoying issue.

I can definately verify that the following helps reduce/fix jittery movement when applying manual transform and not being able to use rigidbody interpolation mode:

// extrapolate visual position based on position of rigidbody at last fixed update
transform.position = MyRigid.position + MyRigid.rigidbody.velocity * (Time.time - Time.fixedTime);

Say, do you also have a solution for rotation smoothing when not using force/torque since I dont really have velocity for that?

Example:

_currentRotation = Quaternion.Euler(Vector3.Lerp(_currentRotation, targetRotation, lerp));
transform.localRotation = _currentRotation;

Thanks

Hi, i also added manual interpolation in my implementation, maybe it can help you with your rotational stuff.

if i am using vsync=1 i do interpolation otherwise extrapolation
i cant exactly remember why i did this (did so much completely other stuff in the meantime) but i just quickly post what i currently do:
the code for the interpolation looks like this:

//Info
//shipModelTransform:	my rigidbodyless camera target
//trueShipTransform:	my shipParent with a driven rigidbody and collider
//previousPosition:		save previous position for interpolation in FixedUpdate, init can be Vector3.zero

//in Update()
float lerpFactor = ((Time.time-Time.fixedTime)/Time.fixedDeltaTime);				
if(extrapolate){
	//extrapolation
	shipModelTransform.position = trueShipTransform.position + ((shipRigidbody.velocity)*lerpFactor*Time.fixedDeltaTime); //
	shipModelTransform.rotation = trueShipTransform.rotation;
		//i dont do rotational extrapolation, but i you have to you should use Rigidbody.angularVelocity i guess
}else{
	//interpolation
	shipModelTransform.position = Vector3.Lerp(previousPosition, trueShipTransform.position, lerpFactor);
	shipModelTransform.rotation = trueShipTransform.rotation;
}

//in FixedUpdate()
previousPosition = trueShipTransform.position; //you would have to save the rotation too

i just rotate my ship in Update since it has a simple capsule collider and therefore rotational collisions can be neglected.
if you rotate your object in FixedUpdate and want smoothness in Update… but without using angular velocity…

then the interpolation case above should work for you but i haven’t tested it sufficiently, please tell me if you succeed

hope it helps

EDIT: fixed code a bit, removed notes that made no sense in context

Would be interesting to know why you are doing this since I am currently only using extrapolation since you dont need additional variables but maybe thats wrong.

I just fixed rotation smoothing using extrapolation by calculating the angular velocity myself in fixed-update:

Vector3 newRotation = Vector3.Lerp(_currentRotation, targetRotation, lerp);
_currentAngularVelocity = (newRotation - _currentRotation) / Time.deltaTime;
_currentRotation = newRotation;

transform.localRotation = Quaternion.Euler(_currentRotation);
float extrapolationLerp = Time.time - Time.fixedTime;

// extrapolate visual position based on position of rigidbody at last fixed update
_visual.localPosition = _currentPosition + _currentVelocity * extrapolationLerp;
_visual.localRotation = Quaternion.Euler(_currentRotation + _currentAngularVelocity * extrapolationLerp);

Anyway thanks for posting your solution. Helped a lot :slight_smile:

i think i did this by testing, getting the best results with interpolation when vsync was on… otherwise everthing was jumpy
But i noticed a mistake now, i set previousPosition in both, Update() FixedUpdate()… i updated my previous post, extra intrap. should be both usable in any vsync case now. But i currently have no access to my code and cant test it though.

Hi, i added a few things and improved the UI

-now includes both, inter- extrapolation
-for position rotation
-added physics-timestep slider

check first post for source and webplayer, ignore all above code samples, they are implemented in it

Thanks for this – was building something similar so it’s nice not having to reinvent the wheel.

Ever figure out why the 60f was necessary?

cube.transform.rotation = cubeRigid.transform.rotation * Quaternion.Euler(cubeRigid.rigidbody.angularVelocity*lerpFactor*Time.fixedDeltaTime*60F);
//quaternions (rotations) are aggregated by multiplying them. I have no idea why i need 60F at the end, but it seems to work with any frame rate

I’m surprised by how bad it runs w/o vsync, at least on my iMac – near constant tearing and movement wasn’t even close to smooth. Will have to check other machines/games, but I usually play games with vsync disabled and don’t notice nearly as much tearing or jitter.

This is all overcomplicating things in my view. Best smoothness:

//vsync on and…
a += amount * Time.smoothDeltaTime;

That does the trick just fine. Very smooth on all 6 tested devices/platforms. With vsync off, it handled very well still. Perhaps try smooth sometime, it might work for you.

Sometimes things get complicated. Like if you need physics-based movement for a player, but also need mouselook. Unity’s interpolation/extrapolation work for rigidbodies when you’re moving/rotating them with forces, but not when you’re manipulating them manually (like you’d typically do with mouselook). His custom interp/extrapolation would allow proper physics calculations in FixedUpdate but with smoothed movement and rotation in Update.

i expect that Time.smoothDeltaTime will give bad results if the framerate varies greatly, but then smoothness would be bad anyway…

long time has passed since i last looked into this issue, it seems that currently my web-build stays on 58 frames for some strange reasons (a single stutter every second).
But standalone is perfectly smooth with 60… However, my main game (top down shooter thingy) is perfectly smooth even in web-player despite the camera being locked onto rigidbodies, maybe i should check the code for this testsetup again next year when i have time again.

For me all the fuss was only about getting my camera hard-locked (no laggy smooth follow) onto my rigidbodies without stuttering, and for my little game it worked out… but Unity-Rigidbody-Interpolation should be working in the same way as my test-setup should show

Hi Marrt, thanks for your research and the nice demo!

I’m trying to get your custom extra-/interpolation working on the new Unity First Person Controller (which now has a rigidbody):

The extrapolation seems to work, but the player then moves at double the speed, so i must be doing something wrong. Any ideas?

// in Update()
if(extrapolate)
{
     transform.position = rigidbody.position + ((rigidbody.velocity) * lerpFactor * Time.fixedDeltaTime); //
}

// in FixedUpdate()
previousPosition = rigidbody.position;
// new velocity:
rigidbody.velocity = desiredMove + Vector3.up * yv;

To test the jitter on the new FPS Controller, make the Run Speed higher (something like 30), Strafe around an Object while always looking at the Object.

I am not using VSync.

Hmm, why did you search for this solution? did you experience a visual stutter? i guess you have tried Unity’s intergrated inter/extrapolation (dropdown at the rigidbody component) already?

About the problem with double speed: Your rigidbody is tied to the transform you are extrapolating. Currently Unity applies the velocity-position-change in FixedUpdate(), and you apply an additional position change in Update(). In my Solution the Transform that is extrapolated has to be detached from your rigidbody, a seperate object without a rigidbody, only for visuals.

In your case the “Transform” that has to be smooth is the Camera, so just get the camera detached from your rigidbody. Out of my head this would be the fix: just detach the camera, get a reference to its transform (in Start() yourCameraTransform = GameObject.Find(“YourCameraName”).transform) and modify its position:

// in Update()
if(extrapolate)
{
     yourCameraTransform.position = rigidbody.position + ((rigidbody.velocity) * lerpFactor * Time.fixedDeltaTime); //
}

// in FixedUpdate()
previousPosition = rigidbody.position;
// new velocity:
rigidbody.velocity = desiredMove + Vector3.up * yv;

Wow, thanks a lot for the fix… It’s working really smooth now - finally :slight_smile:

Yes, there is stutter and the integrated interpolation did nothing.

Nice, good that this actually helped someone. I also would recommend using Interpolation rather than extrapolation, with extrapolation your camera could move through walls for one or two frame if you have fast movement and a small character collider.

But it is really strange that Unity’s Extra/interpolation doesn’t work for you since its exactly the thing that they invented it for. I’ve made small testsetups where Unity’s-Smoothing worked, in a gametest of mine however, it didn’t work. Must have something to do with how much children the smoothed rigidbody-object has or something, i don’t know.

Thanks for the tip on inter/extrapolation, I’ll do some testing.
Well yes it’s strange that unity’s interpolation doesn’t work in this case - i have no idea why.

This hiccup/stutter problem seems to be a recurring topic in many threads and unity questions. This thread in particular appears to have made the most progress.

The most basic example I can think of is by using Unity’s 2D platform sample from the asset store.

If you delete the tower and duplicate the bridge side by side like in the screenshot attached below and run left/right you can see the clouds in the background stutter (everything actually, but the clouds are easier to spot).

Marrt, how would you go about applying your method to fix the Unity’s sample?

If you’re doing any of this within the Unity editor and not standalone, then it will probably always have micro stutter (on windows). Must test standalone.

I’m testing with a standalone build.

Hi, i found some time and took a look at the build Unity offers, these are my quick thoughts, perceptions and a solution, please dont mind my dirty writing style, i wrote it while scripting this out:

  1. Info (blabla)
  2. Solution Info (blablablabla)
  3. Solution Source (skip above and just test those damn scripts)

1. INFO:
Yes, it is stuttering like shit and the Unity-Interpolation doesn’t do anything, why do they even release something like this??

  • 3 possible sources of the stutter: camera-movement-script, parallax-scrolling-script and the character-controlling-scripts

Parallax script: Should be fine, it updates in Update()… but we keep in mind that the camera-script may be called before the scrolling-script, so we should set the camera Updater to LateUpdate() later.

Camera Follow: uses Fixed Update, that means the camera re-positioning happens in physics frames, not in the render frames. We have to fix this! (-> put every “transform.position = …” into Late Update and inter-/extrapolate the Rigidbody-position-input for the renderframes)

Character Controller: The CharacterController is a script that sets the Characters velocity and applies forces, so everything in here is physic-engine dependent, nothing is setting positions directly, that’s fine so far.
We take a look at the Character Game Object and find that it has Rigidbody Interpolation enabled so if we access the transform position of that gameobject in Update(), it should appear smooth due to Interpolation (Unity - Manual: Rigidbody component reference), but it isn’t.

2. SOLUTION INFO:

Solution1. You could set the Camera to follow the interpolated rigidbody position (renderPos in script):
-problem, rigidbodys will still jitter around like crap, try the source. In this source the Camera is pinned to the renderPos. I also edited the “TrackPlayer”-function because the smooth follow was messed up because it was tied to the jumpy rigidbody. In code, look for this to switch between inter or extrapolation, tracking mode is set via a bool flag:

void LateUpdate (){  
        //Choose Inter, or Extrapolation:
        CameraInterpolation();
    //    CameraExtrapolation();  
  
        //default track function, if you like it, set the trackFunction bool
        if(trackFunction){TrackPlayerNEW();}
    }

Solution2. You could detach the Rendered parts of the Rigidbody and move them independent to the renderPos from the rigidbody (you can also use this position as camera placement origin =Solution1). (Be aware that if the audio-listener is on the character and a renderObject has a 3D- Audio source on it, it could create weird stereo effects, move the listener to a renderObject).
But detaching may be bad for some reasons or could interfere with existiing code that accesses childs. So you can also keep the Renderparts as children and only add an temporary Offset to them (reset this offset in the next frame because we get a new offset that is independent of tzhe first). Just gather all children in the Character that have an “Sprite Renderer” Component.

Bonusblablabla: Basically Solution2 tries to give all visible parts of a rigidbody-gameObject a new position that is updated every render-frame instead of every physics-frame. Physic-frames have no timing-connection with render-frames. A Render-frame just samples the last rigidbody-position of the rigidbody - and this could happen twice between two physic-frames. The rigidbody-position is updated in FixedUpdate() and 2 Updates()calls could happen before the next FixedUpdate()call. Practical Example: If you have 50physic-frames/s and 60 render-frames/s(both very common values), about 10 positions per second would be sampled twice and jitter is introduced. Setting fixedTimestep to a value that yields 60 physic frames is also not a guaranteed jitter-kill since render-frames can vary greatly and you would have a double sample every once in a while.

3. SOLUTION SOURCE:
Solution1: replace “CameraFollow.cs” with this file and test the build, background will stop stuttering
after that
Solution2: additional to above, attach this component “SmoothRigidbodyRender.cs” to the hero (and or enemies) to stop the now visible rigidbody stuttering

It is perfectly smooth in standalone, except the health bar that my scripts don’t touch yet.

*however, one problem remains with the scripts, i don’t know anything about sprite animations and how they work but they seem to manipulate the actual localPositions of the sprites and reset them from time to time, so my script messes up those animations, i did a small workaround to disable animations. … but if you create a child - within the RigidbodyObject - that holds the animation logic and all gameObjects that have SpriteRenderers, then you could set that child to renderPos and animations should still work…

If you have any questions or problems to understand why we have jitter in the first place, just ask :smile:

1697435–106624–CameraFollow.cs (3.75 KB)
1697435–106625–SmoothRigidbodyRender.cs (2.9 KB)

4 Likes

This is absolutely fantastic! I can confirm that applying both of these scripts together fixes the jitter in the Unity sample. Following the same approach I was able to fix my game as well.

@Marrt , thanks for taking the time and sharing this with the community. You’ve just made the world a better place (or at least smoother).

-1 to Unity for spreading bad coding patterns and +1 to @Marrt for fixing it.

2 Likes