cannon-es: World.step is buggy when attempting to account for variable framerate

When passing a timeSinceLastCalled value to the world.step method, the simulation performance quickly degrades beyond usability.

Example usage: Cannon demo

cannon.js issue 371

Article: Fix your timestep

Spectrum chat: World step does not adapt to framerate

Per Schteppe (schteppe#371):

Perhaps the number of substeps are maxed out? This could happen if you, for example, pass in deltaTime in milliseconds instead of seconds… or if you accidentally calculate the value wrong for the first frame (there is no “previous” time value). or if the first deltaTime values are too large (they usually are larger during the first frames while the JIT is warming up). What happens if you pass in 1000 substeps instead of 10? If you have implemented it correctly, changing the number of substeps should do nothing.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 20 (11 by maintainers)

Most upvoted comments

yes it seems so, although it also brings questionable features ( “timeSinceLastCalled = -1 instead of 0” )

I am not sure this address the cube freezing midair effect, I am looking into that.

~This looks good and is working well now except for the freezing cubes (no framerate degradation in my testing). We should wait to merge until that issue is resolved.~

I agree with Marco regarding API changes, we should strive to make as few API changes as possible, and maintain backwards compatibility where we can.

@Platane Great work on this so far, I think supporting variable framerate would be a huge feature.

EDIT: I spoke too soon regarding framerate performance

Yes You are right. I was thinking loudly 😃

That’s a big api change 😬maybe if this library was a standalone physics library instead of a fork of cannon, we could have done it.

The only valid api changes I see are the ones to modernize the library and the ones that make it more compatible with Three.js

Is this PR somehow related? I think we should bring in that PR as well, it was closed because it didn’t receive any attention.

the tab switching makes sense, since request animation frame gets paused, the delta when focusing back is huge.


About the cube heap, it pretty interesting, it looks like the simulation takes too long to be renderer at live speed. It takes more than dt to compute step(dt) which builds up a delay that need to be catch up (the accumulator prop). Eventually filling all the maxSubSteps available.

In that case it is indeed a better solution to slow down the simulation, giving up on rendering at live speed.

One obvious fix could be to prevent the accumulator to grow out of control, as I don’t see any situation where it leads to expected behaviour.

We could also detect slow rendering simulation and shortcut them for the sake of keeping a good framerate at the cost of slowing down the simulation.


About the cube freezing midair, I am not entirely sure, but I suspect it has something to do with the cube going into a broken sleep mode. Because it seems that on the param used to determine if an object sleeps is this.time which does not take account of the accumulator

this.time is increase by an amount that might be higher than the delta of the simulation