reze-engine 0.30.1 → 0.30.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/physics/physics.d.ts +4 -0
- package/dist/physics/physics.d.ts.map +1 -1
- package/dist/physics/physics.js +15 -0
- package/package.json +1 -1
- package/src/physics/physics.ts +14 -0
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ npm install reze-engine
|
|
|
18
18
|
- **In-house TS physics** — sequential-impulse rigid bodies for PMX rigs with rest-stable implicit spring-dampers, zero dependencies
|
|
19
19
|
- **Math library** — the shared Vec3/Quat/Mat4 layer of the Reze family: euler orders, swing-twist, shortest-arc, look-rotation, zero-alloc `*Into` variants
|
|
20
20
|
- **VMD animation** — MMD IK with per-chain enable read from the motion, morphs on a GPU compute path, and VMD export
|
|
21
|
-
- **Clip blending & locomotion** — weighted multi-clip pose blending, crossfades, and a game-style character controller (idle/run/sprint speed blend, code-driven root motion) — the [demo](https://reze
|
|
21
|
+
- **Clip blending & locomotion** — weighted multi-clip pose blending, crossfades, and a game-style character controller (idle/run/sprint speed blend, code-driven root motion) — the [demo](https://reze.one) is WASD-playable
|
|
22
22
|
- **Interactive editing** — GPU picking, transform gizmo, bone/material selection
|
|
23
23
|
- **Camera** — orbit, bone-follow, or a driven MMD camera VMD; ground + PCF shadows, multi-model scenes
|
|
24
24
|
- **Offline rendering** — frame-accurate stepping (`renderFrame`) at any resolution (`setRenderSize`) for video export; background color, 360° equirect backdrop, ground shadow-catcher
|
|
@@ -12,6 +12,10 @@ export declare class RezePhysics {
|
|
|
12
12
|
private timeAccum;
|
|
13
13
|
private readonly fixedTimeStep;
|
|
14
14
|
private readonly maxSubSteps;
|
|
15
|
+
/** EMA of one world.step's CPU cost; drives catch-up load shedding. */
|
|
16
|
+
private stepCostEmaMs;
|
|
17
|
+
/** Max ms a single frame may spend catching up physics before shedding. */
|
|
18
|
+
private readonly stepBudgetMs;
|
|
15
19
|
private prevPositions;
|
|
16
20
|
private prevOrientations;
|
|
17
21
|
private kinTargetPos;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../../src/physics/physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAYvC,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;
|
|
1
|
+
{"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../../src/physics/physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAYvC,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAChC,uEAAuE;IACvE,OAAO,CAAC,aAAa,CAAM;IAC3B,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAI;IAMjC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAAc;IAQtC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,eAAe,CAAc;IAMrC,OAAO,CAAC,OAAO,CAAY;IAE3B,OAAO,CAAC,aAAa,CAAY;IAMjC,OAAO,CAAC,WAAW,CAAY;IAG/B,aAAa,SAAI;gBAEL,WAAW,EAAE,SAAS,EAAE,EAAE,MAAM,GAAE,KAAK,EAAO;IA8B1D,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,aAAa;IAKrB,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI;IAG/B,UAAU,IAAI,IAAI;IAGlB,cAAc,IAAI,SAAS,EAAE;IAG7B,SAAS,IAAI,KAAK,EAAE;IAGpB,QAAQ,IAAI,cAAc;IAI1B,sBAAsB,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC;IAiBnE,KAAK,CAAC,iBAAiB,EAAE,IAAI,EAAE,GAAG,IAAI;IActC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,uBAAuB,EAAE,YAAY,GAAG,IAAI;IA2ExF,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,uBAAuB;IAqF/B,OAAO,CAAC,yBAAyB;IAgEjC,OAAO,CAAC,sBAAsB;IAmC9B,OAAO,CAAC,2BAA2B;IA6EnC,OAAO,CAAC,wBAAwB;IA2BhC,OAAO,CAAC,sBAAsB;IAqC9B,OAAO,CAAC,oBAAoB;CA6D7B"}
|
package/dist/physics/physics.js
CHANGED
|
@@ -16,6 +16,10 @@ export class RezePhysics {
|
|
|
16
16
|
this.timeAccum = 0;
|
|
17
17
|
this.fixedTimeStep = 1 / 60;
|
|
18
18
|
this.maxSubSteps = 6;
|
|
19
|
+
/** EMA of one world.step's CPU cost; drives catch-up load shedding. */
|
|
20
|
+
this.stepCostEmaMs = 0.5;
|
|
21
|
+
/** Max ms a single frame may spend catching up physics before shedding. */
|
|
22
|
+
this.stepBudgetMs = 8;
|
|
19
23
|
// Debug counter: frames on which a teleport (scrub/jump discontinuity)
|
|
20
24
|
// was detected and settled.
|
|
21
25
|
this.teleportCount = 0;
|
|
@@ -164,10 +168,21 @@ export class RezePhysics {
|
|
|
164
168
|
let nSub = Math.floor(this.timeAccum / this.fixedTimeStep);
|
|
165
169
|
if (nSub > this.maxSubSteps)
|
|
166
170
|
nSub = this.maxSubSteps;
|
|
171
|
+
// Load shedding: the maxSubSteps cap alone still allows a stable DEGRADED state
|
|
172
|
+
// on weak/throttled devices — one long frame schedules catch-up substeps, which
|
|
173
|
+
// lengthen the next frame, which schedules more, and the cap becomes the steady
|
|
174
|
+
// state (6× step cost every frame; iOS "starts smooth, then stays slow").
|
|
175
|
+
// Catching up must never cost more than a frame-budget slice: shed the backlog
|
|
176
|
+
// instead (physics runs fractionally slow-motion for a beat; framerate holds).
|
|
177
|
+
const affordable = Math.max(1, Math.floor(this.stepBudgetMs / Math.max(0.05, this.stepCostEmaMs)));
|
|
178
|
+
if (nSub > affordable)
|
|
179
|
+
nSub = affordable;
|
|
167
180
|
for (let k = 0; k < nSub; k++) {
|
|
168
181
|
this.savePrevState();
|
|
169
182
|
this.advanceKinematicToTargets(1 / (nSub - k));
|
|
183
|
+
const tStep = performance.now();
|
|
170
184
|
this.world.step(this.store, this.constraints, this.contacts, this.fixedTimeStep);
|
|
185
|
+
this.stepCostEmaMs += (performance.now() - tStep - this.stepCostEmaMs) * 0.2;
|
|
171
186
|
this.restoreNonFiniteBodies();
|
|
172
187
|
this.timeAccum -= this.fixedTimeStep;
|
|
173
188
|
}
|
package/package.json
CHANGED
package/src/physics/physics.ts
CHANGED
|
@@ -24,6 +24,10 @@ export class RezePhysics {
|
|
|
24
24
|
private timeAccum = 0
|
|
25
25
|
private readonly fixedTimeStep = 1 / 60
|
|
26
26
|
private readonly maxSubSteps = 6
|
|
27
|
+
/** EMA of one world.step's CPU cost; drives catch-up load shedding. */
|
|
28
|
+
private stepCostEmaMs = 0.5
|
|
29
|
+
/** Max ms a single frame may spend catching up physics before shedding. */
|
|
30
|
+
private readonly stepBudgetMs = 8
|
|
27
31
|
|
|
28
32
|
// Fixed-timestep render interpolation ("Fix Your Timestep"): the dynamic body pose is
|
|
29
33
|
// rendered as lerp(prev, curr, alpha) between the last two completed substeps, where
|
|
@@ -210,10 +214,20 @@ export class RezePhysics {
|
|
|
210
214
|
this.timeAccum += dt
|
|
211
215
|
let nSub = Math.floor(this.timeAccum / this.fixedTimeStep)
|
|
212
216
|
if (nSub > this.maxSubSteps) nSub = this.maxSubSteps
|
|
217
|
+
// Load shedding: the maxSubSteps cap alone still allows a stable DEGRADED state
|
|
218
|
+
// on weak/throttled devices — one long frame schedules catch-up substeps, which
|
|
219
|
+
// lengthen the next frame, which schedules more, and the cap becomes the steady
|
|
220
|
+
// state (6× step cost every frame; iOS "starts smooth, then stays slow").
|
|
221
|
+
// Catching up must never cost more than a frame-budget slice: shed the backlog
|
|
222
|
+
// instead (physics runs fractionally slow-motion for a beat; framerate holds).
|
|
223
|
+
const affordable = Math.max(1, Math.floor(this.stepBudgetMs / Math.max(0.05, this.stepCostEmaMs)))
|
|
224
|
+
if (nSub > affordable) nSub = affordable
|
|
213
225
|
for (let k = 0; k < nSub; k++) {
|
|
214
226
|
this.savePrevState()
|
|
215
227
|
this.advanceKinematicToTargets(1 / (nSub - k))
|
|
228
|
+
const tStep = performance.now()
|
|
216
229
|
this.world.step(this.store, this.constraints, this.contacts, this.fixedTimeStep)
|
|
230
|
+
this.stepCostEmaMs += (performance.now() - tStep - this.stepCostEmaMs) * 0.2
|
|
217
231
|
this.restoreNonFiniteBodies()
|
|
218
232
|
this.timeAccum -= this.fixedTimeStep
|
|
219
233
|
}
|