schteppe / cannon.js

A lightweight 3D physics engine written in JavaScript.
http://schteppe.github.com/cannon.js
MIT License
4.7k stars 711 forks source link

World.step() doesn't make sense #371

Open brundonsmith opened 6 years ago

brundonsmith commented 6 years ago

I've been trying to figure out how exactly World.step() works. I've read the documentation and multiple examples. Here's my use case:

update(timeDelta) {
    this.cannonWorld.step(1 / 60, timeDelta, 10);
}

update() is called in the main game loop at a slightly variable interval (requestAnimationFrame() recursive). timeDelta is the amount of time since the last update cycle; usually around 0.016 seconds. Given that it's the "time since last called" - the exact name of parameter 2 from the docs - it seems like a natural thing to pass in that spot.

However, with the above code, an increase in items being simulated actually slows down the physics simulation, but strangely, not the program itself. The frame-rate doesn't drop, everything just starts moving in slow-motion, even though the arguments to step() do not change (aside from a ~0.001 variance in timeDelta).

Removing all but the first parameter gets rid of the slowdown no matter how many objects are in the world, but it sounds like that also disables interpolation.

All of that aside, I'm confused by the docs as to why parameter 1 and 2 both exist... Both seem to represent the amount to progress time in the current simulation cycle, and 1 seems to have to be completely constant for some reason, even though frame-rate can be variable. I can't even be sure if the slowdown behavior above is a bug, because it's not clear what parameter 2 is supposed to do.

Can anyone provide some insight? This ticket can of course be converted to a bug report if the slowdown is in fact a bug.

Senglejan commented 6 years ago

+1 I'm stuck trying to figure out where the slowing down comes from, there is no apparent memory leak in the game. Objects starts slowing down though as if garbage collection is being carried out, but nothing results out of ordinary in chrome dev tools

robrohan commented 6 years ago

@brundonsmith I am using cannon as well - can I ask if you see the issue in this demo? http://mesh.robrohan.com/#physics or is it something that builds up over a long time?

The reasons I ask, is before using cannon I was trying to write my own physics engine from scratch, and started with this for the loop: https://gafferongames.com/post/fix_your_timestep/ and when I moved over to cannon, just kept the same loop. If you don't see the same problem in that demo, maybe checkout that article.

brundonsmith commented 6 years ago

So, my theory is that the process itself isn't actually slowing down, but that the interval between steps is getting larger somehow. I think this because my character movement happens independently of the physics, and it doesn't slow down at all; only the physics simulation itself slows down. Why this might happen is beyond me.

What we need is for someone who's familiar with the source code to weigh in and explain how those parameters actually work (and ideally fix the documentation accordingly, since it's incorrect). If none of the developers respond here, and I find myself with both the time and the motivation, maybe I'll take a stab at reading the source myself.

Senglejan commented 6 years ago

@robrohan thank you for the article, I would love to give it a go. By any chance do you have the fixed delta time code in js to use with cannonjs?

robrohan commented 6 years ago

I am using something like this:

private run() {
    let then = 0;
    let delta: number;
    let isRunning = true;

    const interval = 1000 / 60; // 60fps
    const maxSubSteps = 5;
    const timeStep: = 1 / 60;   // (one second)

    const loop = (now: number) => {
      requestAnimationFrame(loop);

      delta = (now - then);
      if (delta > interval && isRunning) {
        world.step(timeStep, delta, maxSubSteps);
        // render(...);
        then = now - (delta % interval);
      }
    };
    requestAnimationFrame(loop);
}
Senglejan commented 6 years ago

Thank you!

Senglejan commented 6 years ago

I'm so lost right now, not sure if the framerate drop comes from my code, threejs or cannonjs or my mac.

I just discovered that this cannon js pile demo > http://schteppe.github.io/cannon.js/demos/pile.html also drops frames after few minutes.

Anyone can check if this happens for him?

Senglejan commented 6 years ago

There is something very wrong somewhere..maybe in WebGL. All the following will eventually drop the fps to <=30

Cannonjs + Three JS Threejs alone no physics Oimo JS basic test BabylonJS demos

The more powerful the GPU , the more time it will take to manifest , but the frames will drop.

dirkk0 commented 6 years ago

You use Chrome? Did you try Firefox?

Senglejan commented 6 years ago

Hi! On Firefox the experience is bad from the start in most cases

dirkk0 commented 6 years ago

My point is - if nearly any demo drops the framerate, it could be the browser, the OS and even the driver of your graphic card. What gear are you using? Would you mind putting up a page with links to the four cases you mentioned before?

Senglejan commented 6 years ago

I tested on 2 machines

Device 1 : ( it takes 30 to 45 mins for frames to drop to -=30) MacBook Pro (Retina, 15-inch, Mid 2014) 2.2 GHz Intel Core i7 Intel Iris Pro 1536 MB OS: macOS High Sierra 10.13.4

Device 2: ( it takes hours +-4hrs for frames to drop to -=30) Gaming PC (very good gfx , 16 gig ram etc) , will get you better details later if needed OS: Window 10

Examples:

OimoJS Basic demo http://lo-th.github.io/Oimo.js/examples/test_basic.html

Babylon js dancers demo https://www.babylonjs.com/demos/dancers/

Threejs shadowmap example https://threejs.org/examples/?q=shadow#webgl_shadowmap

photonstorm commented 6 years ago

How are you monitoring the frame rate?

Senglejan commented 6 years ago

Apart it can be felt going down, using stats.js or chrome fps meter

no apparent memory leak either in GPU or Ram

screen shot 2018-05-31 at 4 43 32 pm

screen shot 2018-05-31 at 4 43 06 pm

but still fps drop to -=30 after 20mins or so

schteppe commented 6 years ago

@brundonsmith weird bug... did you find out what the problem was? Is there a live demo that demonstrates the issue? Can you reproduce it in one of the cannon.js demos?

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.

To understand the stepping works, read this article: https://gafferongames.com/post/fix_your_timestep/ The first argument is the fixed time step and the second one is added to the accumulator.

Maybe the docs are better in p2.js? The api is basically the same but I’ve put some more work into it in some spots.