@aura3d/physics 1.4.4 → 1.5.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/dist/Collider.d.ts +1 -1
- package/dist/Collider.d.ts.map +1 -1
- package/dist/Collider.js +2 -2
- package/dist/Collider.js.map +1 -1
- package/dist/CollisionEvents.d.ts +1 -0
- package/dist/CollisionEvents.d.ts.map +1 -1
- package/dist/CollisionEvents.js.map +1 -1
- package/dist/NarrowPhase.d.ts +11 -0
- package/dist/NarrowPhase.d.ts.map +1 -0
- package/dist/NarrowPhase.js +565 -0
- package/dist/NarrowPhase.js.map +1 -0
- package/dist/PhysicsDebugDraw.js +19 -1
- package/dist/PhysicsDebugDraw.js.map +1 -1
- package/dist/PhysicsWorld.d.ts +43 -0
- package/dist/PhysicsWorld.d.ts.map +1 -1
- package/dist/PhysicsWorld.js +305 -30
- package/dist/PhysicsWorld.js.map +1 -1
- package/dist/RigidBody.d.ts +8 -1
- package/dist/RigidBody.d.ts.map +1 -1
- package/dist/RigidBody.js +32 -5
- package/dist/RigidBody.js.map +1 -1
- package/dist/Shape.d.ts +16 -2
- package/dist/Shape.d.ts.map +1 -1
- package/dist/Shape.js +93 -31
- package/dist/Shape.js.map +1 -1
- package/dist/TimeOfImpact.d.ts +15 -0
- package/dist/TimeOfImpact.d.ts.map +1 -0
- package/dist/TimeOfImpact.js +81 -0
- package/dist/TimeOfImpact.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/Collider.d.ts
CHANGED
|
@@ -22,6 +22,6 @@ export declare class Collider {
|
|
|
22
22
|
readonly material: ColliderMaterial;
|
|
23
23
|
constructor(id: number, bodyId: number, descriptor: ColliderDescriptor);
|
|
24
24
|
canCollideWith(other: Collider): boolean;
|
|
25
|
-
bounds(position: Vec3): Bounds;
|
|
25
|
+
bounds(position: Vec3, rotation?: readonly [number, number, number, number]): Bounds;
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=Collider.d.ts.map
|
package/dist/Collider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collider.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/Collider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC/C,CAAC;AAEF,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;gBAExB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB;IAgCtE,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAIxC,MAAM,CAAC,QAAQ,EAAE,IAAI,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"Collider.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/Collider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC/C,CAAC;AAEF,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;gBAExB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB;IAgCtE,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAIxC,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;CAGrF"}
|
package/dist/Collider.js
CHANGED
|
@@ -38,8 +38,8 @@ export class Collider {
|
|
|
38
38
|
canCollideWith(other) {
|
|
39
39
|
return (this.filter.mask & other.filter.layer) !== 0 && (other.filter.mask & this.filter.layer) !== 0;
|
|
40
40
|
}
|
|
41
|
-
bounds(position) {
|
|
42
|
-
return Shape.bounds(this.shape, position);
|
|
41
|
+
bounds(position, rotation) {
|
|
42
|
+
return Shape.bounds(this.shape, position, rotation);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
//# sourceMappingURL=Collider.js.map
|
package/dist/Collider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collider.js","sourceRoot":"","sources":["../../../../packages/physics/src/Collider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,YAAY,CAAC;AAmB9E,MAAM,OAAO,QAAQ;IACV,EAAE,CAAS;IACX,MAAM,CAAS;IACf,KAAK,CAAe;IACpB,MAAM,CAAU;IAChB,MAAM,CAAkB;IACxB,QAAQ,CAAmB;IAEpC,YAAY,EAAU,EAAE,MAAc,EAAE,UAA8B;QACpE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG;YACZ,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC;YACpC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,IAAI,UAAU;SAC5C,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG;YACd,WAAW,EAAE,UAAU,CAAC,QAAQ,EAAE,WAAW,IAAI,CAAC;YAClD,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,QAAQ,IAAI,GAAG;SAC/C,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QACD,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC3C,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACxC,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAC1B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,cAAc,CAAC,KAAe;QAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,CAAC,QAAc;
|
|
1
|
+
{"version":3,"file":"Collider.js","sourceRoot":"","sources":["../../../../packages/physics/src/Collider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,YAAY,CAAC;AAmB9E,MAAM,OAAO,QAAQ;IACV,EAAE,CAAS;IACX,MAAM,CAAS;IACf,KAAK,CAAe;IACpB,MAAM,CAAU;IAChB,MAAM,CAAkB;IACxB,QAAQ,CAAmB;IAEpC,YAAY,EAAU,EAAE,MAAc,EAAE,UAA8B;QACpE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG;YACZ,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC;YACpC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,IAAI,UAAU;SAC5C,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG;YACd,WAAW,EAAE,UAAU,CAAC,QAAQ,EAAE,WAAW,IAAI,CAAC;YAClD,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,QAAQ,IAAI,GAAG;SAC/C,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QACD,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC3C,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACxC,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAC1B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,cAAc,CAAC,KAAe;QAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,CAAC,QAAc,EAAE,QAAoD;QACzE,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollisionEvents.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/CollisionEvents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,MAAM,CAAwB;IAEtC,MAAM,CAAC,eAAe,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,cAAc,EAAE;IAmBtE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE;IAa7D,KAAK,IAAI,SAAS,cAAc,EAAE;IAMlC,gBAAgB,IAAI,SAAS,OAAO,EAAE;CAGvC"}
|
|
1
|
+
{"version":3,"file":"CollisionEvents.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/CollisionEvents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,MAAM,CAAwB;IAEtC,MAAM,CAAC,eAAe,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,cAAc,EAAE;IAmBtE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE;IAa7D,KAAK,IAAI,SAAS,cAAc,EAAE;IAMlC,gBAAgB,IAAI,SAAS,OAAO,EAAE;CAGvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollisionEvents.js","sourceRoot":"","sources":["../../../../packages/physics/src/CollisionEvents.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CollisionEvents.js","sourceRoot":"","sources":["../../../../packages/physics/src/CollisionEvents.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,SAAiB;IACjE,OAAO,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,SAAS,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,OAAO,mBAAmB;IACtB,gBAAgB,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC9C,MAAM,GAAqB,EAAE,CAAC;IAEtC,MAAM,CAAC,eAAmC;QACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAC;QACxC,MAAM,MAAM,GAAqB,EAAE,CAAC;QACpC,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YACrE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1F,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,cAAc,CAAC,UAAkB;QAC/B,MAAM,aAAa,GAAqB,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACvD,IAAI,OAAO,CAAC,SAAS,KAAK,UAAU,IAAI,OAAO,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBACzE,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,KAAc,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;gBACzD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,KAAK;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,gBAAgB;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Collider } from "./Collider.js";
|
|
2
|
+
import type { RigidBody } from "./RigidBody.js";
|
|
3
|
+
import { type Vec3 } from "./Shape.js";
|
|
4
|
+
export interface NativeNarrowPhaseContact {
|
|
5
|
+
readonly normal: Vec3;
|
|
6
|
+
readonly penetration: number;
|
|
7
|
+
readonly point: Vec3;
|
|
8
|
+
readonly algorithm: "obb-sat" | "gjk-epa" | "triangle-mesh" | "heightfield-triangles";
|
|
9
|
+
}
|
|
10
|
+
export declare function buildNativeNarrowPhaseContact(colliderA: Collider, bodyA: RigidBody, colliderB: Collider, bodyB: RigidBody): NativeNarrowPhaseContact | undefined;
|
|
11
|
+
//# sourceMappingURL=NarrowPhase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NarrowPhase.d.ts","sourceRoot":"","sources":["../../../../packages/physics/src/NarrowPhase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAYL,KAAK,IAAI,EACV,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,eAAe,GAAG,uBAAuB,CAAC;CACvF;AAoCD,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,QAAQ,EACnB,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,QAAQ,EACnB,KAAK,EAAE,SAAS,GACf,wBAAwB,GAAG,SAAS,CAmCtC"}
|
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
import { addVec3, dotVec3, lengthVec3, normalizeVec3, rotateVec3ByQuat, scaleVec3, subVec3 } from "./Shape.js";
|
|
2
|
+
const BOX_FACES = [
|
|
3
|
+
[0, 2, 1], [0, 3, 2],
|
|
4
|
+
[4, 5, 6], [4, 6, 7],
|
|
5
|
+
[0, 1, 5], [0, 5, 4],
|
|
6
|
+
[3, 7, 6], [3, 6, 2],
|
|
7
|
+
[0, 4, 7], [0, 7, 3],
|
|
8
|
+
[1, 2, 6], [1, 6, 5]
|
|
9
|
+
];
|
|
10
|
+
const BOX_EDGES = [
|
|
11
|
+
[0, 1], [1, 2], [2, 3], [3, 0],
|
|
12
|
+
[4, 5], [5, 6], [6, 7], [7, 4],
|
|
13
|
+
[0, 4], [1, 5], [2, 6], [3, 7]
|
|
14
|
+
];
|
|
15
|
+
const EPSILON = 1e-8;
|
|
16
|
+
export function buildNativeNarrowPhaseContact(colliderA, bodyA, colliderB, bodyB) {
|
|
17
|
+
if (colliderA.shape.kind === "box" && colliderB.shape.kind === "box") {
|
|
18
|
+
const polyA = boxPolyhedron(colliderA.shape.halfExtents, bodyA);
|
|
19
|
+
const polyB = boxPolyhedron(colliderB.shape.halfExtents, bodyB);
|
|
20
|
+
const result = satPolyhedra(polyA, polyB);
|
|
21
|
+
return result ? { ...result, algorithm: "obb-sat" } : undefined;
|
|
22
|
+
}
|
|
23
|
+
if (isConvexSolid(colliderA.shape) && isConvexSolid(colliderB.shape)) {
|
|
24
|
+
const polyA = convexPolyhedron(colliderA.shape, bodyA);
|
|
25
|
+
const polyB = convexPolyhedron(colliderB.shape, bodyB);
|
|
26
|
+
const gjkSimplex = gjkIntersection(polyA, polyB);
|
|
27
|
+
if (!gjkSimplex)
|
|
28
|
+
return undefined;
|
|
29
|
+
const epa = epaPenetration(polyA, polyB, gjkSimplex) ?? satPolyhedra(polyA, polyB);
|
|
30
|
+
return epa ? { ...epa, algorithm: "gjk-epa" } : undefined;
|
|
31
|
+
}
|
|
32
|
+
const meshA = isTriangleSurface(colliderA.shape);
|
|
33
|
+
const meshB = isTriangleSurface(colliderB.shape);
|
|
34
|
+
if (meshA === meshB)
|
|
35
|
+
return undefined;
|
|
36
|
+
const surfaceShape = meshA
|
|
37
|
+
? colliderA.shape
|
|
38
|
+
: colliderB.shape;
|
|
39
|
+
const surfaceBody = meshA ? bodyA : bodyB;
|
|
40
|
+
const solidShape = meshA ? colliderB.shape : colliderA.shape;
|
|
41
|
+
const solidBody = meshA ? bodyB : bodyA;
|
|
42
|
+
const solidIsA = !meshA;
|
|
43
|
+
const contact = collideSolidWithSurface(solidShape, solidBody, surfaceShape, surfaceBody);
|
|
44
|
+
if (!contact)
|
|
45
|
+
return undefined;
|
|
46
|
+
return {
|
|
47
|
+
normal: solidIsA ? contact.normal : scaleVec3(contact.normal, -1),
|
|
48
|
+
penetration: contact.penetration,
|
|
49
|
+
point: contact.point,
|
|
50
|
+
algorithm: surfaceShape.kind === "heightfield" ? "heightfield-triangles" : "triangle-mesh"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function isConvexSolid(shape) {
|
|
54
|
+
return shape.kind === "box" || shape.kind === "convex-hull";
|
|
55
|
+
}
|
|
56
|
+
function isTriangleSurface(shape) {
|
|
57
|
+
return shape.kind === "mesh" || shape.kind === "heightfield";
|
|
58
|
+
}
|
|
59
|
+
function boxPolyhedron(halfExtents, body) {
|
|
60
|
+
const [x, y, z] = halfExtents;
|
|
61
|
+
const local = [
|
|
62
|
+
[-x, -y, -z], [x, -y, -z], [x, y, -z], [-x, y, -z],
|
|
63
|
+
[-x, -y, z], [x, -y, z], [x, y, z], [-x, y, z]
|
|
64
|
+
];
|
|
65
|
+
return {
|
|
66
|
+
vertices: local.map((vertex) => worldPoint(vertex, body)),
|
|
67
|
+
faces: BOX_FACES,
|
|
68
|
+
edges: BOX_EDGES,
|
|
69
|
+
center: [...body.position]
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function convexPolyhedron(shape, body) {
|
|
73
|
+
if (shape.kind === "box")
|
|
74
|
+
return boxPolyhedron(shape.halfExtents, body);
|
|
75
|
+
const faces = [];
|
|
76
|
+
for (let offset = 0; offset < shape.indices.length; offset += 3) {
|
|
77
|
+
faces.push([shape.indices[offset], shape.indices[offset + 1], shape.indices[offset + 2]]);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
vertices: shape.vertices.map((vertex) => worldPoint(vertex, body)),
|
|
81
|
+
faces,
|
|
82
|
+
edges: uniqueEdges(faces),
|
|
83
|
+
center: worldPoint(centroid(shape.vertices), body)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function satPolyhedra(a, b) {
|
|
87
|
+
const axes = [
|
|
88
|
+
...faceAxes(a),
|
|
89
|
+
...faceAxes(b)
|
|
90
|
+
];
|
|
91
|
+
const edgesA = edgeDirections(a);
|
|
92
|
+
const edgesB = edgeDirections(b);
|
|
93
|
+
for (const edgeA of edgesA) {
|
|
94
|
+
for (const edgeB of edgesB) {
|
|
95
|
+
const axis = cross(edgeA, edgeB);
|
|
96
|
+
if (lengthVec3(axis) > EPSILON)
|
|
97
|
+
axes.push(normalizeVec3(axis));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return minimumOverlapContact(a, b, axes);
|
|
101
|
+
}
|
|
102
|
+
function minimumOverlapContact(a, b, axes) {
|
|
103
|
+
let minimumOverlap = Number.POSITIVE_INFINITY;
|
|
104
|
+
let minimumAxis = [1, 0, 0];
|
|
105
|
+
for (const candidate of axes) {
|
|
106
|
+
if (lengthVec3(candidate) <= EPSILON)
|
|
107
|
+
continue;
|
|
108
|
+
const axis = normalizeVec3(candidate);
|
|
109
|
+
const projectionA = project(a.vertices, axis);
|
|
110
|
+
const projectionB = project(b.vertices, axis);
|
|
111
|
+
const overlap = Math.min(projectionA.max, projectionB.max) - Math.max(projectionA.min, projectionB.min);
|
|
112
|
+
if (overlap <= EPSILON)
|
|
113
|
+
return undefined;
|
|
114
|
+
if (overlap < minimumOverlap) {
|
|
115
|
+
minimumOverlap = overlap;
|
|
116
|
+
minimumAxis = axis;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!Number.isFinite(minimumOverlap))
|
|
120
|
+
return undefined;
|
|
121
|
+
const centerDelta = subVec3(b.center, a.center);
|
|
122
|
+
const normal = dotVec3(centerDelta, minimumAxis) < 0 ? scaleVec3(minimumAxis, -1) : minimumAxis;
|
|
123
|
+
const point = opposingSupportContactPoint(a.vertices, b.vertices, normal);
|
|
124
|
+
return {
|
|
125
|
+
normal,
|
|
126
|
+
penetration: minimumOverlap,
|
|
127
|
+
point
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function gjkIntersection(a, b) {
|
|
131
|
+
let direction = subVec3(b.center, a.center);
|
|
132
|
+
if (lengthVec3(direction) <= EPSILON)
|
|
133
|
+
direction = [1, 0, 0];
|
|
134
|
+
const simplex = [minkowskiSupport(a, b, direction)];
|
|
135
|
+
direction = scaleVec3(simplex[0].point, -1);
|
|
136
|
+
for (let iteration = 0; iteration < 32; iteration += 1) {
|
|
137
|
+
if (lengthVec3(direction) <= EPSILON)
|
|
138
|
+
direction = [1, 0, 0];
|
|
139
|
+
const next = minkowskiSupport(a, b, direction);
|
|
140
|
+
if (dotVec3(next.point, direction) < EPSILON)
|
|
141
|
+
return undefined;
|
|
142
|
+
simplex.push(next);
|
|
143
|
+
const update = updateSimplex(simplex);
|
|
144
|
+
if (update.containsOrigin)
|
|
145
|
+
return simplex;
|
|
146
|
+
direction = update.direction;
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
function updateSimplex(simplex) {
|
|
151
|
+
const a = simplex[simplex.length - 1].point;
|
|
152
|
+
const ao = scaleVec3(a, -1);
|
|
153
|
+
if (simplex.length === 2) {
|
|
154
|
+
const b = simplex[0].point;
|
|
155
|
+
const ab = subVec3(b, a);
|
|
156
|
+
if (dotVec3(ab, ao) > 0)
|
|
157
|
+
return { containsOrigin: false, direction: tripleCross(ab, ao, ab) };
|
|
158
|
+
simplex.splice(0, 1);
|
|
159
|
+
return { containsOrigin: false, direction: ao };
|
|
160
|
+
}
|
|
161
|
+
if (simplex.length === 3) {
|
|
162
|
+
const b = simplex[1].point;
|
|
163
|
+
const c = simplex[0].point;
|
|
164
|
+
const ab = subVec3(b, a);
|
|
165
|
+
const ac = subVec3(c, a);
|
|
166
|
+
const abc = cross(ab, ac);
|
|
167
|
+
if (dotVec3(cross(abc, ac), ao) > 0) {
|
|
168
|
+
if (dotVec3(ac, ao) > 0) {
|
|
169
|
+
simplex.splice(1, 1);
|
|
170
|
+
return { containsOrigin: false, direction: tripleCross(ac, ao, ac) };
|
|
171
|
+
}
|
|
172
|
+
simplex.splice(0, 1);
|
|
173
|
+
return updateSimplex(simplex);
|
|
174
|
+
}
|
|
175
|
+
if (dotVec3(cross(ab, abc), ao) > 0) {
|
|
176
|
+
simplex.splice(0, 1);
|
|
177
|
+
return updateSimplex(simplex);
|
|
178
|
+
}
|
|
179
|
+
if (dotVec3(abc, ao) > 0)
|
|
180
|
+
return { containsOrigin: false, direction: abc };
|
|
181
|
+
[simplex[0], simplex[1]] = [simplex[1], simplex[0]];
|
|
182
|
+
return { containsOrigin: false, direction: scaleVec3(abc, -1) };
|
|
183
|
+
}
|
|
184
|
+
const b = simplex[2].point;
|
|
185
|
+
const c = simplex[1].point;
|
|
186
|
+
const d = simplex[0].point;
|
|
187
|
+
const ab = subVec3(b, a);
|
|
188
|
+
const ac = subVec3(c, a);
|
|
189
|
+
const ad = subVec3(d, a);
|
|
190
|
+
const abc = outwardFaceNormal(a, b, c, d);
|
|
191
|
+
const acd = outwardFaceNormal(a, c, d, b);
|
|
192
|
+
const adb = outwardFaceNormal(a, d, b, c);
|
|
193
|
+
if (dotVec3(abc, ao) > 0) {
|
|
194
|
+
simplex.splice(0, 1);
|
|
195
|
+
return { containsOrigin: false, direction: abc };
|
|
196
|
+
}
|
|
197
|
+
if (dotVec3(acd, ao) > 0) {
|
|
198
|
+
simplex.splice(2, 1);
|
|
199
|
+
return { containsOrigin: false, direction: acd };
|
|
200
|
+
}
|
|
201
|
+
if (dotVec3(adb, ao) > 0) {
|
|
202
|
+
simplex.splice(1, 1);
|
|
203
|
+
return { containsOrigin: false, direction: adb };
|
|
204
|
+
}
|
|
205
|
+
return { containsOrigin: true, direction: [0, 0, 0] };
|
|
206
|
+
}
|
|
207
|
+
function epaPenetration(a, b, simplex) {
|
|
208
|
+
if (simplex.length < 4)
|
|
209
|
+
return undefined;
|
|
210
|
+
const vertices = [...simplex.slice(-4)];
|
|
211
|
+
let faces = [
|
|
212
|
+
createEpaFace(vertices, [0, 1, 2]),
|
|
213
|
+
createEpaFace(vertices, [0, 3, 1]),
|
|
214
|
+
createEpaFace(vertices, [0, 2, 3]),
|
|
215
|
+
createEpaFace(vertices, [1, 3, 2])
|
|
216
|
+
].filter((face) => face !== undefined);
|
|
217
|
+
for (let iteration = 0; iteration < 48; iteration += 1) {
|
|
218
|
+
faces.sort((left, right) => left.distance - right.distance);
|
|
219
|
+
const closest = faces[0];
|
|
220
|
+
if (!closest)
|
|
221
|
+
return undefined;
|
|
222
|
+
const support = minkowskiSupport(a, b, closest.normal);
|
|
223
|
+
const supportDistance = dotVec3(support.point, closest.normal);
|
|
224
|
+
if (supportDistance - closest.distance <= 1e-6) {
|
|
225
|
+
const centerDelta = subVec3(b.center, a.center);
|
|
226
|
+
const normal = dotVec3(centerDelta, closest.normal) < 0 ? scaleVec3(closest.normal, -1) : closest.normal;
|
|
227
|
+
return {
|
|
228
|
+
normal,
|
|
229
|
+
penetration: Math.max(closest.distance, EPSILON),
|
|
230
|
+
point: opposingSupportContactPoint(a.vertices, b.vertices, normal)
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const newIndex = vertices.push(support) - 1;
|
|
234
|
+
const visible = faces.filter((face) => dotVec3(face.normal, subVec3(support.point, vertices[face.indices[0]].point)) > 1e-7);
|
|
235
|
+
const boundary = boundaryEdges(visible);
|
|
236
|
+
faces = faces.filter((face) => !visible.includes(face));
|
|
237
|
+
for (const [from, to] of boundary) {
|
|
238
|
+
const face = createEpaFace(vertices, [from, to, newIndex]);
|
|
239
|
+
if (face)
|
|
240
|
+
faces.push(face);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
function collideSolidWithSurface(solidShape, solidBody, surfaceShape, surfaceBody) {
|
|
246
|
+
const triangles = surfaceTriangles(surfaceShape, surfaceBody);
|
|
247
|
+
let best;
|
|
248
|
+
for (const triangle of triangles) {
|
|
249
|
+
const contact = solidShape.kind === "sphere"
|
|
250
|
+
? sphereTriangleContact(solidBody.position, solidShape.radius, triangle)
|
|
251
|
+
: solidShape.kind === "capsule"
|
|
252
|
+
? capsuleTriangleContact(solidBody, solidShape.radius, solidShape.halfHeight, triangle)
|
|
253
|
+
: isConvexSolid(solidShape)
|
|
254
|
+
? polyhedronTriangleContact(convexPolyhedron(solidShape, solidBody), triangle)
|
|
255
|
+
: undefined;
|
|
256
|
+
if (contact && (!best || contact.penetration > best.penetration))
|
|
257
|
+
best = contact;
|
|
258
|
+
}
|
|
259
|
+
return best;
|
|
260
|
+
}
|
|
261
|
+
function capsuleTriangleContact(body, radius, halfHeight, triangle) {
|
|
262
|
+
const axis = rotateVec3ByQuat([0, halfHeight, 0], body.rotation);
|
|
263
|
+
const start = subVec3(body.position, axis);
|
|
264
|
+
const end = addVec3(body.position, axis);
|
|
265
|
+
const candidates = [
|
|
266
|
+
{ segment: start, triangle: closestPointOnTriangle(start, ...triangle) },
|
|
267
|
+
{ segment: end, triangle: closestPointOnTriangle(end, ...triangle) }
|
|
268
|
+
];
|
|
269
|
+
for (const vertex of triangle) {
|
|
270
|
+
candidates.push({ segment: closestPointOnSegment(vertex, start, end), triangle: vertex });
|
|
271
|
+
}
|
|
272
|
+
const planeNormal = normalizeOr(cross(subVec3(triangle[1], triangle[0]), subVec3(triangle[2], triangle[0])), [0, 1, 0]);
|
|
273
|
+
const denominator = dotVec3(planeNormal, subVec3(end, start));
|
|
274
|
+
if (Math.abs(denominator) > EPSILON) {
|
|
275
|
+
const t = dotVec3(planeNormal, subVec3(triangle[0], start)) / denominator;
|
|
276
|
+
if (t >= 0 && t <= 1) {
|
|
277
|
+
const point = addVec3(start, scaleVec3(subVec3(end, start), t));
|
|
278
|
+
const trianglePoint = closestPointOnTriangle(point, ...triangle);
|
|
279
|
+
if (lengthVec3(subVec3(point, trianglePoint)) <= 1e-7)
|
|
280
|
+
candidates.push({ segment: point, triangle: trianglePoint });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const closest = candidates.reduce((best, candidate) => squaredDistance(candidate.segment, candidate.triangle) < squaredDistance(best.segment, best.triangle) ? candidate : best);
|
|
284
|
+
const delta = subVec3(closest.triangle, closest.segment);
|
|
285
|
+
const distance = lengthVec3(delta);
|
|
286
|
+
if (distance >= radius)
|
|
287
|
+
return undefined;
|
|
288
|
+
return {
|
|
289
|
+
normal: distance > EPSILON ? scaleVec3(delta, 1 / distance) : orientToward(planeNormal, subVec3(centroid(triangle), body.position)),
|
|
290
|
+
penetration: radius - distance,
|
|
291
|
+
point: closest.triangle
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function sphereTriangleContact(center, radius, triangle) {
|
|
295
|
+
const point = closestPointOnTriangle(center, triangle[0], triangle[1], triangle[2]);
|
|
296
|
+
const delta = subVec3(point, center);
|
|
297
|
+
const distance = lengthVec3(delta);
|
|
298
|
+
if (distance >= radius)
|
|
299
|
+
return undefined;
|
|
300
|
+
const triangleNormal = normalizeOr(cross(subVec3(triangle[1], triangle[0]), subVec3(triangle[2], triangle[0])), [0, 1, 0]);
|
|
301
|
+
return {
|
|
302
|
+
normal: distance > EPSILON ? scaleVec3(delta, 1 / distance) : orientToward(triangleNormal, subVec3(centroid(triangle), center)),
|
|
303
|
+
penetration: radius - distance,
|
|
304
|
+
point
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function polyhedronTriangleContact(poly, triangle) {
|
|
308
|
+
const triangleCenter = centroid(triangle);
|
|
309
|
+
let triangleNormal = normalizeOr(cross(subVec3(triangle[1], triangle[0]), subVec3(triangle[2], triangle[0])), [0, 1, 0]);
|
|
310
|
+
const plane = dotVec3(triangleNormal, triangle[0]);
|
|
311
|
+
const distances = poly.vertices.map((vertex) => dotVec3(triangleNormal, vertex) - plane);
|
|
312
|
+
const centerDistance = dotVec3(triangleNormal, poly.center) - plane;
|
|
313
|
+
const penetration = centerDistance >= 0 ? -Math.min(...distances) : Math.max(...distances);
|
|
314
|
+
if (penetration <= EPSILON)
|
|
315
|
+
return undefined;
|
|
316
|
+
triangleNormal = centerDistance >= 0 ? scaleVec3(triangleNormal, -1) : triangleNormal;
|
|
317
|
+
const triangleEdges = [
|
|
318
|
+
subVec3(triangle[1], triangle[0]),
|
|
319
|
+
subVec3(triangle[2], triangle[1]),
|
|
320
|
+
subVec3(triangle[0], triangle[2])
|
|
321
|
+
];
|
|
322
|
+
const axes = [...faceAxes(poly)];
|
|
323
|
+
for (const triangleEdge of triangleEdges) {
|
|
324
|
+
axes.push(normalizeOr(cross(triangleEdge, triangleNormal), [1, 0, 0]));
|
|
325
|
+
for (const polyEdge of edgeDirections(poly)) {
|
|
326
|
+
const axis = cross(triangleEdge, polyEdge);
|
|
327
|
+
if (lengthVec3(axis) > EPSILON)
|
|
328
|
+
axes.push(normalizeVec3(axis));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
for (const axis of axes) {
|
|
332
|
+
const projectionPoly = project(poly.vertices, axis);
|
|
333
|
+
const projectionTriangle = project(triangle, axis);
|
|
334
|
+
if (Math.min(projectionPoly.max, projectionTriangle.max) - Math.max(projectionPoly.min, projectionTriangle.min) < -EPSILON) {
|
|
335
|
+
return undefined;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const support = supportVertex(poly.vertices, triangleNormal);
|
|
339
|
+
const point = closestPointOnTriangle(support, triangle[0], triangle[1], triangle[2]);
|
|
340
|
+
return {
|
|
341
|
+
normal: orientToward(triangleNormal, subVec3(triangleCenter, poly.center)),
|
|
342
|
+
penetration,
|
|
343
|
+
point
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function surfaceTriangles(shape, body) {
|
|
347
|
+
if (shape.kind === "mesh") {
|
|
348
|
+
const triangles = [];
|
|
349
|
+
for (let offset = 0; offset < shape.indices.length; offset += 3) {
|
|
350
|
+
triangles.push([
|
|
351
|
+
worldPoint(shape.vertices[shape.indices[offset]], body),
|
|
352
|
+
worldPoint(shape.vertices[shape.indices[offset + 1]], body),
|
|
353
|
+
worldPoint(shape.vertices[shape.indices[offset + 2]], body)
|
|
354
|
+
]);
|
|
355
|
+
}
|
|
356
|
+
return triangles;
|
|
357
|
+
}
|
|
358
|
+
const triangles = [];
|
|
359
|
+
const halfWidth = (shape.columns - 1) * shape.cellSize * 0.5;
|
|
360
|
+
const halfDepth = (shape.rows - 1) * shape.cellSize * 0.5;
|
|
361
|
+
const sample = (row, column) => worldPoint([
|
|
362
|
+
column * shape.cellSize - halfWidth,
|
|
363
|
+
shape.heights[row * shape.columns + column],
|
|
364
|
+
row * shape.cellSize - halfDepth
|
|
365
|
+
], body);
|
|
366
|
+
for (let row = 0; row < shape.rows - 1; row += 1) {
|
|
367
|
+
for (let column = 0; column < shape.columns - 1; column += 1) {
|
|
368
|
+
const a = sample(row, column);
|
|
369
|
+
const b = sample(row, column + 1);
|
|
370
|
+
const c = sample(row + 1, column);
|
|
371
|
+
const d = sample(row + 1, column + 1);
|
|
372
|
+
triangles.push([a, c, b], [b, c, d]);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return triangles;
|
|
376
|
+
}
|
|
377
|
+
function faceAxes(poly) {
|
|
378
|
+
const axes = [];
|
|
379
|
+
for (const [a, b, c] of poly.faces) {
|
|
380
|
+
const normal = cross(subVec3(poly.vertices[b], poly.vertices[a]), subVec3(poly.vertices[c], poly.vertices[a]));
|
|
381
|
+
if (lengthVec3(normal) > EPSILON)
|
|
382
|
+
axes.push(normalizeVec3(normal));
|
|
383
|
+
}
|
|
384
|
+
return uniqueAxes(axes);
|
|
385
|
+
}
|
|
386
|
+
function edgeDirections(poly) {
|
|
387
|
+
return uniqueAxes(poly.edges.map(([a, b]) => normalizeOr(subVec3(poly.vertices[b], poly.vertices[a]), [1, 0, 0])));
|
|
388
|
+
}
|
|
389
|
+
function uniqueEdges(faces) {
|
|
390
|
+
const keys = new Set();
|
|
391
|
+
const edges = [];
|
|
392
|
+
for (const [a, b, c] of faces) {
|
|
393
|
+
for (const [left, right] of [[a, b], [b, c], [c, a]]) {
|
|
394
|
+
const edge = left < right ? [left, right] : [right, left];
|
|
395
|
+
const key = `${edge[0]}:${edge[1]}`;
|
|
396
|
+
if (!keys.has(key)) {
|
|
397
|
+
keys.add(key);
|
|
398
|
+
edges.push(edge);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return edges;
|
|
403
|
+
}
|
|
404
|
+
function uniqueAxes(axes) {
|
|
405
|
+
const unique = [];
|
|
406
|
+
for (const axis of axes) {
|
|
407
|
+
if (!unique.some((candidate) => Math.abs(dotVec3(candidate, axis)) > 0.999999))
|
|
408
|
+
unique.push(axis);
|
|
409
|
+
}
|
|
410
|
+
return unique;
|
|
411
|
+
}
|
|
412
|
+
function minkowskiSupport(a, b, direction) {
|
|
413
|
+
const pointA = supportVertex(a.vertices, direction);
|
|
414
|
+
const pointB = supportVertex(b.vertices, scaleVec3(direction, -1));
|
|
415
|
+
return { point: subVec3(pointA, pointB), pointA, pointB };
|
|
416
|
+
}
|
|
417
|
+
function supportVertex(vertices, direction) {
|
|
418
|
+
let best = vertices[0];
|
|
419
|
+
let bestProjection = dotVec3(best, direction);
|
|
420
|
+
for (let index = 1; index < vertices.length; index += 1) {
|
|
421
|
+
const projection = dotVec3(vertices[index], direction);
|
|
422
|
+
if (projection > bestProjection) {
|
|
423
|
+
best = vertices[index];
|
|
424
|
+
bestProjection = projection;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return best;
|
|
428
|
+
}
|
|
429
|
+
function opposingSupportContactPoint(verticesA, verticesB, normal) {
|
|
430
|
+
const featureA = supportFeature(verticesA, normal);
|
|
431
|
+
const featureB = supportFeature(verticesB, scaleVec3(normal, -1));
|
|
432
|
+
const selected = featureA.spread <= featureB.spread ? featureA.point : featureB.point;
|
|
433
|
+
const middlePlane = (dotVec3(featureA.point, normal) + dotVec3(featureB.point, normal)) * 0.5;
|
|
434
|
+
return addVec3(selected, scaleVec3(normal, middlePlane - dotVec3(selected, normal)));
|
|
435
|
+
}
|
|
436
|
+
function supportFeature(vertices, direction) {
|
|
437
|
+
const maximum = Math.max(...vertices.map((vertex) => dotVec3(vertex, direction)));
|
|
438
|
+
const support = vertices.filter((vertex) => maximum - dotVec3(vertex, direction) <= 1e-7);
|
|
439
|
+
const point = centroid(support);
|
|
440
|
+
const spread = support.reduce((sum, vertex) => sum + squaredDistance(vertex, point), 0);
|
|
441
|
+
return { point, spread };
|
|
442
|
+
}
|
|
443
|
+
function project(vertices, axis) {
|
|
444
|
+
let min = dotVec3(vertices[0], axis);
|
|
445
|
+
let max = min;
|
|
446
|
+
for (let index = 1; index < vertices.length; index += 1) {
|
|
447
|
+
const value = dotVec3(vertices[index], axis);
|
|
448
|
+
min = Math.min(min, value);
|
|
449
|
+
max = Math.max(max, value);
|
|
450
|
+
}
|
|
451
|
+
return { min, max };
|
|
452
|
+
}
|
|
453
|
+
function createEpaFace(vertices, indices) {
|
|
454
|
+
const a = vertices[indices[0]].point;
|
|
455
|
+
const b = vertices[indices[1]].point;
|
|
456
|
+
const c = vertices[indices[2]].point;
|
|
457
|
+
let normal = cross(subVec3(b, a), subVec3(c, a));
|
|
458
|
+
if (lengthVec3(normal) <= EPSILON)
|
|
459
|
+
return undefined;
|
|
460
|
+
normal = normalizeVec3(normal);
|
|
461
|
+
let distance = dotVec3(normal, a);
|
|
462
|
+
let orientedIndices = indices;
|
|
463
|
+
if (distance < 0) {
|
|
464
|
+
normal = scaleVec3(normal, -1);
|
|
465
|
+
distance = -distance;
|
|
466
|
+
orientedIndices = [indices[0], indices[2], indices[1]];
|
|
467
|
+
}
|
|
468
|
+
return { indices: orientedIndices, normal, distance };
|
|
469
|
+
}
|
|
470
|
+
function boundaryEdges(faces) {
|
|
471
|
+
const edges = [];
|
|
472
|
+
for (const face of faces) {
|
|
473
|
+
for (const edge of [
|
|
474
|
+
[face.indices[0], face.indices[1]],
|
|
475
|
+
[face.indices[1], face.indices[2]],
|
|
476
|
+
[face.indices[2], face.indices[0]]
|
|
477
|
+
]) {
|
|
478
|
+
const reverse = edges.findIndex((candidate) => candidate[0] === edge[1] && candidate[1] === edge[0]);
|
|
479
|
+
if (reverse >= 0)
|
|
480
|
+
edges.splice(reverse, 1);
|
|
481
|
+
else
|
|
482
|
+
edges.push(edge);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return edges;
|
|
486
|
+
}
|
|
487
|
+
function worldPoint(local, body) {
|
|
488
|
+
return addVec3(body.position, rotateVec3ByQuat(local, body.rotation));
|
|
489
|
+
}
|
|
490
|
+
function centroid(points) {
|
|
491
|
+
const sum = points.reduce((value, point) => addVec3(value, point), [0, 0, 0]);
|
|
492
|
+
return scaleVec3(sum, 1 / points.length);
|
|
493
|
+
}
|
|
494
|
+
function cross(a, b) {
|
|
495
|
+
return [
|
|
496
|
+
a[1] * b[2] - a[2] * b[1],
|
|
497
|
+
a[2] * b[0] - a[0] * b[2],
|
|
498
|
+
a[0] * b[1] - a[1] * b[0]
|
|
499
|
+
];
|
|
500
|
+
}
|
|
501
|
+
function tripleCross(a, b, c) {
|
|
502
|
+
const result = cross(cross(a, b), c);
|
|
503
|
+
return lengthVec3(result) > EPSILON ? result : perpendicular(c);
|
|
504
|
+
}
|
|
505
|
+
function perpendicular(value) {
|
|
506
|
+
const reference = Math.abs(value[0]) < Math.abs(value[1]) ? [1, 0, 0] : [0, 1, 0];
|
|
507
|
+
return normalizeOr(cross(value, reference), [0, 0, 1]);
|
|
508
|
+
}
|
|
509
|
+
function outwardFaceNormal(a, b, c, opposite) {
|
|
510
|
+
let normal = normalizeOr(cross(subVec3(b, a), subVec3(c, a)), [1, 0, 0]);
|
|
511
|
+
if (dotVec3(normal, subVec3(opposite, a)) > 0)
|
|
512
|
+
normal = scaleVec3(normal, -1);
|
|
513
|
+
return normal;
|
|
514
|
+
}
|
|
515
|
+
function orientToward(normal, direction) {
|
|
516
|
+
return dotVec3(normal, direction) < 0 ? scaleVec3(normal, -1) : normal;
|
|
517
|
+
}
|
|
518
|
+
function normalizeOr(value, fallback) {
|
|
519
|
+
return lengthVec3(value) > EPSILON ? normalizeVec3(value) : fallback;
|
|
520
|
+
}
|
|
521
|
+
function closestPointOnTriangle(point, a, b, c) {
|
|
522
|
+
const ab = subVec3(b, a);
|
|
523
|
+
const ac = subVec3(c, a);
|
|
524
|
+
const ap = subVec3(point, a);
|
|
525
|
+
const d1 = dotVec3(ab, ap);
|
|
526
|
+
const d2 = dotVec3(ac, ap);
|
|
527
|
+
if (d1 <= 0 && d2 <= 0)
|
|
528
|
+
return a;
|
|
529
|
+
const bp = subVec3(point, b);
|
|
530
|
+
const d3 = dotVec3(ab, bp);
|
|
531
|
+
const d4 = dotVec3(ac, bp);
|
|
532
|
+
if (d3 >= 0 && d4 <= d3)
|
|
533
|
+
return b;
|
|
534
|
+
const vc = d1 * d4 - d3 * d2;
|
|
535
|
+
if (vc <= 0 && d1 >= 0 && d3 <= 0)
|
|
536
|
+
return addVec3(a, scaleVec3(ab, d1 / (d1 - d3)));
|
|
537
|
+
const cp = subVec3(point, c);
|
|
538
|
+
const d5 = dotVec3(ab, cp);
|
|
539
|
+
const d6 = dotVec3(ac, cp);
|
|
540
|
+
if (d6 >= 0 && d5 <= d6)
|
|
541
|
+
return c;
|
|
542
|
+
const vb = d5 * d2 - d1 * d6;
|
|
543
|
+
if (vb <= 0 && d2 >= 0 && d6 <= 0)
|
|
544
|
+
return addVec3(a, scaleVec3(ac, d2 / (d2 - d6)));
|
|
545
|
+
const va = d3 * d6 - d5 * d4;
|
|
546
|
+
if (va <= 0 && d4 - d3 >= 0 && d5 - d6 >= 0)
|
|
547
|
+
return addVec3(b, scaleVec3(subVec3(c, b), (d4 - d3) / ((d4 - d3) + (d5 - d6))));
|
|
548
|
+
const denominator = 1 / (va + vb + vc);
|
|
549
|
+
const v = vb * denominator;
|
|
550
|
+
const w = vc * denominator;
|
|
551
|
+
return addVec3(a, addVec3(scaleVec3(ab, v), scaleVec3(ac, w)));
|
|
552
|
+
}
|
|
553
|
+
function closestPointOnSegment(point, start, end) {
|
|
554
|
+
const direction = subVec3(end, start);
|
|
555
|
+
const denominator = dotVec3(direction, direction);
|
|
556
|
+
if (denominator <= EPSILON)
|
|
557
|
+
return start;
|
|
558
|
+
const t = Math.max(0, Math.min(1, dotVec3(subVec3(point, start), direction) / denominator));
|
|
559
|
+
return addVec3(start, scaleVec3(direction, t));
|
|
560
|
+
}
|
|
561
|
+
function squaredDistance(a, b) {
|
|
562
|
+
const delta = subVec3(a, b);
|
|
563
|
+
return dotVec3(delta, delta);
|
|
564
|
+
}
|
|
565
|
+
//# sourceMappingURL=NarrowPhase.js.map
|