@aura3d/physics 1.5.2 → 2.0.1

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.
Files changed (103) hide show
  1. package/dist/ArcadeCharacterController.d.ts +53 -0
  2. package/dist/ArcadeCharacterController.d.ts.map +1 -0
  3. package/dist/ArcadeCharacterController.js +98 -0
  4. package/dist/ArcadeCharacterController.js.map +1 -0
  5. package/dist/{VehicleDynamics.d.ts → ArcadeVehicleTelemetry.d.ts} +14 -4
  6. package/dist/ArcadeVehicleTelemetry.d.ts.map +1 -0
  7. package/dist/{VehicleDynamics.js → ArcadeVehicleTelemetry.js} +37 -9
  8. package/dist/ArcadeVehicleTelemetry.js.map +1 -0
  9. package/dist/Constraint.d.ts +20 -4
  10. package/dist/Constraint.d.ts.map +1 -1
  11. package/dist/Constraint.js +34 -60
  12. package/dist/Constraint.js.map +1 -1
  13. package/dist/FightingCharacterController.d.ts +32 -0
  14. package/dist/FightingCharacterController.d.ts.map +1 -0
  15. package/dist/FightingCharacterController.js +76 -0
  16. package/dist/FightingCharacterController.js.map +1 -0
  17. package/dist/MeshBVH.d.ts +72 -0
  18. package/dist/MeshBVH.d.ts.map +1 -0
  19. package/dist/MeshBVH.js +244 -0
  20. package/dist/MeshBVH.js.map +1 -0
  21. package/dist/PhysicsDebugDraw.d.ts +40 -1
  22. package/dist/PhysicsDebugDraw.d.ts.map +1 -1
  23. package/dist/PhysicsDebugDraw.js +87 -17
  24. package/dist/PhysicsDebugDraw.js.map +1 -1
  25. package/dist/PhysicsWorld.d.ts +37 -18
  26. package/dist/PhysicsWorld.d.ts.map +1 -1
  27. package/dist/PhysicsWorld.js +231 -630
  28. package/dist/PhysicsWorld.js.map +1 -1
  29. package/dist/Raycast.d.ts +11 -0
  30. package/dist/Raycast.d.ts.map +1 -1
  31. package/dist/Raycast.js +62 -8
  32. package/dist/Raycast.js.map +1 -1
  33. package/dist/RigidBody.d.ts +16 -9
  34. package/dist/RigidBody.d.ts.map +1 -1
  35. package/dist/RigidBody.js +23 -75
  36. package/dist/RigidBody.js.map +1 -1
  37. package/dist/SurfaceQuery.d.ts +72 -0
  38. package/dist/SurfaceQuery.d.ts.map +1 -0
  39. package/dist/SurfaceQuery.js +89 -0
  40. package/dist/SurfaceQuery.js.map +1 -0
  41. package/dist/index.d.ts +62 -17
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +70 -17
  44. package/dist/index.js.map +1 -1
  45. package/dist/solverless.d.ts +37 -0
  46. package/dist/solverless.d.ts.map +1 -0
  47. package/dist/solverless.js +36 -0
  48. package/dist/solverless.js.map +1 -0
  49. package/dist/world.d.ts +18 -0
  50. package/dist/world.d.ts.map +1 -0
  51. package/dist/world.js +17 -0
  52. package/dist/world.js.map +1 -0
  53. package/package.json +10 -2
  54. package/dist/CharacterController.d.ts +0 -83
  55. package/dist/CharacterController.d.ts.map +0 -1
  56. package/dist/CharacterController.js +0 -236
  57. package/dist/CharacterController.js.map +0 -1
  58. package/dist/ClothFixtures.d.ts +0 -87
  59. package/dist/ClothFixtures.d.ts.map +0 -1
  60. package/dist/ClothFixtures.js +0 -264
  61. package/dist/ClothFixtures.js.map +0 -1
  62. package/dist/Crowd.d.ts +0 -64
  63. package/dist/Crowd.d.ts.map +0 -1
  64. package/dist/Crowd.js +0 -209
  65. package/dist/Crowd.js.map +0 -1
  66. package/dist/FireSmokeFixtures.d.ts +0 -103
  67. package/dist/FireSmokeFixtures.d.ts.map +0 -1
  68. package/dist/FireSmokeFixtures.js +0 -271
  69. package/dist/FireSmokeFixtures.js.map +0 -1
  70. package/dist/FluidFixtures.d.ts +0 -75
  71. package/dist/FluidFixtures.d.ts.map +0 -1
  72. package/dist/FluidFixtures.js +0 -219
  73. package/dist/FluidFixtures.js.map +0 -1
  74. package/dist/FractureFixtures.d.ts +0 -68
  75. package/dist/FractureFixtures.d.ts.map +0 -1
  76. package/dist/FractureFixtures.js +0 -199
  77. package/dist/FractureFixtures.js.map +0 -1
  78. package/dist/NarrowPhase.d.ts +0 -11
  79. package/dist/NarrowPhase.d.ts.map +0 -1
  80. package/dist/NarrowPhase.js +0 -565
  81. package/dist/NarrowPhase.js.map +0 -1
  82. package/dist/Navigation.d.ts +0 -67
  83. package/dist/Navigation.d.ts.map +0 -1
  84. package/dist/Navigation.js +0 -261
  85. package/dist/Navigation.js.map +0 -1
  86. package/dist/PhysicsSandboxFixtures.d.ts +0 -53
  87. package/dist/PhysicsSandboxFixtures.d.ts.map +0 -1
  88. package/dist/PhysicsSandboxFixtures.js +0 -280
  89. package/dist/PhysicsSandboxFixtures.js.map +0 -1
  90. package/dist/PlatformerFixtures.d.ts +0 -70
  91. package/dist/PlatformerFixtures.d.ts.map +0 -1
  92. package/dist/PlatformerFixtures.js +0 -120
  93. package/dist/PlatformerFixtures.js.map +0 -1
  94. package/dist/SoftBodyFixtures.d.ts +0 -70
  95. package/dist/SoftBodyFixtures.d.ts.map +0 -1
  96. package/dist/SoftBodyFixtures.js +0 -272
  97. package/dist/SoftBodyFixtures.js.map +0 -1
  98. package/dist/Steering.d.ts +0 -161
  99. package/dist/Steering.d.ts.map +0 -1
  100. package/dist/Steering.js +0 -347
  101. package/dist/Steering.js.map +0 -1
  102. package/dist/VehicleDynamics.d.ts.map +0 -1
  103. package/dist/VehicleDynamics.js.map +0 -1
@@ -0,0 +1,76 @@
1
+ import { KinematicBody } from "./KinematicBody.js";
2
+ /** Authored-unit fighting movement; this is not a physical-simulation controller. */
3
+ export class FightingCharacterController {
4
+ body;
5
+ walkSpeed;
6
+ crouchSpeed;
7
+ fastFallSpeed;
8
+ #state = "idle";
9
+ constructor(descriptor = {}) {
10
+ this.walkSpeed = positive(descriptor.walkSpeed ?? descriptor.maxSpeed ?? 4.5, "fighting controller walkSpeed");
11
+ this.crouchSpeed = positive(descriptor.crouchSpeed ?? this.walkSpeed * 0.45, "fighting controller crouchSpeed");
12
+ this.fastFallSpeed = positive(descriptor.fastFallSpeed ?? descriptor.maxFallSpeed ?? 20, "fighting controller fastFallSpeed");
13
+ this.body = new KinematicBody({
14
+ ...descriptor,
15
+ id: descriptor.id ?? "fighter",
16
+ halfExtents: descriptor.halfExtents ?? [0.32, 0.9, 0.25],
17
+ maxSpeed: descriptor.maxSpeed ?? this.walkSpeed,
18
+ acceleration: descriptor.acceleration ?? 54,
19
+ airAcceleration: descriptor.airAcceleration ?? 24,
20
+ groundFriction: descriptor.groundFriction ?? 56,
21
+ airFriction: descriptor.airFriction ?? 4,
22
+ gravity: descriptor.gravity ?? 26,
23
+ jumpSpeed: descriptor.jumpSpeed ?? 9.4,
24
+ maxFallSpeed: descriptor.maxFallSpeed ?? Math.max(this.fastFallSpeed, 20),
25
+ dashSpeed: descriptor.dashSpeed ?? 8.6,
26
+ dashDuration: descriptor.dashDuration ?? 0.12,
27
+ dashCooldown: descriptor.dashCooldown ?? 0.18,
28
+ groundSnapDistance: descriptor.groundSnapDistance ?? 0.06,
29
+ lockDepth: descriptor.lockDepth ?? true
30
+ });
31
+ }
32
+ walk(direction, speed) {
33
+ const magnitude = Math.min(1, Math.abs(finiteOrZero(direction)));
34
+ const facing = direction < 0 ? -1 : 1;
35
+ const targetSpeed = speed ?? (this.body.snapshot().crouching ? this.crouchSpeed : this.walkSpeed);
36
+ const normalizedSpeed = this.body.maxSpeed > 0 ? Math.min(1, positive(targetSpeed, "fighting controller walk speed") / this.body.maxSpeed) : 0;
37
+ this.body.move(facing * magnitude * normalizedSpeed);
38
+ this.#state = magnitude > 0 ? "walk" : this.#derive([]);
39
+ }
40
+ stop() { this.body.move(0); this.#state = this.#derive([]); }
41
+ jump() { this.body.jump(); this.#state = "jump"; }
42
+ dash(direction) { this.body.dash(direction); this.#state = "dash"; }
43
+ fastFall(speed = this.fastFallSpeed) { this.body.fastFall(speed); if (!this.body.grounded)
44
+ this.#state = "fast-fall"; }
45
+ crouch(active = true) { this.body.crouch(active); this.#state = active ? "crouch" : this.#derive([]); }
46
+ step(dt, options = {}) {
47
+ const events = this.body.step(dt, options);
48
+ this.#state = this.#derive(events);
49
+ return events;
50
+ }
51
+ snapshot() {
52
+ return { ...this.body.snapshot(), state: this.#state, walkSpeed: this.walkSpeed, crouchSpeed: this.crouchSpeed, fastFallSpeed: this.fastFallSpeed };
53
+ }
54
+ #derive(events) {
55
+ if (events.some((event) => event.type === "land"))
56
+ return "landing";
57
+ const snapshot = this.body.snapshot();
58
+ if (snapshot.crouching)
59
+ return "crouch";
60
+ if (snapshot.dashFramesRemaining > 0)
61
+ return "dash";
62
+ if (!snapshot.grounded)
63
+ return snapshot.velocity[1] < -this.fastFallSpeed * 0.5 ? "fast-fall" : "jump";
64
+ return Math.abs(snapshot.velocity[0]) > 0.05 ? "walk" : "idle";
65
+ }
66
+ }
67
+ export function createFightingCharacterController(descriptor = {}) {
68
+ return new FightingCharacterController(descriptor);
69
+ }
70
+ function positive(value, label) {
71
+ if (!Number.isFinite(value) || value <= 0)
72
+ throw new RangeError(`${label} must be finite and positive.`);
73
+ return value;
74
+ }
75
+ function finiteOrZero(value) { return Number.isFinite(value) ? value : 0; }
76
+ //# sourceMappingURL=FightingCharacterController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FightingCharacterController.js","sourceRoot":"","sources":["../../../../packages/physics/src/FightingCharacterController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgH,MAAM,oBAAoB,CAAC;AAiBjK,qFAAqF;AACrF,MAAM,OAAO,2BAA2B;IAC7B,IAAI,CAAgB;IACpB,SAAS,CAAS;IAClB,WAAW,CAAS;IACpB,aAAa,CAAS;IAC/B,MAAM,GAAqC,MAAM,CAAC;IAElD,YAAY,aAAoD,EAAE;QAChE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,IAAI,UAAU,CAAC,QAAQ,IAAI,GAAG,EAAE,+BAA+B,CAAC,CAAC;QAC/G,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,EAAE,iCAAiC,CAAC,CAAC;QAChH,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,IAAI,UAAU,CAAC,YAAY,IAAI,EAAE,EAAE,mCAAmC,CAAC,CAAC;QAC9H,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC;YAC5B,GAAG,UAAU;YACb,EAAE,EAAE,UAAU,CAAC,EAAE,IAAI,SAAS;YAC9B,WAAW,EAAE,UAAU,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC;YACxD,QAAQ,EAAE,UAAU,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS;YAC/C,YAAY,EAAE,UAAU,CAAC,YAAY,IAAI,EAAE;YAC3C,eAAe,EAAE,UAAU,CAAC,eAAe,IAAI,EAAE;YACjD,cAAc,EAAE,UAAU,CAAC,cAAc,IAAI,EAAE;YAC/C,WAAW,EAAE,UAAU,CAAC,WAAW,IAAI,CAAC;YACxC,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,EAAE;YACjC,SAAS,EAAE,UAAU,CAAC,SAAS,IAAI,GAAG;YACtC,YAAY,EAAE,UAAU,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;YACzE,SAAS,EAAE,UAAU,CAAC,SAAS,IAAI,GAAG;YACtC,YAAY,EAAE,UAAU,CAAC,YAAY,IAAI,IAAI;YAC7C,YAAY,EAAE,UAAU,CAAC,YAAY,IAAI,IAAI;YAC7C,kBAAkB,EAAE,UAAU,CAAC,kBAAkB,IAAI,IAAI;YACzD,SAAS,EAAE,UAAU,CAAC,SAAS,IAAI,IAAI;SACxC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,SAAiB,EAAE,KAAc;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClG,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,EAAE,gCAAgC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/I,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,GAAG,eAAe,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,KAAW,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnE,IAAI,KAAW,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,SAAkB,IAAU,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IACnF,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,aAAa,IAAU,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC;IAC7H,MAAM,CAAC,MAAM,GAAG,IAAI,IAAU,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAE7G,IAAI,CAAC,EAAU,EAAE,UAAgC,EAAE;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;IACtJ,CAAC;IAED,OAAO,CAAC,MAAqC;QAC3C,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;YAAE,OAAO,SAAS,CAAC;QACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,QAAQ,CAAC,SAAS;YAAE,OAAO,QAAQ,CAAC;QACxC,IAAI,QAAQ,CAAC,mBAAmB,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC;QACpD,IAAI,CAAC,QAAQ,CAAC,QAAQ;YAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;QACvG,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACjE,CAAC;CACF;AAED,MAAM,UAAU,iCAAiC,CAAC,aAAoD,EAAE;IACtG,OAAO,IAAI,2BAA2B,CAAC,UAAU,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,KAAa;IAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,+BAA+B,CAAC,CAAC;IACzG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,IAAY,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,72 @@
1
+ import type { Vec3 } from "./Shape.js";
2
+ /**
3
+ * Bounding volume hierarchy over an indexed triangle mesh.
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Every grounding system in the library was solving against an *approximation of* a
8
+ * surface rather than the surface itself. Turbo Drift sampled
9
+ * `TRACK_SURFACE_Y - VERGE_DROP * shoulderFraction` — a flat plane plus an analytic
10
+ * ramp — so on a banked or crowned corner the returned height was wrong and the car's
11
+ * tyres passed through the visible road. The fix is to ask the real triangles, which
12
+ * needs a spatial index: a naive per-sample scan over a 40k-triangle circuit is far too
13
+ * slow to run four times per frame.
14
+ *
15
+ * ## Determinism
16
+ *
17
+ * Construction must not depend on iteration order or floating-point tie-breaking, or two
18
+ * runs over the same mesh produce different trees and the same query returns different
19
+ * hits. Splits use the median along the widest axis with a stable index-based tiebreak,
20
+ * so the tree is a pure function of the input arrays.
21
+ */
22
+ export interface MeshBVHBuildOptions {
23
+ /** Stop splitting at this triangle count. Larger leaves trade traversal for tests. */
24
+ readonly maxLeafTriangles?: number | undefined;
25
+ /** Hard depth cap, a safety valve against degenerate geometry. */
26
+ readonly maxDepth?: number | undefined;
27
+ }
28
+ interface BVHNode {
29
+ readonly min: [number, number, number];
30
+ readonly max: [number, number, number];
31
+ /** Triangle indices, leaf nodes only. */
32
+ readonly triangles?: readonly number[] | undefined;
33
+ readonly left?: number | undefined;
34
+ readonly right?: number | undefined;
35
+ }
36
+ export interface MeshBVH {
37
+ readonly kind: "aura-mesh-bvh";
38
+ readonly nodes: readonly BVHNode[];
39
+ readonly positions: Float32Array;
40
+ readonly indices: Uint32Array;
41
+ readonly triangleCount: number;
42
+ readonly maxDepth: number;
43
+ }
44
+ export declare function buildMeshBVH(positions: Float32Array, indices: Uint32Array, options?: MeshBVHBuildOptions): MeshBVH;
45
+ export interface MeshRayHit {
46
+ readonly triangle: number;
47
+ readonly distance: number;
48
+ readonly point: Vec3;
49
+ /** Geometric normal, unit length, oriented against the ray. */
50
+ readonly normal: Vec3;
51
+ /** Barycentric coordinates, for interpolating vertex attributes. */
52
+ readonly barycentric: Vec3;
53
+ /** True when the ray struck the back face. */
54
+ readonly backFace: boolean;
55
+ }
56
+ export interface RaycastMeshOptions {
57
+ readonly maxDistance?: number | undefined;
58
+ /** Skip back faces. Off by default so a ray starting inside geometry still reports. */
59
+ readonly cullBackFaces?: boolean | undefined;
60
+ }
61
+ /**
62
+ * Nearest triangle hit along a ray, using the BVH.
63
+ *
64
+ * The direction is normalised internally so `distance` is always in world units; a
65
+ * caller passing an unnormalised direction otherwise gets a distance scaled by its
66
+ * length, which is a silent and very confusing error.
67
+ */
68
+ export declare function raycastMesh(bvh: MeshBVH, origin: Vec3, direction: Vec3, options?: RaycastMeshOptions): MeshRayHit | undefined;
69
+ /** Reference implementation, for testing the BVH. Never use in a hot path. */
70
+ export declare function raycastMeshBruteForce(bvh: MeshBVH, origin: Vec3, direction: Vec3, options?: RaycastMeshOptions): MeshRayHit | undefined;
71
+ export {};
72
+ //# sourceMappingURL=MeshBVH.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshBVH.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/MeshBVH.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,sFAAsF;IACtF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,UAAU,OAAO;IACf,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,yCAAyC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AA0BD,wBAAgB,YAAY,CAC1B,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CA0ET;AA2BD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAiED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,IAAI,EACf,OAAO,GAAE,kBAAuB,GAC/B,UAAU,GAAG,SAAS,CAkCxB;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,IAAI,EACf,OAAO,GAAE,kBAAuB,GAC/B,UAAU,GAAG,SAAS,CAaxB"}
@@ -0,0 +1,244 @@
1
+ function triangleBounds(positions, indices, triangle) {
2
+ const a = indices[triangle * 3] * 3;
3
+ const b = indices[triangle * 3 + 1] * 3;
4
+ const c = indices[triangle * 3 + 2] * 3;
5
+ const min = [Infinity, Infinity, Infinity];
6
+ const max = [-Infinity, -Infinity, -Infinity];
7
+ for (const base of [a, b, c]) {
8
+ for (let axis = 0; axis < 3; axis += 1) {
9
+ const value = positions[base + axis];
10
+ if (value < min[axis])
11
+ min[axis] = value;
12
+ if (value > max[axis])
13
+ max[axis] = value;
14
+ }
15
+ }
16
+ return {
17
+ min,
18
+ max,
19
+ centroid: [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2]
20
+ };
21
+ }
22
+ export function buildMeshBVH(positions, indices, options = {}) {
23
+ if (indices.length % 3 !== 0) {
24
+ throw new Error("buildMeshBVH requires an index count divisible by 3.");
25
+ }
26
+ const triangleCount = indices.length / 3;
27
+ const maxLeafTriangles = Math.max(1, options.maxLeafTriangles ?? 8);
28
+ const maxDepth = Math.max(1, options.maxDepth ?? 32);
29
+ const bounds = Array.from({ length: triangleCount }, (_, index) => triangleBounds(positions, indices, index));
30
+ const nodes = [];
31
+ let observedDepth = 0;
32
+ function build(triangles, depth) {
33
+ observedDepth = Math.max(observedDepth, depth);
34
+ const min = [Infinity, Infinity, Infinity];
35
+ const max = [-Infinity, -Infinity, -Infinity];
36
+ for (const triangle of triangles) {
37
+ const b = bounds[triangle];
38
+ for (let axis = 0; axis < 3; axis += 1) {
39
+ if (b.min[axis] < min[axis])
40
+ min[axis] = b.min[axis];
41
+ if (b.max[axis] > max[axis])
42
+ max[axis] = b.max[axis];
43
+ }
44
+ }
45
+ const index = nodes.length;
46
+ if (triangles.length <= maxLeafTriangles || depth >= maxDepth) {
47
+ nodes.push({ min, max, triangles: [...triangles] });
48
+ return index;
49
+ }
50
+ // Split on the widest axis; median split keeps the tree balanced regardless of
51
+ // how the mesh was authored.
52
+ let axis = 0;
53
+ let widest = -Infinity;
54
+ for (let candidate = 0; candidate < 3; candidate += 1) {
55
+ const extent = max[candidate] - min[candidate];
56
+ if (extent > widest) {
57
+ widest = extent;
58
+ axis = candidate;
59
+ }
60
+ }
61
+ // Stable sort: centroid, then triangle index. Without the index tiebreak, equal
62
+ // centroids order differently between runs and the tree stops being deterministic.
63
+ const sorted = [...triangles].sort((left, right) => {
64
+ const delta = bounds[left].centroid[axis] - bounds[right].centroid[axis];
65
+ return delta !== 0 ? delta : left - right;
66
+ });
67
+ const mid = Math.floor(sorted.length / 2);
68
+ const leftTriangles = sorted.slice(0, mid);
69
+ const rightTriangles = sorted.slice(mid);
70
+ if (leftTriangles.length === 0 || rightTriangles.length === 0) {
71
+ nodes.push({ min, max, triangles: [...triangles] });
72
+ return index;
73
+ }
74
+ // Reserve this slot before recursing so child indices are stable.
75
+ nodes.push({ min, max });
76
+ const left = build(leftTriangles, depth + 1);
77
+ const right = build(rightTriangles, depth + 1);
78
+ nodes[index] = { min, max, left, right };
79
+ return index;
80
+ }
81
+ if (triangleCount > 0) {
82
+ build(Array.from({ length: triangleCount }, (_, index) => index), 0);
83
+ }
84
+ else {
85
+ nodes.push({ min: [0, 0, 0], max: [0, 0, 0], triangles: [] });
86
+ }
87
+ return {
88
+ kind: "aura-mesh-bvh",
89
+ nodes,
90
+ positions,
91
+ indices,
92
+ triangleCount,
93
+ maxDepth: observedDepth
94
+ };
95
+ }
96
+ /** Slab test. `tMax` lets a caller reject nodes beyond an existing best hit. */
97
+ function rayHitsAabb(origin, inverseDirection, node, tMax) {
98
+ let tMin = 0;
99
+ let tFar = tMax;
100
+ for (let axis = 0; axis < 3; axis += 1) {
101
+ const inv = inverseDirection[axis];
102
+ let tNear = (node.min[axis] - origin[axis]) * inv;
103
+ let tFarAxis = (node.max[axis] - origin[axis]) * inv;
104
+ if (tNear > tFarAxis) {
105
+ const swap = tNear;
106
+ tNear = tFarAxis;
107
+ tFarAxis = swap;
108
+ }
109
+ if (tNear > tMin)
110
+ tMin = tNear;
111
+ if (tFarAxis < tFar)
112
+ tFar = tFarAxis;
113
+ if (tMin > tFar)
114
+ return false;
115
+ }
116
+ return true;
117
+ }
118
+ /** Möller–Trumbore. Returns undefined for a miss or a degenerate triangle. */
119
+ function intersectTriangle(positions, indices, triangle, origin, direction) {
120
+ const ia = indices[triangle * 3] * 3;
121
+ const ib = indices[triangle * 3 + 1] * 3;
122
+ const ic = indices[triangle * 3 + 2] * 3;
123
+ const ax = positions[ia], ay = positions[ia + 1], az = positions[ia + 2];
124
+ const bx = positions[ib], by = positions[ib + 1], bz = positions[ib + 2];
125
+ const cx = positions[ic], cy = positions[ic + 1], cz = positions[ic + 2];
126
+ const e1x = bx - ax, e1y = by - ay, e1z = bz - az;
127
+ const e2x = cx - ax, e2y = cy - ay, e2z = cz - az;
128
+ const px = direction[1] * e2z - direction[2] * e2y;
129
+ const py = direction[2] * e2x - direction[0] * e2z;
130
+ const pz = direction[0] * e2y - direction[1] * e2x;
131
+ const det = e1x * px + e1y * py + e1z * pz;
132
+ // A near-zero determinant means the ray is parallel to the plane, or the triangle is
133
+ // degenerate (zero area). Both are misses, and both would divide by ~0 below.
134
+ if (Math.abs(det) < 1e-12)
135
+ return undefined;
136
+ const invDet = 1 / det;
137
+ const tx = origin[0] - ax, ty = origin[1] - ay, tz = origin[2] - az;
138
+ const u = (tx * px + ty * py + tz * pz) * invDet;
139
+ if (u < -1e-9 || u > 1 + 1e-9)
140
+ return undefined;
141
+ const qx = ty * e1z - tz * e1y;
142
+ const qy = tz * e1x - tx * e1z;
143
+ const qz = tx * e1y - ty * e1x;
144
+ const v = (direction[0] * qx + direction[1] * qy + direction[2] * qz) * invDet;
145
+ if (v < -1e-9 || u + v > 1 + 1e-9)
146
+ return undefined;
147
+ const t = (e2x * qx + e2y * qy + e2z * qz) * invDet;
148
+ if (t < 0)
149
+ return undefined;
150
+ let nx = e1y * e2z - e1z * e2y;
151
+ let ny = e1z * e2x - e1x * e2z;
152
+ let nz = e1x * e2y - e1y * e2x;
153
+ const length = Math.hypot(nx, ny, nz);
154
+ if (length < 1e-12)
155
+ return undefined;
156
+ nx /= length;
157
+ ny /= length;
158
+ nz /= length;
159
+ // Orient the normal against the ray so callers always get an outward-facing surface.
160
+ const facing = nx * direction[0] + ny * direction[1] + nz * direction[2];
161
+ const backFace = facing > 0;
162
+ if (backFace) {
163
+ nx = -nx;
164
+ ny = -ny;
165
+ nz = -nz;
166
+ }
167
+ return {
168
+ triangle,
169
+ distance: t,
170
+ point: [origin[0] + direction[0] * t, origin[1] + direction[1] * t, origin[2] + direction[2] * t],
171
+ normal: [nx, ny, nz],
172
+ barycentric: [1 - u - v, u, v],
173
+ backFace
174
+ };
175
+ }
176
+ /**
177
+ * Nearest triangle hit along a ray, using the BVH.
178
+ *
179
+ * The direction is normalised internally so `distance` is always in world units; a
180
+ * caller passing an unnormalised direction otherwise gets a distance scaled by its
181
+ * length, which is a silent and very confusing error.
182
+ */
183
+ export function raycastMesh(bvh, origin, direction, options = {}) {
184
+ const length = Math.hypot(direction[0], direction[1], direction[2]);
185
+ if (!Number.isFinite(length) || length < 1e-12)
186
+ return undefined;
187
+ const dir = [direction[0] / length, direction[1] / length, direction[2] / length];
188
+ const maxDistance = options.maxDistance ?? Infinity;
189
+ const inverse = [
190
+ 1 / (dir[0] === 0 ? 1e-30 : dir[0]),
191
+ 1 / (dir[1] === 0 ? 1e-30 : dir[1]),
192
+ 1 / (dir[2] === 0 ? 1e-30 : dir[2])
193
+ ];
194
+ let best;
195
+ let bestDistance = maxDistance;
196
+ const stack = bvh.nodes.length > 0 ? [0] : [];
197
+ while (stack.length > 0) {
198
+ const nodeIndex = stack.pop();
199
+ const node = bvh.nodes[nodeIndex];
200
+ if (!node)
201
+ continue;
202
+ if (!rayHitsAabb(origin, inverse, node, bestDistance))
203
+ continue;
204
+ if (node.triangles) {
205
+ for (const triangle of node.triangles) {
206
+ const hit = intersectTriangle(bvh.positions, bvh.indices, triangle, origin, dir);
207
+ if (!hit)
208
+ continue;
209
+ if (hit.distance > bestDistance)
210
+ continue;
211
+ if (options.cullBackFaces && hit.backFace)
212
+ continue;
213
+ best = hit;
214
+ bestDistance = hit.distance;
215
+ }
216
+ continue;
217
+ }
218
+ if (node.left !== undefined)
219
+ stack.push(node.left);
220
+ if (node.right !== undefined)
221
+ stack.push(node.right);
222
+ }
223
+ return best;
224
+ }
225
+ /** Reference implementation, for testing the BVH. Never use in a hot path. */
226
+ export function raycastMeshBruteForce(bvh, origin, direction, options = {}) {
227
+ const length = Math.hypot(direction[0], direction[1], direction[2]);
228
+ if (!Number.isFinite(length) || length < 1e-12)
229
+ return undefined;
230
+ const dir = [direction[0] / length, direction[1] / length, direction[2] / length];
231
+ const maxDistance = options.maxDistance ?? Infinity;
232
+ let best;
233
+ for (let triangle = 0; triangle < bvh.triangleCount; triangle += 1) {
234
+ const hit = intersectTriangle(bvh.positions, bvh.indices, triangle, origin, dir);
235
+ if (!hit || hit.distance > maxDistance)
236
+ continue;
237
+ if (options.cullBackFaces && hit.backFace)
238
+ continue;
239
+ if (!best || hit.distance < best.distance)
240
+ best = hit;
241
+ }
242
+ return best;
243
+ }
244
+ //# sourceMappingURL=MeshBVH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshBVH.js","sourceRoot":"","sources":["../../../../packages/physics/src/MeshBVH.ts"],"names":[],"mappings":"AAgDA,SAAS,cAAc,CACrB,SAAuB,EACvB,OAAoB,EACpB,QAAgB;IAEhB,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC;IACrC,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAA6B,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACrE,MAAM,GAAG,GAA6B,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;IACxE,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC7B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,GAAG,IAAI,CAAE,CAAC;YACtC,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YACzC,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,OAAO;QACL,GAAG;QACH,GAAG;QACH,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAChF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,SAAuB,EACvB,OAAoB,EACpB,UAA+B,EAAE;IAEjC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IAC9G,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,SAAS,KAAK,CAAC,SAAmB,EAAE,KAAa;QAC/C,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,GAAG,GAA6B,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACrE,MAAM,GAAG,GAA6B,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;QACxE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAE,CAAC;YAC5B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrD,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,IAAI,SAAS,CAAC,MAAM,IAAI,gBAAgB,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC9D,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;YACpD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,+EAA+E;QAC/E,6BAA6B;QAC7B,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,MAAM,GAAG,CAAC,QAAQ,CAAC;QACvB,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,IAAI,CAAC,EAAE,CAAC;YACtD,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,MAAM,GAAG,MAAM,EAAE,CAAC;gBACpB,MAAM,GAAG,MAAM,CAAC;gBAChB,IAAI,GAAG,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QACD,gFAAgF;QAChF,mFAAmF;QACnF,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACjD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC3E,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1C,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9D,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;YACpD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,kEAAkE;QAClE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/C,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,KAAK;QACL,SAAS;QACT,OAAO;QACP,aAAa;QACb,QAAQ,EAAE,aAAa;KACxB,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAS,WAAW,CAClB,MAAY,EACZ,gBAAsB,EACtB,IAAa,EACb,IAAY;IAEZ,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAE,CAAC;QACpC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAE,CAAC,GAAG,GAAG,CAAC;QACnD,IAAI,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAE,CAAC,GAAG,GAAG,CAAC;QACtD,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,KAAK,CAAC;YACnB,KAAK,GAAG,QAAQ,CAAC;YACjB,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QACD,IAAI,KAAK,GAAG,IAAI;YAAE,IAAI,GAAG,KAAK,CAAC;QAC/B,IAAI,QAAQ,GAAG,IAAI;YAAE,IAAI,GAAG,QAAQ,CAAC;QACrC,IAAI,IAAI,GAAG,IAAI;YAAE,OAAO,KAAK,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAcD,8EAA8E;AAC9E,SAAS,iBAAiB,CACxB,SAAuB,EACvB,OAAoB,EACpB,QAAgB,EAChB,MAAY,EACZ,SAAe;IAEf,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAE,EAAE,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,EAAE,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC;IAC5E,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAE,EAAE,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,EAAE,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC;IAC5E,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAE,EAAE,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,EAAE,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC;IAE5E,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC;IAClD,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC;IAElD,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,GAAG,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,GAAG,CAAC;IACrD,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,GAAG,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,GAAG,CAAC;IACrD,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,GAAG,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,GAAG,CAAC;IACrD,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;IAE3C,qFAAqF;IACrF,8EAA8E;IAC9E,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;QAAE,OAAO,SAAS,CAAC;IAE5C,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC;IACvB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAE,GAAG,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC,CAAE,GAAG,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC;IACvE,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;IACjD,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI;QAAE,OAAO,SAAS,CAAC;IAEhD,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;IAC/B,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;IAClF,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI;QAAE,OAAO,SAAS,CAAC;IAEpD,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC;IACpD,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAE5B,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC/B,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC/B,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAC;IACrC,EAAE,IAAI,MAAM,CAAC;IAAC,EAAE,IAAI,MAAM,CAAC;IAAC,EAAE,IAAI,MAAM,CAAC;IAEzC,qFAAqF;IACrF,MAAM,MAAM,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAE,CAAC;IAC5E,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,CAAC;IAC5B,IAAI,QAAQ,EAAE,CAAC;QAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IAAC,CAAC;IAE/C,OAAO;QACL,QAAQ;QACR,QAAQ,EAAE,CAAC;QACX,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAE,GAAG,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC;QACvG,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;QACpB,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9B,QAAQ;KACT,CAAC;AACJ,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,GAAY,EACZ,MAAY,EACZ,SAAe,EACf,UAA8B,EAAE;IAEhC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAE,EAAE,SAAS,CAAC,CAAC,CAAE,EAAE,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,GAAG,GAAS,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,MAAM,EAAE,SAAS,CAAC,CAAC,CAAE,GAAG,MAAM,EAAE,SAAS,CAAC,CAAC,CAAE,GAAG,MAAM,CAAC,CAAC;IAC3F,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,QAAQ,CAAC;IACpD,MAAM,OAAO,GAAS;QACpB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KACpC,CAAC;IAEF,IAAI,IAA4B,CAAC;IACjC,IAAI,YAAY,GAAG,WAAW,CAAC;IAC/B,MAAM,KAAK,GAAa,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC;YAAE,SAAS;QAChE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACtC,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;gBACjF,IAAI,CAAC,GAAG;oBAAE,SAAS;gBACnB,IAAI,GAAG,CAAC,QAAQ,GAAG,YAAY;oBAAE,SAAS;gBAC1C,IAAI,OAAO,CAAC,aAAa,IAAI,GAAG,CAAC,QAAQ;oBAAE,SAAS;gBACpD,IAAI,GAAG,GAAG,CAAC;gBACX,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9B,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,qBAAqB,CACnC,GAAY,EACZ,MAAY,EACZ,SAAe,EACf,UAA8B,EAAE;IAEhC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAE,EAAE,SAAS,CAAC,CAAC,CAAE,EAAE,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,GAAG,GAAS,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,MAAM,EAAE,SAAS,CAAC,CAAC,CAAE,GAAG,MAAM,EAAE,SAAS,CAAC,CAAC,CAAE,GAAG,MAAM,CAAC,CAAC;IAC3F,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,QAAQ,CAAC;IACpD,IAAI,IAA4B,CAAC;IACjC,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,aAAa,EAAE,QAAQ,IAAI,CAAC,EAAE,CAAC;QACnE,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QACjF,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,GAAG,WAAW;YAAE,SAAS;QACjD,IAAI,OAAO,CAAC,aAAa,IAAI,GAAG,CAAC,QAAQ;YAAE,SAAS;QACpD,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ;YAAE,IAAI,GAAG,GAAG,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -4,8 +4,47 @@ export type DebugLine = {
4
4
  readonly from: Vec3;
5
5
  readonly to: Vec3;
6
6
  readonly color: Vec3;
7
+ /**
8
+ * What this line represents, so a consumer can filter or legend it.
9
+ *
10
+ * Without a category every line is an anonymous coloured segment, and a debug overlay that
11
+ * cannot say "these are contacts and those are joints" is decoration rather than a tool.
12
+ */
13
+ readonly category?: DebugLineCategory;
7
14
  };
15
+ export type DebugLineCategory = "collider" | "sensor" | "contact" | "normal" | "joint" | "sleeping" | "raycast";
16
+ /** A raycast to draw, so a developer can see the query they cannot otherwise observe. */
17
+ export type DebugRaycast = {
18
+ readonly origin: Vec3;
19
+ readonly direction: Vec3;
20
+ readonly distance: number;
21
+ /** True when the ray hit something; drawn in a different colour. */
22
+ readonly hit?: boolean;
23
+ };
24
+ export type PhysicsDebugDrawOptions = {
25
+ /** Draw contact points and their normals. */
26
+ readonly contacts?: boolean;
27
+ /** Draw joint anchors and the segment between them. */
28
+ readonly joints?: boolean;
29
+ /** Tint sleeping bodies differently from awake ones. */
30
+ readonly sleeping?: boolean;
31
+ /** Extra rays to visualise, which the world cannot know about. */
32
+ readonly raycasts?: readonly DebugRaycast[];
33
+ /** Length of a drawn contact normal, in world units. */
34
+ readonly normalLength?: number;
35
+ };
36
+ type DebugWorld = Pick<PhysicsWorld, "colliders" | "getBody"> & Partial<Pick<PhysicsWorld, "snapshot" | "constraints">>;
8
37
  export declare class PhysicsDebugDraw {
9
- buildLines(world: Pick<PhysicsWorld, "colliders" | "getBody">): readonly DebugLine[];
38
+ /**
39
+ * Build debug geometry for a world.
40
+ *
41
+ * WS-1.7 asks for colliders, contacts, normals, joints, sleeping state and raycasts. Only
42
+ * colliders existed, which is why the capability sat at "unproven with 0 consumers" — there was
43
+ * not enough here for a route to consume.
44
+ *
45
+ * Options default to off so the existing single-argument call keeps its previous output exactly.
46
+ */
47
+ buildLines(world: DebugWorld, options?: PhysicsDebugDrawOptions): readonly DebugLine[];
10
48
  }
49
+ export {};
11
50
  //# sourceMappingURL=PhysicsDebugDraw.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PhysicsDebugDraw.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/PhysicsDebugDraw.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;CACtB,CAAC;AAEF,qBAAa,gBAAgB;IAC3B,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,SAAS,EAAE;CAWrF"}
1
+ {"version":3,"file":"PhysicsDebugDraw.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/PhysicsDebugDraw.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,UAAU,GACV,SAAS,CAAC;AAEd,yFAAyF;AACzF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,wDAAwD;IACxD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,KAAK,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC,GAC3D,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC;AAE1D,qBAAa,gBAAgB;IAC3B;;;;;;;;OAQG;IACH,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,uBAA4B,GAAG,SAAS,SAAS,EAAE;CAuE3F"}
@@ -1,18 +1,88 @@
1
1
  export class PhysicsDebugDraw {
2
- buildLines(world) {
2
+ /**
3
+ * Build debug geometry for a world.
4
+ *
5
+ * WS-1.7 asks for colliders, contacts, normals, joints, sleeping state and raycasts. Only
6
+ * colliders existed, which is why the capability sat at "unproven with 0 consumers" — there was
7
+ * not enough here for a route to consume.
8
+ *
9
+ * Options default to off so the existing single-argument call keeps its previous output exactly.
10
+ */
11
+ buildLines(world, options = {}) {
3
12
  const lines = [];
13
+ const snapshot = options.contacts || options.sleeping ? world.snapshot?.() : undefined;
14
+ const sleepingIds = new Set();
15
+ if (options.sleeping && snapshot) {
16
+ for (const body of snapshot.bodies) {
17
+ if (body.sleeping)
18
+ sleepingIds.add(body.id);
19
+ }
20
+ }
4
21
  for (const collider of world.colliders()) {
5
22
  const body = world.getBody(collider.bodyId);
6
23
  if (!body) {
7
24
  continue;
8
25
  }
9
- appendColliderLines(lines, collider, body.position);
26
+ appendColliderLines(lines, collider, body.position, sleepingIds.has(body.id));
27
+ }
28
+ if (options.contacts && snapshot) {
29
+ const normalLength = options.normalLength ?? 0.25;
30
+ for (const contact of snapshot.contacts) {
31
+ const point = contact.point;
32
+ if (!point)
33
+ continue;
34
+ // A short cross at the contact point, then the normal as a ray out of it. Penetration is
35
+ // the number that matters for "is this body inside that one", so it tints the cross.
36
+ const penetrating = contact.penetration > 1e-4;
37
+ const crossColor = penetrating ? [1, 0.2, 0.2] : [0.2, 1, 0.4];
38
+ const size = normalLength * 0.25;
39
+ lines.push({ from: [point[0] - size, point[1], point[2]], to: [point[0] + size, point[1], point[2]], color: crossColor, category: "contact" });
40
+ lines.push({ from: [point[0], point[1] - size, point[2]], to: [point[0], point[1] + size, point[2]], color: crossColor, category: "contact" });
41
+ lines.push({
42
+ from: point,
43
+ to: [
44
+ point[0] + contact.normal[0] * normalLength,
45
+ point[1] + contact.normal[1] * normalLength,
46
+ point[2] + contact.normal[2] * normalLength
47
+ ],
48
+ color: [1, 1, 0.3],
49
+ category: "normal"
50
+ });
51
+ }
52
+ }
53
+ if (options.joints && world.constraints) {
54
+ for (const constraint of world.constraints()) {
55
+ const a = world.getBody(constraint.bodyA.id);
56
+ const b = world.getBody(constraint.bodyB.id);
57
+ if (!a || !b)
58
+ continue;
59
+ // The segment between the two bodies a joint connects. A joint that has come apart is
60
+ // visible as a segment that keeps growing, which is exactly the failure mode that made
61
+ // the former silent backend divergence so hard to spot.
62
+ lines.push({ from: a.position, to: b.position, color: [0.9, 0.4, 1], category: "joint" });
63
+ }
64
+ }
65
+ for (const ray of options.raycasts ?? []) {
66
+ const length = Number.isFinite(ray.distance) ? ray.distance : 1;
67
+ lines.push({
68
+ from: ray.origin,
69
+ to: [
70
+ ray.origin[0] + ray.direction[0] * length,
71
+ ray.origin[1] + ray.direction[1] * length,
72
+ ray.origin[2] + ray.direction[2] * length
73
+ ],
74
+ color: ray.hit ? [1, 0.35, 0.35] : [0.5, 0.5, 0.55],
75
+ category: "raycast"
76
+ });
10
77
  }
11
78
  return lines;
12
79
  }
13
80
  }
14
- function appendColliderLines(lines, collider, position) {
15
- const color = collider.sensor ? [1, 0.75, 0] : [0.1, 0.8, 1];
81
+ function appendColliderLines(lines, collider, position, sleeping = false) {
82
+ // Sleeping bodies are drawn dim: a body that has gone to sleep and should not have is otherwise
83
+ // indistinguishable from one that is simply not moving.
84
+ const color = sleeping ? [0.4, 0.42, 0.5] : collider.sensor ? [1, 0.75, 0] : [0.1, 0.8, 1];
85
+ const category = sleeping ? "sleeping" : collider.sensor ? "sensor" : "collider";
16
86
  if (collider.shape.kind === "box") {
17
87
  const h = collider.shape.halfExtents;
18
88
  const corners = [
@@ -27,24 +97,24 @@ function appendColliderLines(lines, collider, position) {
27
97
  ];
28
98
  const pairs = [[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [3, 7]];
29
99
  for (const [a, b] of pairs) {
30
- lines.push({ from: corners[a], to: corners[b], color });
100
+ lines.push({ from: corners[a], to: corners[b], color, category });
31
101
  }
32
102
  }
33
103
  else if (collider.shape.kind === "sphere") {
34
104
  const r = collider.shape.radius;
35
- lines.push({ from: [position[0] - r, position[1], position[2]], to: [position[0] + r, position[1], position[2]], color });
36
- lines.push({ from: [position[0], position[1] - r, position[2]], to: [position[0], position[1] + r, position[2]], color });
37
- lines.push({ from: [position[0], position[1], position[2] - r], to: [position[0], position[1], position[2] + r], color });
105
+ lines.push({ from: [position[0] - r, position[1], position[2]], to: [position[0] + r, position[1], position[2]], color, category });
106
+ lines.push({ from: [position[0], position[1] - r, position[2]], to: [position[0], position[1] + r, position[2]], color, category });
107
+ lines.push({ from: [position[0], position[1], position[2] - r], to: [position[0], position[1], position[2] + r], color, category });
38
108
  }
39
109
  else if (collider.shape.kind === "plane") {
40
- lines.push({ from: [-10, position[1], 0], to: [10, position[1], 0], color });
41
- lines.push({ from: [0, position[1], -10], to: [0, position[1], 10], color });
110
+ lines.push({ from: [-10, position[1], 0], to: [10, position[1], 0], color, category });
111
+ lines.push({ from: [0, position[1], -10], to: [0, position[1], 10], color, category });
42
112
  }
43
113
  else if (collider.shape.kind === "capsule") {
44
114
  const r = collider.shape.radius;
45
115
  const h = collider.shape.halfHeight;
46
- lines.push({ from: [position[0], position[1] - h - r, position[2]], to: [position[0], position[1] + h + r, position[2]], color });
47
- lines.push({ from: [position[0] - r, position[1], position[2]], to: [position[0] + r, position[1], position[2]], color });
116
+ lines.push({ from: [position[0], position[1] - h - r, position[2]], to: [position[0], position[1] + h + r, position[2]], color, category });
117
+ lines.push({ from: [position[0] - r, position[1], position[2]], to: [position[0] + r, position[1], position[2]], color, category });
48
118
  }
49
119
  else if (collider.shape.kind === "mesh" || collider.shape.kind === "convex-hull") {
50
120
  const { vertices, indices } = collider.shape;
@@ -52,9 +122,9 @@ function appendColliderLines(lines, collider, position) {
52
122
  const a = translate(vertices[indices[index]], position);
53
123
  const b = translate(vertices[indices[index + 1]], position);
54
124
  const c = translate(vertices[indices[index + 2]], position);
55
- lines.push({ from: a, to: b, color });
56
- lines.push({ from: b, to: c, color });
57
- lines.push({ from: c, to: a, color });
125
+ lines.push({ from: a, to: b, color, category });
126
+ lines.push({ from: b, to: c, color, category });
127
+ lines.push({ from: c, to: a, color, category });
58
128
  }
59
129
  }
60
130
  else {
@@ -69,9 +139,9 @@ function appendColliderLines(lines, collider, position) {
69
139
  for (let row = 0; row < shape.rows; row += 1) {
70
140
  for (let column = 0; column < shape.columns; column += 1) {
71
141
  if (column + 1 < shape.columns)
72
- lines.push({ from: sample(row, column), to: sample(row, column + 1), color });
142
+ lines.push({ from: sample(row, column), to: sample(row, column + 1), color, category });
73
143
  if (row + 1 < shape.rows)
74
- lines.push({ from: sample(row, column), to: sample(row + 1, column), color });
144
+ lines.push({ from: sample(row, column), to: sample(row + 1, column), color, category });
75
145
  }
76
146
  }
77
147
  }