@@ -61,6 +61,14 @@ const LAYER_GHOST = 10
6161const COUNT_OBJECT_LAYERS = 11
6262
6363export 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
6674const 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.
100110export 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