bjornbytes / lovr

Lua Virtual Reality Framework
https://lovr.org
MIT License
2k stars 138 forks source link

Fixed Timestep Physics Interpolation #707

Closed bjornbytes closed 6 months ago

bjornbytes commented 1 year ago

Fixed timesteps are important to keep physics stable, and allow physics updates to happen at a rate independent of rendering.

VR renders at a high framerate.

The easiest and most common way to do physics in LÖVR is like this:

function lovr.update(dt)
  world:update(dt)
end

Or this:

function lovr.update(dt)
  world:update(1 / lovr.headset.getRefreshRate())
end

Both have issues. The first not using a fixed timestep. The second is based on headset frameloop speed instead of wallclock time, and risks discontinuities during frame drops or e.g. if the user looks at an expensive part of a scene and the VR runtime steps app submission rate down to half the refresh rate, the physics will become slow motion.

Both of them also use an unnecessarily high tick rate for many use cases, which leads to high CPU usage.

A better approach is to use a fixed timestep and interpolate collider poses. Physics will add delta times to an accumulator and perform zero or more updates depending on how much time remains in the accumulator. Then, for rendering, colliders will use poses interpolated between their 2 most recent states.

LÖVR should be minimal, can't people just do this in Lua or use a library?

It's possible, but there are a few reasons why it's better done in C:

Bullet has interpolation built-in. Here's a discussion with recommendations about doing interpolation in Jolt.

Rough implementation details:

bjornbytes commented 6 months ago

This has been implemented.