@woosh/meep-engine 2.145.0 → 2.147.0
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/package.json +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +33 -3
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +486 -451
- package/src/engine/control/first-person/DESIGN_COLLISION.md +365 -352
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +1 -14
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +20 -8
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +552 -546
- package/src/engine/control/first-person/TODO.md +13 -11
- package/src/engine/control/first-person/abilities/LedgeGrab.d.ts +8 -3
- package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/LedgeGrab.js +213 -199
- package/src/engine/control/first-person/abilities/Mantle.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/Mantle.js +195 -188
- package/src/engine/control/first-person/abilities/WallJump.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/WallJump.js +11 -3
- package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/WallRun.js +183 -163
- package/src/engine/control/first-person/collision/KinematicMover.d.ts.map +1 -1
- package/src/engine/control/first-person/collision/KinematicMover.js +634 -592
- package/src/engine/control/first-person/prototype_first_person_controller.js +1003 -901
- package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts +9 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensors.d.ts.map +1 -1
- package/src/engine/control/first-person/sensors/FirstPersonSensors.js +87 -77
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts +8 -0
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +229 -196
- package/src/engine/ecs/EntityManager.d.ts +34 -11
- package/src/engine/ecs/EntityManager.d.ts.map +1 -1
- package/src/engine/ecs/EntityManager.js +71 -42
- package/src/engine/interpolation/BinaryInterpolationAdapter.d.ts.map +1 -0
- package/src/engine/interpolation/Interpoland.d.ts +48 -0
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -0
- package/src/engine/interpolation/Interpoland.js +49 -0
- package/src/engine/interpolation/Interpolated.d.ts +101 -0
- package/src/engine/interpolation/Interpolated.d.ts.map +1 -0
- package/src/engine/interpolation/Interpolated.js +149 -0
- package/src/engine/{network/sim → interpolation}/InterpolationLog.d.ts +1 -1
- package/src/engine/interpolation/InterpolationLog.d.ts.map +1 -0
- package/src/engine/{network/sim → interpolation}/InterpolationLog.js +2 -2
- package/src/engine/interpolation/InterpolationSystem.d.ts +116 -0
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -0
- package/src/engine/interpolation/InterpolationSystem.js +233 -0
- package/src/engine/interpolation/PoseInterpolationAdapter.d.ts +17 -0
- package/src/engine/interpolation/PoseInterpolationAdapter.d.ts.map +1 -0
- package/src/engine/interpolation/PoseInterpolationAdapter.js +61 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +35 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +57 -0
- package/src/engine/interpolation/pose_interpoland.d.ts +18 -0
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -0
- package/src/engine/interpolation/pose_interpoland.js +27 -0
- package/src/engine/network/NetworkSession.d.ts +2 -2
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +2 -2
- package/src/engine/network/adapters/QuaternionInterpolationAdapter.d.ts +1 -1
- package/src/engine/network/adapters/QuaternionInterpolationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/QuaternionInterpolationAdapter.js +1 -1
- package/src/engine/network/adapters/TransformInterpolationAdapter.d.ts +1 -1
- package/src/engine/network/adapters/TransformInterpolationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/TransformInterpolationAdapter.js +1 -1
- package/src/engine/network/adapters/Vector3InterpolationAdapter.d.ts +1 -1
- package/src/engine/network/adapters/Vector3InterpolationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/Vector3InterpolationAdapter.js +1 -1
- package/src/engine/physics/INTEPOLATION_SYSTEM_PLAN.md +287 -0
- package/src/engine/physics/PLAN.md +944 -809
- package/src/engine/physics/body/BodyStorage.d.ts +9 -0
- package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
- package/src/engine/physics/body/BodyStorage.js +23 -0
- package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
- package/src/engine/physics/broadphase/generate_pairs.js +7 -0
- package/src/engine/physics/ccd/linear_sweep.d.ts +97 -0
- package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -0
- package/src/engine/physics/ccd/linear_sweep.js +238 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +82 -3
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +227 -8
- package/src/engine/physics/ecs/RigidBodyFlags.d.ts +6 -0
- package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -1
- package/src/engine/physics/ecs/RigidBodyFlags.js +6 -0
- package/src/engine/physics/narrowphase/box_triangle_contact.js +814 -811
- package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/compute_penetration.js +325 -323
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +27 -8
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +235 -204
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +97 -13
- package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
- package/src/engine/physics/queries/overlap_shape.js +185 -183
- package/src/engine/simulation/Ticker.d.ts +14 -0
- package/src/engine/simulation/Ticker.d.ts.map +1 -1
- package/src/engine/simulation/Ticker.js +136 -1
- package/src/engine/network/sim/BinaryInterpolationAdapter.d.ts.map +0 -1
- package/src/engine/network/sim/InterpolationLog.d.ts.map +0 -1
- /package/src/engine/{network/sim → interpolation}/BinaryInterpolationAdapter.d.ts +0 -0
- /package/src/engine/{network/sim → interpolation}/BinaryInterpolationAdapter.js +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
2
3
|
import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
|
|
3
4
|
import Signal from "../../../core/events/signal/Signal.js";
|
|
4
5
|
import Vector3 from "../../../core/geom/Vector3.js";
|
|
@@ -21,6 +22,7 @@ import { narrowphase_step } from "../narrowphase/narrowphase_step.js";
|
|
|
21
22
|
import { overlap_shape as overlap_shape_query } from "../queries/overlap_shape.js";
|
|
22
23
|
import { raycast as raycast_query } from "../queries/raycast.js";
|
|
23
24
|
import { shape_cast as shape_cast_query } from "../queries/shape_cast.js";
|
|
25
|
+
import { ccd_resolve } from "../ccd/linear_sweep.js";
|
|
24
26
|
import { returnTrue } from "../../../core/function/returnTrue.js";
|
|
25
27
|
import {
|
|
26
28
|
prepare_contacts,
|
|
@@ -46,6 +48,7 @@ import { Collider, COLLIDER_UNBOUND } from "./Collider.js";
|
|
|
46
48
|
import { RIGID_BODY_UNALLOCATED, RigidBody } from "./RigidBody.js";
|
|
47
49
|
import { RigidBodyFlags } from "./RigidBodyFlags.js";
|
|
48
50
|
import { SleepState } from "./SleepState.js";
|
|
51
|
+
import { Interpolated } from "../../interpolation/Interpolated.js";
|
|
49
52
|
|
|
50
53
|
/**
|
|
51
54
|
* Reusable scratch buffer for world-AABB construction so the link path is
|
|
@@ -294,6 +297,23 @@ export class PhysicsSystem extends System {
|
|
|
294
297
|
*/
|
|
295
298
|
this.__pseudo_velocity = new Float64Array(0);
|
|
296
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Master switch for the continuous-collision pass. When false the
|
|
302
|
+
* {@link RigidBodyFlags.CCD} flag is ignored and no swept queries run.
|
|
303
|
+
* @type {boolean}
|
|
304
|
+
*/
|
|
305
|
+
this.ccdEnabled = true;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Start-of-step world positions for CCD-flagged bodies — 3 doubles per
|
|
309
|
+
* body slot index (`[x, y, z]`). Captured in Stage 1 before the substep
|
|
310
|
+
* loop integrates poses; the CCD pass ({@link ccd_resolve}) sweeps from
|
|
311
|
+
* here to the final pose. Grows to `storage.high_water_mark * 3`; only
|
|
312
|
+
* CCD-flagged slots are written each step.
|
|
313
|
+
* @type {Float64Array}
|
|
314
|
+
*/
|
|
315
|
+
this.__ccd_start_pos = new Float64Array(0);
|
|
316
|
+
|
|
297
317
|
/**
|
|
298
318
|
* Bound reference to {@link __pair_filter} so we hand the same
|
|
299
319
|
* callable to {@link generate_pairs} each step without per-step
|
|
@@ -301,6 +321,26 @@ export class PhysicsSystem extends System {
|
|
|
301
321
|
* @private
|
|
302
322
|
*/
|
|
303
323
|
this.__pair_filter_bound = (idA, idB) => this.__pair_filter(idA, idB);
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Optional shared interpolation log to produce per-step pose snapshots
|
|
327
|
+
* into (the {@link InterpolationSystem}'s log). When set — and only then —
|
|
328
|
+
* each fixedUpdate restores every awake {@link Interpolated} body's live
|
|
329
|
+
* components from the previous tick (undoing render-time interpolation so
|
|
330
|
+
* the sim reads authoritative state), then records the post-step state
|
|
331
|
+
* under the current `entityManager.fixedStepTick`. Null on a headless /
|
|
332
|
+
* non-rendering world, where the producer work is skipped entirely.
|
|
333
|
+
* @type {InterpolationLog|null}
|
|
334
|
+
*/
|
|
335
|
+
this.interpolationLog = null;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Reusable decode buffer for restoring interpolated snapshots.
|
|
339
|
+
* @private
|
|
340
|
+
* @type {BinaryBuffer}
|
|
341
|
+
*/
|
|
342
|
+
this.__interp_scratch = new BinaryBuffer();
|
|
343
|
+
this.__interp_scratch.fromArrayBuffer(new ArrayBuffer(256));
|
|
304
344
|
}
|
|
305
345
|
|
|
306
346
|
/**
|
|
@@ -586,20 +626,16 @@ export class PhysicsSystem extends System {
|
|
|
586
626
|
}
|
|
587
627
|
|
|
588
628
|
/**
|
|
589
|
-
*
|
|
590
|
-
* O(
|
|
591
|
-
*
|
|
629
|
+
* Resolve an entity to its body index, or -1 if no live body owns it.
|
|
630
|
+
* O(1) via {@link BodyStorage#index_of_entity}'s entity → index map — used
|
|
631
|
+
* on the collider attach / detach and joint link paths.
|
|
592
632
|
*
|
|
593
633
|
* @private
|
|
594
634
|
* @param {number} entity
|
|
595
635
|
* @returns {number} body index or -1
|
|
596
636
|
*/
|
|
597
637
|
__find_body_index_by_entity(entity) {
|
|
598
|
-
|
|
599
|
-
for (let i = 0; i < hwm; i++) {
|
|
600
|
-
if (this.storage.entity_at(i) === entity) return i;
|
|
601
|
-
}
|
|
602
|
-
return -1;
|
|
638
|
+
return this.storage.index_of_entity(entity);
|
|
603
639
|
}
|
|
604
640
|
|
|
605
641
|
/**
|
|
@@ -815,6 +851,50 @@ export class PhysicsSystem extends System {
|
|
|
815
851
|
}
|
|
816
852
|
}
|
|
817
853
|
|
|
854
|
+
/**
|
|
855
|
+
* Teleport a body to a new pose, bypassing integration: writes the body's
|
|
856
|
+
* Transform directly and wakes it. For an interpolated body this also flags a
|
|
857
|
+
* render `snap` on its {@link Interpolated} component, so the producer keeps
|
|
858
|
+
* this pose (rather than restoring the previous tick over it) and the
|
|
859
|
+
* renderer shows the new pose without sliding across the jump.
|
|
860
|
+
*
|
|
861
|
+
* This is the authoritative way to reposition an interpolated body — a raw
|
|
862
|
+
* `Transform` write would be undone by the per-step restore. Velocity is left
|
|
863
|
+
* as-is; zero it via {@link setLinearVelocity} if the teleport should also
|
|
864
|
+
* stop the body.
|
|
865
|
+
*
|
|
866
|
+
* @param {RigidBody} rigidBody
|
|
867
|
+
* @param {Vector3|{x:number,y:number,z:number}} position world position
|
|
868
|
+
* @param {Quaternion|{x:number,y:number,z:number,w:number}} rotation world unit-quaternion rotation
|
|
869
|
+
*/
|
|
870
|
+
setPose(rigidBody, position, rotation) {
|
|
871
|
+
const idx = body_id_index(rigidBody._bodyId);
|
|
872
|
+
const transform = this.__transforms[idx];
|
|
873
|
+
if (transform === undefined) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
transform.position.set(position.x, position.y, position.z);
|
|
878
|
+
transform.rotation.set(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
879
|
+
|
|
880
|
+
this.__wake_body(rigidBody);
|
|
881
|
+
|
|
882
|
+
// Flag a snap on the body's Interpolated component, if any, so the
|
|
883
|
+
// interpolation producer (restore) and consumer (blend) treat this pose
|
|
884
|
+
// as authoritative this frame instead of interpolating across the jump.
|
|
885
|
+
const em = this.entityManager;
|
|
886
|
+
if (em !== null && em !== undefined) {
|
|
887
|
+
const dataset = em.dataset;
|
|
888
|
+
if (dataset !== null && dataset !== undefined) {
|
|
889
|
+
const entity = this.storage.entity_at(idx);
|
|
890
|
+
const interpolated = dataset.getComponent(entity, Interpolated);
|
|
891
|
+
if (interpolated !== undefined && interpolated !== null) {
|
|
892
|
+
interpolated.snap = true;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
818
898
|
/**
|
|
819
899
|
* Force the body awake. Static bodies are ignored.
|
|
820
900
|
* @param {RigidBody} rigidBody
|
|
@@ -1259,7 +1339,103 @@ export class PhysicsSystem extends System {
|
|
|
1259
1339
|
}
|
|
1260
1340
|
}
|
|
1261
1341
|
|
|
1342
|
+
/**
|
|
1343
|
+
* Producer — restore pass. At the top of a fixed step, reset every awake
|
|
1344
|
+
* {@link Interpolated} body's live components to their authoritative state
|
|
1345
|
+
* from the previous tick's snapshot, undoing any render-time interpolation
|
|
1346
|
+
* the {@link InterpolationSystem} wrote between frames so the sim integrates
|
|
1347
|
+
* from truth, not an interpolated pose. A body with no previous snapshot
|
|
1348
|
+
* (first step ever, or just woken) is left as-is — its live state is already
|
|
1349
|
+
* authoritative. No-op unless {@link interpolationLog} is wired.
|
|
1350
|
+
* @private
|
|
1351
|
+
*/
|
|
1352
|
+
__interp_restore() {
|
|
1353
|
+
const log = this.interpolationLog;
|
|
1354
|
+
const em = this.entityManager;
|
|
1355
|
+
if (log === null || em === null || em === undefined) return;
|
|
1356
|
+
const dataset = em.dataset;
|
|
1357
|
+
if (dataset === null || dataset === undefined) return;
|
|
1358
|
+
|
|
1359
|
+
const prev_tick = em.fixedStepTick - 1;
|
|
1360
|
+
if (prev_tick < 0) return;
|
|
1361
|
+
|
|
1362
|
+
const storage = this.storage;
|
|
1363
|
+
const count = storage.awake_count;
|
|
1364
|
+
const scratch = this.__interp_scratch;
|
|
1365
|
+
|
|
1366
|
+
for (let i = 0; i < count; i++) {
|
|
1367
|
+
const idx = storage.awake_at(i);
|
|
1368
|
+
const entity = storage.entity_at(idx);
|
|
1369
|
+
const interpolated = dataset.getComponent(entity, Interpolated);
|
|
1370
|
+
if (interpolated === undefined || interpolated === null) continue;
|
|
1371
|
+
// A teleported body (snap set, e.g. via setPose) keeps its live pose
|
|
1372
|
+
// this step — restoring the previous tick would undo the teleport.
|
|
1373
|
+
if (interpolated.snap) continue;
|
|
1374
|
+
const key = interpolated.key;
|
|
1375
|
+
if (key < 0) continue;
|
|
1376
|
+
|
|
1377
|
+
const interpolands = interpolated.interpolands;
|
|
1378
|
+
for (let k = 0; k < interpolands.length; k++) {
|
|
1379
|
+
const ip = interpolands[k];
|
|
1380
|
+
scratch.position = 0;
|
|
1381
|
+
// Snap to the previous tick's snapshot (both offsets equal → t irrelevant).
|
|
1382
|
+
const ok = log.interpolate(scratch, key, ip.type_id, prev_tick, prev_tick, 0, ip.interpolation_adapter);
|
|
1383
|
+
if (!ok) continue;
|
|
1384
|
+
const target = dataset.getComponent(entity, ip.component_class);
|
|
1385
|
+
if (target === undefined || target === null) continue;
|
|
1386
|
+
scratch.position = 0;
|
|
1387
|
+
ip.serialization_adapter.deserialize(scratch, target);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Producer — record pass. At the end of a fixed step, snapshot every awake
|
|
1394
|
+
* {@link Interpolated} body's live components into the shared log under the
|
|
1395
|
+
* current `entityManager.fixedStepTick`. The render-time
|
|
1396
|
+
* {@link InterpolationSystem} blends consecutive ticks from these snapshots.
|
|
1397
|
+
* Only awake (moving) bodies are recorded, so the log stays sparse. No-op
|
|
1398
|
+
* unless {@link interpolationLog} is wired.
|
|
1399
|
+
* @private
|
|
1400
|
+
*/
|
|
1401
|
+
__interp_record() {
|
|
1402
|
+
const log = this.interpolationLog;
|
|
1403
|
+
const em = this.entityManager;
|
|
1404
|
+
if (log === null || em === null || em === undefined) return;
|
|
1405
|
+
const dataset = em.dataset;
|
|
1406
|
+
if (dataset === null || dataset === undefined) return;
|
|
1407
|
+
|
|
1408
|
+
const tick = em.fixedStepTick;
|
|
1409
|
+
const storage = this.storage;
|
|
1410
|
+
const count = storage.awake_count;
|
|
1411
|
+
|
|
1412
|
+
log.begin_tick(tick);
|
|
1413
|
+
for (let i = 0; i < count; i++) {
|
|
1414
|
+
const idx = storage.awake_at(i);
|
|
1415
|
+
const entity = storage.entity_at(idx);
|
|
1416
|
+
const interpolated = dataset.getComponent(entity, Interpolated);
|
|
1417
|
+
if (interpolated === undefined || interpolated === null) continue;
|
|
1418
|
+
const key = interpolated.key;
|
|
1419
|
+
if (key < 0) continue;
|
|
1420
|
+
|
|
1421
|
+
const interpolands = interpolated.interpolands;
|
|
1422
|
+
for (let k = 0; k < interpolands.length; k++) {
|
|
1423
|
+
const ip = interpolands[k];
|
|
1424
|
+
const target = dataset.getComponent(entity, ip.component_class);
|
|
1425
|
+
if (target === undefined || target === null) continue;
|
|
1426
|
+
const buf = log.begin_record(key, ip.type_id);
|
|
1427
|
+
ip.serialization_adapter.serialize(buf, target);
|
|
1428
|
+
log.end_record();
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
log.end_tick();
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1262
1434
|
fixedUpdate(dt) {
|
|
1435
|
+
// Producer: restore authoritative pose (undo render interpolation)
|
|
1436
|
+
// before the sim reads any Transform this step.
|
|
1437
|
+
this.__interp_restore();
|
|
1438
|
+
|
|
1263
1439
|
const gx = this.gravity.x;
|
|
1264
1440
|
const gy = this.gravity.y;
|
|
1265
1441
|
const gz = this.gravity.z;
|
|
@@ -1347,6 +1523,34 @@ export class PhysicsSystem extends System {
|
|
|
1347
1523
|
const h = dt / N;
|
|
1348
1524
|
const count_after_wake = this.storage.awake_count;
|
|
1349
1525
|
|
|
1526
|
+
// CCD: capture start-of-step positions for flagged bodies over the
|
|
1527
|
+
// post-wake awake set (poses are unchanged until the substep loop below
|
|
1528
|
+
// integrates them). The CCD pass after the solver sweeps from here to
|
|
1529
|
+
// each body's final pose. Reads the primary collider's transform so the
|
|
1530
|
+
// start matches the end the resolve pass reads. Zero-cost when no body
|
|
1531
|
+
// is flagged.
|
|
1532
|
+
const ccd_on = this.ccdEnabled;
|
|
1533
|
+
if (ccd_on) {
|
|
1534
|
+
const ccd_need = this.storage.high_water_mark * 3;
|
|
1535
|
+
if (this.__ccd_start_pos.length < ccd_need) {
|
|
1536
|
+
this.__ccd_start_pos = new Float64Array(ccd_need);
|
|
1537
|
+
}
|
|
1538
|
+
const ccd_start = this.__ccd_start_pos;
|
|
1539
|
+
for (let i = 0; i < count_after_wake; i++) {
|
|
1540
|
+
const idx = this.storage.awake_at(i);
|
|
1541
|
+
const rb = this.__bodies[idx];
|
|
1542
|
+
if (rb.kind !== BodyKind.Dynamic) continue;
|
|
1543
|
+
if ((rb.flags & RigidBodyFlags.CCD) === 0) continue;
|
|
1544
|
+
const list = this.__body_collider_lists[idx];
|
|
1545
|
+
if (list === undefined || list.length === 0) continue;
|
|
1546
|
+
const cp = list[0].transform.position;
|
|
1547
|
+
const cb = idx * 3;
|
|
1548
|
+
ccd_start[cb] = cp[0];
|
|
1549
|
+
ccd_start[cb + 1] = cp[1];
|
|
1550
|
+
ccd_start[cb + 2] = cp[2];
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1350
1554
|
// Size the pseudo-velocity buffer ONCE (it may reallocate on growth),
|
|
1351
1555
|
// then capture the reference. Inside the loop we only zero its live
|
|
1352
1556
|
// region per substep — re-capturing is unnecessary since it won't
|
|
@@ -1403,6 +1607,21 @@ export class PhysicsSystem extends System {
|
|
|
1403
1607
|
// the approach velocity captured at prepare time.
|
|
1404
1608
|
apply_restitution(this.manifolds, this);
|
|
1405
1609
|
|
|
1610
|
+
// Stage 8.5: continuous collision — sweep CCD-flagged fast movers along
|
|
1611
|
+
// their net step translation and stop them at the first blocker, so they
|
|
1612
|
+
// can't tunnel through thin geometry between discrete steps. Runs on the
|
|
1613
|
+
// final post-solve poses, before the sleep test sees the clamped
|
|
1614
|
+
// velocities. No-op when no awake body is flagged.
|
|
1615
|
+
if (ccd_on) {
|
|
1616
|
+
ccd_resolve(this);
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// Producer: record the post-step authoritative pose of every awake
|
|
1620
|
+
// interpolated body under this step's tick. Before the sleep test, so a
|
|
1621
|
+
// body that settles this step still records its final pose for the last
|
|
1622
|
+
// interpolation interval.
|
|
1623
|
+
this.__interp_record();
|
|
1624
|
+
|
|
1406
1625
|
// Stage 9: sleep test.
|
|
1407
1626
|
this.__sleep_test(dt);
|
|
1408
1627
|
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* component during solve.
|
|
9
9
|
* - {@link DisableSleep }: this body never enters the sleeping set. Bodies near it
|
|
10
10
|
* may still sleep when stable.
|
|
11
|
+
* - {@link CCD }: opt-in continuous collision detection. After the solver, the
|
|
12
|
+
* body's net step translation is shape-cast against the broadphase and the
|
|
13
|
+
* body is stopped at the first blocker, so a fast mover can't tunnel through
|
|
14
|
+
* thin geometry between discrete steps. Off by default — it costs one swept
|
|
15
|
+
* query per fast-moving flagged body per step. See `ccd/linear_sweep.js`.
|
|
11
16
|
*/
|
|
12
17
|
export type RigidBodyFlags = number;
|
|
13
18
|
export namespace RigidBodyFlags {
|
|
@@ -17,5 +22,6 @@ export namespace RigidBodyFlags {
|
|
|
17
22
|
let LockRotY: number;
|
|
18
23
|
let LockRotZ: number;
|
|
19
24
|
let DisableSleep: number;
|
|
25
|
+
let CCD: number;
|
|
20
26
|
}
|
|
21
27
|
//# sourceMappingURL=RigidBodyFlags.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RigidBodyFlags.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/RigidBodyFlags.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RigidBodyFlags.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/RigidBodyFlags.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;6BAiBU,MAAM"}
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* component during solve.
|
|
9
9
|
* - {@link DisableSleep}: this body never enters the sleeping set. Bodies near it
|
|
10
10
|
* may still sleep when stable.
|
|
11
|
+
* - {@link CCD}: opt-in continuous collision detection. After the solver, the
|
|
12
|
+
* body's net step translation is shape-cast against the broadphase and the
|
|
13
|
+
* body is stopped at the first blocker, so a fast mover can't tunnel through
|
|
14
|
+
* thin geometry between discrete steps. Off by default — it costs one swept
|
|
15
|
+
* query per fast-moving flagged body per step. See `ccd/linear_sweep.js`.
|
|
11
16
|
*
|
|
12
17
|
* @readonly
|
|
13
18
|
* @enum {number}
|
|
@@ -19,4 +24,5 @@ export const RigidBodyFlags = {
|
|
|
19
24
|
LockRotY: 4,
|
|
20
25
|
LockRotZ: 8,
|
|
21
26
|
DisableSleep: 16,
|
|
27
|
+
CCD: 32,
|
|
22
28
|
};
|