How to make physics forces independent of frame rate?

It’s not possible to make your physics behave identically regardless of physics simulation frame rate. You can make it independent of the rendering frame rate, but all computer physics simulations are dependent on their time step. This is because game simulation of physics is done by calculating discrete chunks of time and integrating the results (known as Numerical Integration, you can google it for lots of details). The problem is that large time steps cause most integration methods to overestimate forces and movement, which you’re seeing in your game when you increase the time between updates and your suspension responds with much more force than when the time step is small. This is why many game engines have a fixed physics time step that is updated separately from the rendering loop. I don’t know if unreal has the option to configure physics timestep and rendering framerate independently, but no matter what, changing your physics timestep will always change the results of your simulation.

Here’s a quick example:

Say you’re applying 10N down the x axis to a 1kg object for two seconds. This means a = F/m = 10m/ss.

@ .5 fps (2s per frame)
Frame 1, 2s: v = 2s * 10m/ss = 20m/s. pos = 2s * 20m/s = (40m, 0m, 0m)

@1 fps (1s per frame)
Frame 1, 1s: v = 1s * 10m/ss = 10m/s. pos = 1s * 10m/s = (10m, 0m, 0m)
Frame 2, 2s v =  20m/s. pos += 1s * 20m/s = (30m, 0m, 0m)

@2 fps (.5s per frame)
Frame 1, .5s: v = .5s * 10m/ss = 5m/s. pos = 5m/s * .5s = (2.5m, 0m, 0m)
Frame 2, 1s: v = 10m/s. pos += .5s * 10m/s = (7.5m, 0m, 0m)
Frame 3, 1.5s: v = 15m/s. pos += .5s * 15m/s = (15m, 0m, 0m)
Frame 4, 2s: v = 20m/s. pos += .5s * 20m/s = (25m, 0m, 0m)

Note that after two seconds velocity is always 20m/s but the position is wildly different.

If you absolutely need your suspension code to use a predictable fixed time step, you can use your own fixed simulation time always, no matter what the frame time was. If the frame time was much longer than your chosen fixed simulation timestep, run your suspension simulation multiple times that frame.

void DoSuspension (float dt) {

const float simStep = 1.0f / 120.0f;

float timeToSimulate = dt + m_prevFrameExtraTime;
for (; timeToSimulate > simStep; timeToSimulate -= simStep)
    Simulate();
m_prevFrameExtraTime = timeToSimulate;

}

Hope this helped!

1 Like