• RuntimesUnityBugs
  • Physics Jitters/Unstable At Higher Framerates

Hello,

I am trying to add a model that implements physics for the first time in Unity and I'm running into major issues with the constraints jittering/unstable when the model is moving and physics constraints are updated.

Here is how the model looks in Spine:

The odd thing is that the constraints seem stable at a constant 30 fps:

And here is how it looks at a constant 60 fps:

With a variable frame rate 60-120 fps the constraints jitter back and forth but not at a constant rate. I've also tried other things like changing the physics translation scale and updating the animation in FixedUpdate instead but there is no improvement.

FYI this is using the latest Unity Spine runtime and Unity 2022.3.

Related Discussions
...
Noeski додали Bugs тег .

Spine's physics runs at a fixed time step. When a physics constraint is updated, it accumulates time until it has at least enough to step the simulation forward one time step. This is done to improve the physics stability. If physics was instead updated every frame, you could get wildly different physics results at higher or especially lower application frame rates.

The time needed to step the physics simulation is controlled by the FPS setting on the physics constraints. It defaults to 60. What is yours set to? Please note that changing this setting affects physics behavior, so you may need to adjust some or all of the other physics settings to get the same look you had before changing FPS.

What appears to be happening is that you render your app faster than the physics are being updated. This allows you to see skeleton movement that hasn't affected physics yet, then when physics are stepped forward the constrained bones are moved by physics. This can cause jerky motion when physics aren't only updated every other frame.

I've tried exporting at 30 FPS, 60 FPS, 120 FPS, and they all have the same jitter issue - it's more jittery in the editor due to frame rate fluctuation, but it still happens in the built game which seems problematic. Are there any tips to making things more stable?

To be sure, you set ALL your physics constraints to 60 or 120 FPS? You exported and are sure the app is using that new export?

You can set the editor max framerate in the editor settings, so you can see it there are various framerates.

If you are still having the issue, it would help if we can see it firsthand. Can you send your .spine file and images? contact@esotericsoftware.com

Yep, I double checked the frame rate and it was exported correctly.

Here is how it looks in game exported @ 60 FPS:

I sent over the spine project to check out, let me know if you need any more info!

Got it, thanks! Did you say it was possible to see in the editor? How exactly? I made an animation that moves left/right and I don't see jitter with my monitor refresh rate (100Hz) and editor settings (100Hz).

If I change my monitor to 60Hz, set the editor frame rate to 60Hz, and have Simulate checked but Deterministic unchecked, then I do see jitter. It's easiest to see on the Hip bone when moving from right to left. Set playback speed to 10% to see it more easily. The bone rotation lags behind due to physics, then when physics steps it applies Strength and other settings that cause the bone to catch up to the unconstrained position, but the time elapsed between each time physics catches up is too long. When the happens you see the bone lagging behind, then a strong Strength force is applied that makes the bone jump toward the unconstrained position, then you see it lag behind again, then it jumps again, etc. That is the "jitter".

If I set the Hip physics constraint to 90Hz then the jitter mostly goes away in the editor. At 120Hz it is gone. The update rate needs to be high enough that the adjustments physics is making are not distracting. This depends on the rendering rate, the physics update rate, the skeleton movement, and the physics strength. When the rendering rate and physics update rate aren't divisible or the rendering rate fluctuates, it can cause a physics update to be missed by a frame. Often this is not important, but can cause a jump like this.

BTW, while looking into your issue we found that changing the physics constraint FPS can leave some accumulated time in the constraint. This can affect the update rate interactions, particularly how the skeleton behaves when changing from a higher FPS to lower. For example, say you see jitter with 60Hz, you change to 120 and it goes away, you change back to 60 and there appears to be no jitter now! To reset all the constraints you can click Reset or Reset All or change animate/setup mode and back. That zeros the accumulated time and now you can see the 60Hz jitter consistently. We'll fix this so changing the FPS resets the constraint automatically.

If you check Deterministic you won't be able to see jitter, as it calculates the exact pose from frame 0. This is different from applying physics all the time.

What is your monitor refresh rate and editor frame rate settings?

At runtime, what is the rendering frame rate?

It's worth checking to make sure you are not updating physics twice each frame (and that you are indeed updating exactly one time). Skeleton updateWorldTransform should only be called with Physics.update once per application frame render.

I know you reported 120Hz physics constraints don't fix the problem at runtime. I'm not sure why that is, there could be something else happening. Indeed the expected jitter that I see with the Hip bone is not quite the same as what you showed. You could try 250 FPS (type the value or drag the slider extra far).

I exported and played the left/right animation using Skeleton Viewer with 60Hz monitor and physics and didn't see jitter. Skeleton Viewer uses vsync so it renders at the monitor refresh rate.

The next step would be for you to provide a runtime example that shows the problem in the simplest possible way (we don't want to dig through your application code 🙂).

Ah sorry for the confusion, by editor I meant the Unity editor and not the Spine editor.

Setting the FPS to something super high like 250 FPS does minimize the issue, but still seems a bit off and it definitely seems to depend on the frame rate of the game so if there are any frame drops or FPS dips then it gets worse.

If I am able to match the frame rate of the game to the FPS of the physics constraints it does definitely smooth things out, but if there are ever any frame drops or if the frame rate were set to something else then it starts to get out of sync.

You can see what I mean here if the frame rate is uncapped vs vsync is enabled @ 60 fps:

FYI I sent a minimal project which is reproducing the issue for me.

Thanks, sorry for the delay. Harald will be along shortly to help out.

@Noeski Thanks for sending the reproduction project. Unfortunately there is nothing obviously wrong with your setup and also frametime inconsistencies seem not to be the cause of the problem. We will continue to investigate and get back to you here on the forum once we've figured out what's going wrong.

  • Змінено

@Noeski We just discovered that it's an internal physics logic problem.

It will require some changes on the runtime side, we will get back to you here on the forum once we have a bugfix ready. Thanks for reporting!

  • Noeski відповіли на це.
  • Fabiano вподобали це.

    Harald thank you for looking into this!

    @Nate By the way, as a test I tried removing the physics step altogether and always updating the constraints with the same frame time as the normal Unity deltaTime which is giving me MUCH better results. This would of course be non-deterministic and less stable for a physics simulation, but it looks fine and since this is purely visual the accuracy is not a huge factor to me.

    8 днів пізніше

    Hi @Harald, is there any progress on this? Thanks!

    Sorry for the delay! We investigated and so far the theory is it happens due to how the PhysicsConstraint translate method transfers game world movement to the constraint. We haven't yet determined a fix, but hope to get to it soon.

    9 днів пізніше

    Sorry again for the delay. This appears to be stuttering that happens when the game FPS is slightly different from the physics FPS. It depends on the particular interaction of those two frequencies. It's common for the game update rate to vary slightly, be capped at vsync, and it's possible for it to dip a large amount, for example when another app suddenly takes a lot of resources. Physics accumulates time based on the game update rate, but physics only updates at its configured rate, with any remaining time spilling over to the next game update. For these reasons it's difficult to control the interactions.

    Increasing the physics update rate generally makes the stuttering smaller, but isn't a real solution, again depending on the interactions of the update rates of the game and physics.

    The easiest solution is to remove the fixed time step from physics. When physics runs at the same update rate as the game, stuttering won't occur. The downside is that physics behavior is dependent on the update rate. If the game FPS varies significantly from the update rate the physics settings were designed for, the behavior may be undesirable. For example, things may not move as fast or as far, or they may move too fast or too far. This can be mitigated by capping the physics update rate. For example, if the target game update rate is 60 FPS, allow physics to update between 50 and 70 FPS. Larger variations of the game update rate would cause stuttering.

    Another solution is to interpolate between the last 2 physics states. With this approach, when physics is updated, the difference is not applied right away. Instead every game frame the amount of that difference that is used is based on this percentage: the time elapsed since the update divided by the time between updates. This interpolation ensures smooth movement between physics updates, regardless of alignment of the game and physics update rates. The downside is it's a little more work to remember and apply the values, and especially that then the physics pose is always behind from between 0% to 100% of the physics update rate. For example, at 60 FPS physics would have average lag of 1 / 60 * 50% = 8.3ms with worst case lag of 1 / 60 = 16.6ms.

    Unfortunately, fixing this exceeds the complexity of a change we're comfortable with making to a stable version (4.2). Of the two solutions interpolation is better, so we would like to implement that in 4.3. If you need assistance having physics run at the game update rate, we can help with that.

    @Nate thanks again for taking the time to look into this, I realize it's not a simple fix!

    Adding the option for interpolation sounds like a great solution, this is what Unity offers for their physics system that works well but yes it would have a 1 frame physics delay.

    For us, removing the fixed timestep would be the best short term option and we do have a quick and dirty solution in our fork here: Noeski/spine-runtimes but I've noticed a few weird glitches that occur when changing the global Unity timescale.

    I'm sure you and @Harald have a better idea of how to update to properly support this.

    Thanks!

    • Harald відповіли на це.
    • Nate вподобали це.

      Noeski but I've noticed a few weird glitches that occur when changing the global Unity timescale.

      Could you please describe what kind of glitches you received, and between which timescale values you changed? Did you imediately change timescale, or did you change it over time (e.g. via linear interpolation from timescaleA to timescaleB over one second)?

      In general your commit looks good, unfortunately I can't see any obvious reason for a glitch (immediate change) yet that different delta time would cause (apart from different response in general).

      @Harald I figured out what the issue was. It was a side effect of the change I made and also setting 'UnscaledTime' to true which sometimes resulted in a large update time that would cause the physics simulation to get really unstable. I'm fixing this by making sure we still step the physics over multiple smaller steps if the time value is greater than 100ms. This seems to fix the weird glitches that I was seeing.

      @Noeski Glad to hear you've figured it out! Thanks for letting us know.