Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/world/World.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,15 +388,13 @@ export class World extends EventTarget {
* world.step(1/60);
*
* @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
* @see https://gafferongames.com/post/fix_your_timestep/
*/
step(dt: number, timeSinceLastCalled = 0, maxSubSteps = 10): void {
if (timeSinceLastCalled === 0) {
step(dt: number, timeSinceLastCalled?: number, maxSubSteps: number = 10): void {
if (timeSinceLastCalled === undefined) {
// Fixed, simple stepping

this.internalStep(dt)

// Increment time
this.time += dt
} else {
this.accumulator += timeSinceLastCalled
let substeps = 0
Expand All @@ -407,14 +405,16 @@ export class World extends EventTarget {
substeps++
}

const t = (this.accumulator % dt) / dt
// prevent the accumulator to build up delay to catch up. The logic being: if the step did not catch up at this frame, it is unlikely to catch up in the next one. Even if it does, it will result in a speed up simulation which is arguably worse that staying behind the real time.
this.accumulator = Math.max(this.accumulator, dt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so how does this behave diifferently than setting this.accumulator = this.accumulator % dt? Just a question, can't really wrap my head around what would happen differently 😅

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question!
To my understanding, the accumulator is useful to catch up a frame when for example the simulation runs at 50fps and the step is 1/60ms. The accumulator growing greater than dt is an unexpected behaviour.

afaik, once we agree to discard some simulation time, it does not matter much if we carry the modulo or not.

I arbitrary decide to use a hard limit because of the semantic, as using a modulo might be interpreted as being important in the interpolation after ( which is not, the interpolation does not make any sense in case the accumulator gets truncate )


const t = this.accumulator / dt
for (let j = 0; j !== this.bodies.length; j++) {
const b = this.bodies[j]
b.previousPosition.lerp(b.position, t, b.interpolatedPosition)
b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion)
b.previousQuaternion.normalize()
}
this.time += timeSinceLastCalled
}
}

Expand Down