Skip to content

Commit 3eb1cd4

Browse files
committed
fix(physics): robot jitter caused by substep change
Signed-off-by: Dhruv Arora <dhruv.arora1@autodesk.com>
1 parent 210ea86 commit 3eb1cd4

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

fission/src/systems/physics/PhysicsSystem.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ const LAYER_GHOST = 10
6161
const COUNT_OBJECT_LAYERS = 11
6262

6363
export const STANDARD_SIMULATION_PERIOD = 1.0 / 60.0
64+
const MAX_COLLISIONS_STEP_PERIOD = 1.0 / 1200.0
65+
// cap on collision steps per rendered frame
66+
// when a frame is so slow that the cap is hit, each collision
67+
// step covers more simulation time
68+
const MAX_COLLISIONS_STEPS = 20
69+
// step count will scale depending on how many active bodies
70+
// there currently are
71+
const ACTIVE_BODY_STEP_BUDGET = 600
6472
// maximum amount of simulation time that can be consumed per render
6573
// for catching up to slow frame
6674
const MAX_SIMULATION_TIME_PER_FRAME = 4 * STANDARD_SIMULATION_PERIOD
@@ -96,7 +104,9 @@ function computeSphericity(volume: number, area: number): number {
96104
return volumeEquivalentSphereArea / area
97105
}
98106

99-
// fixing simulation system in STANDARD_SIMULATION_PERIOD increments
107+
// simulation period. actual step length tracks the rendered
108+
// frame time (PhysicsSystem.update), so stable constant keeps
109+
// driver stiffness independent of construction-time frame rate.
100110
export function getLastDeltaT(): number {
101111
return STANDARD_SIMULATION_PERIOD
102112
}
@@ -152,8 +162,6 @@ class PhysicsSystem extends WorldSystem {
152162

153163
private _pauseSet = new Set<string>()
154164

155-
private _simulationTimeDebt = 0
156-
157165
private _bodyAssociations: Map<JoltBodyIndexAndSequence, BodyAssociate>
158166

159167
public get isPaused(): boolean {
@@ -190,6 +198,7 @@ class PhysicsSystem extends WorldSystem {
190198
this._joltPhysSystem.GetPhysicsSettings().mDeterministicSimulation = false
191199
this._joltPhysSystem.GetPhysicsSettings().mSpeculativeContactDistance = 0.06
192200
this._joltPhysSystem.GetPhysicsSettings().mPenetrationSlop = 0.005
201+
this._joltPhysSystem.GetPhysicsSettings().mTimeBeforeSleep = 0.2
193202

194203
const ground = this.createBox(
195204
new THREE.Vector3(7.5, 0.1, 7.5),
@@ -1085,6 +1094,10 @@ class PhysicsSystem extends WorldSystem {
10851094
this._joltBodyInterface.AddBody(body.GetID(), JOLT.EActivation_Activate)
10861095

10871096
// allowing gamepieces to sleep
1097+
this._joltBodyInterface.AddBody(
1098+
body.GetID(),
1099+
rn.isGamePiece ? JOLT.EActivation_DontActivate : JOLT.EActivation_Activate
1100+
)
10881101
if (!rn.isGamePiece) body.SetAllowSleeping(false)
10891102
rnToBodies.set(rn.id, body.GetID())
10901103

@@ -1422,12 +1435,14 @@ class PhysicsSystem extends WorldSystem {
14221435
return
14231436
}
14241437

1425-
// timestepping with a catchup for skipped frames
1426-
this._simulationTimeDebt = Math.min(this._simulationTimeDebt + deltaT, MAX_SIMULATION_TIME_PER_FRAME)
1427-
1428-
while (this._simulationTimeDebt >= STANDARD_SIMULATION_PERIOD) {
1429-
this._joltInterface.Step(STANDARD_SIMULATION_PERIOD, 1)
1430-
this._simulationTimeDebt -= STANDARD_SIMULATION_PERIOD
1438+
// step the simulation by rendered frame's duration so motion is smooth
1439+
const simTime = Math.min(deltaT, MAX_SIMULATION_TIME_PER_FRAME)
1440+
if (simTime > 0) {
1441+
const desiredSteps = Math.ceil(simTime / MAX_COLLISIONS_STEP_PERIOD)
1442+
const activeBodies = this._joltPhysSystem.GetNumActiveBodies(JOLT.EBodyType_RigidBody)
1443+
const affordableSteps = Math.floor(ACTIVE_BODY_STEP_BUDGET / Math.max(activeBodies, 1))
1444+
const collisionSteps = Math.max(1, Math.min(MAX_COLLISIONS_STEPS, desiredSteps, affordableSteps))
1445+
this._joltInterface.Step(simTime, collisionSteps)
14311446
}
14321447

14331448
this.applySphereGamePieceStiction()

0 commit comments

Comments
 (0)