@perplexdotgg/bounce 1.0.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.
Files changed (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/package.json +32 -0
  4. package/src/builders/ConvexHullBuilder.ts +437 -0
  5. package/src/builders/ConvexHullBuilder2d.ts +344 -0
  6. package/src/builders/ConvexHullBuilder3d.ts +1689 -0
  7. package/src/builders/HeightMapBuilder.ts +414 -0
  8. package/src/builders/TriangleMeshBuilder.ts +92 -0
  9. package/src/collision/CastShapesModule.ts +184 -0
  10. package/src/collision/CollideShapesModule.ts +152 -0
  11. package/src/collision/HeightMapCaster.ts +38 -0
  12. package/src/collision/HeightMapCollider.ts +33 -0
  13. package/src/collision/TriangleCaster.ts +249 -0
  14. package/src/collision/TriangleCollider.ts +308 -0
  15. package/src/collision/TriangleCollider2.ts +379 -0
  16. package/src/collision/activeEdge.ts +146 -0
  17. package/src/collision/cast/cast.ts +139 -0
  18. package/src/collision/cast/castCompoundVsCompound.ts +59 -0
  19. package/src/collision/cast/castCompoundVsConvex.ts +116 -0
  20. package/src/collision/cast/castConvexVsCompound.ts +123 -0
  21. package/src/collision/cast/castConvexVsConvex.ts +213 -0
  22. package/src/collision/cast/castConvexVsHeightMap.ts +73 -0
  23. package/src/collision/cast/castConvexVsTriangleMesh.ts +56 -0
  24. package/src/collision/cast/castRayVsCompound.ts +44 -0
  25. package/src/collision/cast/castRayVsConvex.ts +45 -0
  26. package/src/collision/cast/castRayVsHeightMap.ts +58 -0
  27. package/src/collision/cast/castRayVsTriangleMesh.ts +58 -0
  28. package/src/collision/closestPoints/closestPoints.ts +23 -0
  29. package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +32 -0
  30. package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +81 -0
  31. package/src/collision/closestPoints/computeClosestPointOnLine.ts +30 -0
  32. package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +96 -0
  33. package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +195 -0
  34. package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +25 -0
  35. package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +72 -0
  36. package/src/collision/collide/collide.ts +146 -0
  37. package/src/collision/collide/collideCompoundVsCompound.ts +60 -0
  38. package/src/collision/collide/collideCompoundVsConvex.ts +59 -0
  39. package/src/collision/collide/collideCompoundVsHeightMap.ts +73 -0
  40. package/src/collision/collide/collideCompoundVsTriangleMesh.ts +56 -0
  41. package/src/collision/collide/collideConvexVsCompound.ts +57 -0
  42. package/src/collision/collide/collideConvexVsConvex.ts +225 -0
  43. package/src/collision/collide/collideConvexVsConvexImp.ts +236 -0
  44. package/src/collision/collide/collideConvexVsHeightMap.ts +53 -0
  45. package/src/collision/collide/collideConvexVsTriangleMesh.ts +58 -0
  46. package/src/collision/collide/collideHeightMapVsCompound.ts +69 -0
  47. package/src/collision/collide/collideHeightMapVsConvex.ts +53 -0
  48. package/src/collision/collide/collideSphereVsSphere.ts +81 -0
  49. package/src/collision/collide/collideTriangleMeshVsCompound.ts +58 -0
  50. package/src/collision/collide/collideTriangleMeshVsConvex.ts +58 -0
  51. package/src/collision/epa/EpaConvexHullBuilder.ts +397 -0
  52. package/src/collision/epa/StaticArray.ts +154 -0
  53. package/src/collision/epa/TriangleFactory.ts +32 -0
  54. package/src/collision/epa/arrays.ts +99 -0
  55. package/src/collision/epa/binaryHeap.ts +82 -0
  56. package/src/collision/epa/structs.ts +227 -0
  57. package/src/collision/gjk/GjkModule.ts +864 -0
  58. package/src/collision/gjk/PenetrationDepthModule.ts +493 -0
  59. package/src/collision/gjk/SupportPoints.ts +50 -0
  60. package/src/collision/imp/MinkowskiDifference.ts +36 -0
  61. package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +40 -0
  62. package/src/collision/imp/finalizeImpResult.ts +69 -0
  63. package/src/collision/imp/findContactImp.ts +196 -0
  64. package/src/collision/imp/imp.ts +28 -0
  65. package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +207 -0
  66. package/src/collision/mpr/findPortal.ts +152 -0
  67. package/src/collision/mpr/mpr.ts +29 -0
  68. package/src/collision/mpr/updatePortal.ts +52 -0
  69. package/src/constraints/BaseConstraint.ts +50 -0
  70. package/src/constraints/ConstraintOptions.ts +22 -0
  71. package/src/constraints/ConstraintSolver.ts +119 -0
  72. package/src/constraints/DistanceConstraint.ts +229 -0
  73. package/src/constraints/FixedConstraint.ts +203 -0
  74. package/src/constraints/HingeConstraint.ts +460 -0
  75. package/src/constraints/PointConstraint.ts +108 -0
  76. package/src/constraints/components/AngleComponent.ts +226 -0
  77. package/src/constraints/components/AxisComponent.ts +263 -0
  78. package/src/constraints/components/HingeComponent.ts +215 -0
  79. package/src/constraints/components/Motor.ts +36 -0
  80. package/src/constraints/components/PointConstraintComponent.ts +179 -0
  81. package/src/constraints/components/RotationEulerComponent.ts +139 -0
  82. package/src/constraints/components/Spring.ts +30 -0
  83. package/src/constraints/components/SpringComponent.ts +71 -0
  84. package/src/constraints/types.ts +6 -0
  85. package/src/helpers.ts +147 -0
  86. package/src/index.ts +50 -0
  87. package/src/math/BasicTransform.ts +19 -0
  88. package/src/math/NumberValue.ts +13 -0
  89. package/src/math/isometry.ts +64 -0
  90. package/src/math/mat3.ts +529 -0
  91. package/src/math/mat4.ts +588 -0
  92. package/src/math/quat.ts +193 -0
  93. package/src/math/scalar.ts +81 -0
  94. package/src/math/tensor.ts +17 -0
  95. package/src/math/vec3.ts +589 -0
  96. package/src/math/vec4.ts +10 -0
  97. package/src/physics/Body.ts +581 -0
  98. package/src/physics/CollisionFilter.ts +52 -0
  99. package/src/physics/SleepModule.ts +163 -0
  100. package/src/physics/broadphase/BodyPairsModule.ts +363 -0
  101. package/src/physics/broadphase/BvhModule.ts +237 -0
  102. package/src/physics/broadphase/BvhTree.ts +803 -0
  103. package/src/physics/broadphase/ConstraintPairsModule.ts +385 -0
  104. package/src/physics/broadphase/TriangleMeshBvhTree.ts +379 -0
  105. package/src/physics/manifold/ContactManifold.ts +227 -0
  106. package/src/physics/manifold/ContactManifoldModule.ts +623 -0
  107. package/src/physics/manifold/Face.ts +119 -0
  108. package/src/physics/manifold/ManifoldCache.ts +116 -0
  109. package/src/physics/manifold/clipping/clipPolyVsEdge.ts +131 -0
  110. package/src/physics/manifold/clipping/clipPolyVsPlane.ts +73 -0
  111. package/src/physics/manifold/clipping/clipPolyVsPoly.ts +72 -0
  112. package/src/physics/narrowphase/CollideBodiesModule.ts +755 -0
  113. package/src/physics/solver/ContactConstraintModule.ts +659 -0
  114. package/src/physics/solver/ManifoldConstraint.ts +420 -0
  115. package/src/physics/solver/estimateCollisionResponse.ts +146 -0
  116. package/src/shape/Aabb.ts +400 -0
  117. package/src/shape/Box.ts +231 -0
  118. package/src/shape/Capsule.ts +332 -0
  119. package/src/shape/CompoundShape.ts +288 -0
  120. package/src/shape/Convex.ts +130 -0
  121. package/src/shape/ConvexHull.ts +423 -0
  122. package/src/shape/Cylinder.ts +313 -0
  123. package/src/shape/HeightMap.ts +511 -0
  124. package/src/shape/Line.ts +14 -0
  125. package/src/shape/Plane.ts +116 -0
  126. package/src/shape/Ray.ts +81 -0
  127. package/src/shape/Segment.ts +25 -0
  128. package/src/shape/Shape.ts +77 -0
  129. package/src/shape/Sphere.ts +181 -0
  130. package/src/shape/TransformedShape.ts +51 -0
  131. package/src/shape/Triangle.ts +122 -0
  132. package/src/shape/TriangleMesh.ts +186 -0
  133. package/src/types.ts +1 -0
  134. package/src/world.ts +1335 -0
  135. package/tests/BodyPairsModule.test.ts +71 -0
  136. package/tests/BvhTree.test.ts +406 -0
  137. package/tests/test.md +642 -0
  138. package/tests/vec3.test.ts +12 -0
  139. package/tsconfig.json +20 -0
  140. package/vite.config.js +40 -0
@@ -0,0 +1,213 @@
1
+ import { Isometry } from "../../math/isometry";
2
+ import { Vec3 } from "../../math/vec3";
3
+ import { Body } from "../../physics/Body";
4
+ import { ConvexWithcomputeSupportShape, SupportMode } from "../../shape/Convex";
5
+ import { BackFaceMode } from "../collide/collide";
6
+ import { GjkCastShapeResult } from "../gjk/GjkModule";
7
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
8
+ import { CastCollector, CastResult, CastSettings } from "./cast";
9
+
10
+ const negatedOffset = /*@__PURE__*/ Vec3.create();
11
+ const offsetIsometryA = /*@__PURE__*/ Isometry.create();
12
+ const offsetIsometryB = /*@__PURE__*/ Isometry.create();
13
+ const inverseOffsetIsometryB = /*@__PURE__*/ Isometry.create();
14
+ const offsetIsometryAToB = /*@__PURE__*/ Isometry.create();
15
+ const displacementInB = /*@__PURE__*/ Vec3.create();
16
+
17
+ export function castConvexVsConvex(
18
+ penetrationDepthModule: PenetrationDepthModule,
19
+ ioCollector: CastCollector,
20
+ inShapeA: ConvexWithcomputeSupportShape,
21
+ inShapeB: ConvexWithcomputeSupportShape,
22
+ isometryA: Isometry,
23
+ isometryB: Isometry,
24
+ inScaleA: number,
25
+ inScaleB: number,
26
+ displacement: Vec3,
27
+ offset: Vec3,
28
+ inSettings: CastSettings,
29
+ preferredNormalBDirection?: Vec3,
30
+ bodyA: Body | null = null,
31
+ bodyB: Body | null = null
32
+ ): void {
33
+ // translate A and B by the offset, for example to move them both to origin
34
+ negatedOffset.negateVector(offset);
35
+ offsetIsometryA.matrix.postTranslatedMatrix(isometryA.matrix, negatedOffset);
36
+ offsetIsometryB.matrix.postTranslatedMatrix(isometryB.matrix, negatedOffset);
37
+
38
+ // get a transformA in the space of B
39
+ inverseOffsetIsometryB.matrix.invertMatrix(offsetIsometryB.matrix);
40
+ offsetIsometryAToB.matrix.multiplyMatrices(inverseOffsetIsometryB.matrix, offsetIsometryA.matrix);
41
+
42
+ // get displacement in the space of B
43
+ inverseOffsetIsometryB.matrix.multiply3x3(displacementInB, displacement);
44
+
45
+ castConvexVsConvexLocal(
46
+ penetrationDepthModule,
47
+ ioCollector,
48
+ inShapeA,
49
+ inShapeB,
50
+ offsetIsometryAToB,
51
+ offsetIsometryB,
52
+ inScaleA,
53
+ inScaleB,
54
+ displacementInB,
55
+ inSettings,
56
+ preferredNormalBDirection,
57
+ bodyA,
58
+ bodyB
59
+ );
60
+ }
61
+
62
+ const contact_normal_world = /*@__PURE__*/ Vec3.create();
63
+ const epaResult = /*@__PURE__*/ GjkCastShapeResult.create();
64
+ const result = /*@__PURE__*/ CastResult.create();
65
+
66
+ // cast in B space, return in world space
67
+ export function castConvexVsConvexLocal(
68
+ penetrationDepthModule: PenetrationDepthModule,
69
+ ioCollector: CastCollector,
70
+ inShapeA: ConvexWithcomputeSupportShape,
71
+ inShapeB: ConvexWithcomputeSupportShape,
72
+ isometryAToB: Isometry,
73
+ isometryB: Isometry,
74
+ inScaleA: number,
75
+ inScaleB: number,
76
+ displacementInB: Vec3,
77
+ inShapeCastSettings: CastSettings,
78
+ preferredNormalBDirection?: Vec3,
79
+ bodyA: Body | null = null,
80
+ bodyB: Body | null = null,
81
+ subShapeIdA: number = 0,
82
+ subShapeIdB: number = 0
83
+ ): void {
84
+ // Only supported for convex shapes
85
+ const cast_shape = inShapeA;
86
+
87
+ const shape = inShapeB;
88
+
89
+ const support_mode = inShapeCastSettings.useShrunkenShapeAndConvexRadius
90
+ ? SupportMode.ExcludeConvexRadius
91
+ : SupportMode.IncludeConvexRadius;
92
+
93
+ // Create support function for shape to cast
94
+ const cast_support = cast_shape.computeSupportShape(support_mode, inScaleA);
95
+
96
+ // Create support function for target shape
97
+ // SOURCE
98
+ const target_support = shape.computeSupportShape(support_mode, inScaleB);
99
+ const shapeB = target_support;
100
+ // SOURCE
101
+ // CHANGE
102
+ // const target_support = shape.computeSupportShape(support_mode, inScale);
103
+ // this.transformed_b.set(inCenterOfMassTransform2, target_support);
104
+ // const shapeB = this.transformed_b;
105
+ // CHANGE
106
+
107
+ // debugger;
108
+
109
+ // Do a raycast against the result
110
+ epaResult.lambda = ioCollector.getEarlyOutFraction();
111
+ penetrationDepthModule.castShape(
112
+ epaResult,
113
+ isometryAToB,
114
+ displacementInB,
115
+ inShapeCastSettings.collisionTolerance,
116
+ inShapeCastSettings.penetrationTolerance,
117
+ cast_support,
118
+ shapeB,
119
+ cast_support.getConvexRadius(),
120
+ target_support.getConvexRadius(),
121
+ inShapeCastSettings.returnDeepestPoint
122
+ );
123
+
124
+ const condition =
125
+ epaResult.isHitFound === true &&
126
+ (inShapeCastSettings.backFaceModeConvex === BackFaceMode.CollideWithBackFaces ||
127
+ epaResult.separatingAxis.dot(displacementInB) > 0);
128
+ // const condition = epaResult.isHitFound === true;
129
+ if (condition) {
130
+ // SOURCE
131
+ // Convert to world space
132
+ epaResult.pointA.transformByMat4(isometryB.matrix);
133
+ epaResult.pointB.transformByMat4(isometryB.matrix);
134
+ isometryB.matrix.multiply3x3(contact_normal_world, epaResult.separatingAxis);
135
+ // SOURCE
136
+ // CHANGE
137
+ //
138
+ // CHANGE
139
+
140
+ // @ts-ignore
141
+ result.bodyA = bodyA;
142
+ // @ts-ignore
143
+ result.bodyB = bodyB;
144
+ result.subShapeIdA = subShapeIdA;
145
+ result.subShapeIdB = subShapeIdB;
146
+ result.fraction = epaResult.lambda;
147
+ result.isBackFaceHit = false;
148
+ result.contactPointA.copy(epaResult.pointA);
149
+ result.contactPointB.copy(epaResult.pointB);
150
+ // result.bodyId2 = ioCollector.bodyId2;
151
+
152
+ // SOURCE
153
+ result.normalA.copy(contact_normal_world);
154
+ result.normalB.negateVector(contact_normal_world);
155
+ // SOURCE
156
+ // CHANGE
157
+ // result.penetrationAxis.copy(epaResult.separatingAxis);
158
+ // CHANGE
159
+
160
+ result.penetration = epaResult.pointA.distance(epaResult.pointB);
161
+
162
+ // Early out if this hit is deeper than the collector's early out value
163
+ if (epaResult.lambda === 0 && -result.penetration >= ioCollector.getEarlyOutFraction()) {
164
+ ioCollector.addMiss();
165
+ return;
166
+ }
167
+
168
+ // // TODO: Gather faces
169
+ // if (inShapeCastSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces)
170
+ // {
171
+ // // Get supporting face of shape 1
172
+ // Mat44 transform_1_to_2 = inShapeCast.mCenterOfMassStart;
173
+ // transform_1_to_2.SetTranslation(transform_1_to_2.GetTranslation() + fraction * inShapeCast.mDirection);
174
+ // cast_shape->computeSupportingFace(SubShapeID(), transform_1_to_2.Multiply3x3Transposed(-contact_normal), inShapeCast.mScale, inCenterOfMassTransform2 * transform_1_to_2, result.mShape1Face);
175
+
176
+ // // Get supporting face of shape 2
177
+ // shape->computeSupportingFace(SubShapeID(), contact_normal, inScale, inCenterOfMassTransform2, result.mShape2Face);
178
+ // }
179
+
180
+ // adjust normal if preferred normal B direction is provided
181
+ // if (preferredNormalBDirection !== undefined) {
182
+ // // compare normalB to preferredNormalBDirection component-wise
183
+ // const difference = Vec3.global(this.world, "CastModule.castConvexVsConvexLocal.difference");
184
+ // vec3.sub(difference, result.normalB, preferredNormalBDirection);
185
+ // if (difference.isNearZero() === false) {
186
+ // result.normalB.copy(preferredNormalBDirection);
187
+ // vec3.negate(result.normalA, preferredNormalBDirection);
188
+ // }
189
+ // }
190
+
191
+ // // exit if hit is shallower than the collector's current hit
192
+ // if (result.fraction >= ioCollector.getEarlyOutFraction()) {
193
+ // ioCollector.addMiss();
194
+ // return;
195
+ // }
196
+
197
+ // // flip normals
198
+ // vec3.negate(result.normalA, result.normalA);
199
+ // vec3.negate(result.normalB, result.normalB);
200
+
201
+ // always align the normals with the preferred normal direction
202
+ if (preferredNormalBDirection !== undefined) {
203
+ result.normalB.copy(preferredNormalBDirection);
204
+ result.normalA.negateVector(preferredNormalBDirection);
205
+ }
206
+
207
+ ioCollector.earlyOutFraction = result.fraction;
208
+
209
+ ioCollector.addHit(result);
210
+ } else {
211
+ ioCollector.addMiss();
212
+ }
213
+ }
@@ -0,0 +1,73 @@
1
+ import { Isometry } from "../../math/isometry";
2
+ import { Mat3 } from "../../math/mat3";
3
+ import { Vec3 } from "../../math/vec3";
4
+ import { Body } from "../../physics/Body";
5
+ import { Aabb } from "../../shape/Aabb";
6
+ import { HeightMap } from "../../shape/HeightMap";
7
+ import { Ray } from "../../shape/Ray";
8
+ import { ConvexShape } from "../../shape/Shape";
9
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
10
+ import { HeightMapCaster } from "../HeightMapCaster";
11
+ import { TriangleCaster } from "../TriangleCaster";
12
+ import { CastCollector, CastSettings } from "./cast";
13
+
14
+ const isometryWorldToB = /*@__PURE__*/ Isometry.create();
15
+ const isometryAToB = /*@__PURE__*/ Isometry.create();
16
+ const shapeABoundsInBSpace = /*@__PURE__*/ Aabb.create();
17
+ const displacementAInBSpace = /*@__PURE__*/ Vec3.create();
18
+ const rotateWorldToB = /*@__PURE__*/ Mat3.create();
19
+ const ray = /*@__PURE__*/ Ray.create();
20
+ const halfExtents = /*@__PURE__*/ Vec3.create();
21
+ const heightMapCaster = /*@__PURE__*/ new HeightMapCaster(new TriangleCaster());
22
+
23
+ export function castConvexVsHeightMap(
24
+ penetrationDepthModule: PenetrationDepthModule,
25
+ ioCollector: CastCollector,
26
+ inShapeA: ConvexShape,
27
+ inShapeB: HeightMap,
28
+ isometryA: Isometry,
29
+ isometryB: Isometry,
30
+ inScaleA: number,
31
+ inScaleB: number,
32
+ displacement: Vec3,
33
+ offset: Vec3,
34
+ inSettings: CastSettings,
35
+ preferredNormalBDirection?: Vec3,
36
+ bodyA: Body | null = null,
37
+ bodyB: Body | null = null
38
+ ): void {
39
+ heightMapCaster.triangleCaster.initialize(
40
+ inSettings,
41
+ ioCollector,
42
+ inShapeA,
43
+ isometryA,
44
+ isometryB,
45
+ displacement,
46
+ offset
47
+ );
48
+
49
+ isometryWorldToB.matrix.invertMatrix(isometryB.matrix);
50
+
51
+ // a to world -> world to b
52
+ isometryAToB.matrix.multiplyMatrices(isometryA.matrix, isometryWorldToB.matrix);
53
+
54
+ shapeABoundsInBSpace.copy(inShapeA.computedAabb);
55
+ shapeABoundsInBSpace.transform(isometryAToB);
56
+
57
+ rotateWorldToB.fromMat4(isometryB.matrix);
58
+ displacementAInBSpace.transformVectorFromMat3(displacement, rotateWorldToB);
59
+
60
+ // aabb cast is done by the following method
61
+ // 1. shrink the shape aabb by its own extents down to a point
62
+ // 2. expand the block aabb by the extents of the shape aabb
63
+ // 3. cast the point by the displacement against the expanded block aabb (raycast vs aabb test)
64
+
65
+ shapeABoundsInBSpace.computeCentroid(ray.origin);
66
+ ray.direction.normalizeVector(displacementAInBSpace);
67
+ ray.length = displacementAInBSpace.length();
68
+
69
+ shapeABoundsInBSpace.computeHalfExtents(halfExtents);
70
+
71
+ heightMapCaster.initialize(halfExtents, ray, bodyA, bodyB);
72
+ inShapeB.walkHeightMap(heightMapCaster);
73
+ }
@@ -0,0 +1,56 @@
1
+ import { Isometry } from "../../math/isometry";
2
+ import { Vec3 } from "../../math/vec3";
3
+ import { Body } from "../../physics/Body";
4
+ import { Aabb } from "../../shape/Aabb";
5
+ import { ConvexShape } from "../../shape/Shape";
6
+ import { Triangle } from "../../shape/Triangle";
7
+ import { TriangleMesh } from "../../shape/TriangleMesh";
8
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
9
+ import { TriangleCaster } from "../TriangleCaster";
10
+ import { CastCollector, CastSettings } from "./cast";
11
+
12
+ const isometryWorldToB = /*@__PURE__*/ Isometry.create();
13
+ const isometryAToB = /*@__PURE__*/ Isometry.create();
14
+ const boundsA = /*@__PURE__*/ Aabb.create();
15
+ const transformedDisplacement = /*@__PURE__*/ Vec3.create();
16
+ const triangleCaster = /*@__PURE__*/ new TriangleCaster();
17
+
18
+ function onHit(triangle: Triangle) {
19
+ triangleCaster.cast(triangle, triangle.activeEdges, triangle.subShapeId, triangleCaster.bodyA, triangleCaster.bodyB);
20
+ return false;
21
+ }
22
+
23
+ export function castConvexVsTriangleMesh(
24
+ penetrationDepthModule: PenetrationDepthModule,
25
+ ioCollector: CastCollector,
26
+ inShapeA: ConvexShape,
27
+ inShapeB: TriangleMesh,
28
+ isometryA: Isometry,
29
+ isometryB: Isometry,
30
+ inScaleA: number,
31
+ inScaleB: number,
32
+ displacement: Vec3,
33
+ offset: Vec3,
34
+ inSettings: CastSettings,
35
+ preferredNormalBDirection?: Vec3,
36
+ bodyA: Body | null = null,
37
+ bodyB: Body | null = null
38
+ ): void {
39
+ triangleCaster.initialize(
40
+ inSettings,
41
+ ioCollector,
42
+ inShapeA,
43
+ isometryA,
44
+ isometryB,
45
+ displacement,
46
+ offset,
47
+ bodyA,
48
+ bodyB
49
+ );
50
+ isometryWorldToB.matrix.invertMatrix(isometryB.matrix);
51
+ isometryAToB.matrix.multiplyMatrices(isometryWorldToB.matrix, isometryA.matrix);
52
+ boundsA.copy(inShapeA.computedAabb);
53
+ boundsA.transform(isometryAToB);
54
+ isometryWorldToB.matrix.multiply3x3(transformedDisplacement, displacement);
55
+ inShapeB.bvh!.castAabb(onHit, boundsA, transformedDisplacement);
56
+ }
@@ -0,0 +1,44 @@
1
+ import { BasicTransform, ConvexShape } from "../..";
2
+ import { Isometry } from "../../math/isometry";
3
+ import { Vec3 } from "../../math/vec3";
4
+ import { Body } from "../../physics/Body";
5
+ import { CompoundShape } from "../../shape/CompoundShape";
6
+ import { ConvexWithcomputeSupportShape, SupportMode } from "../../shape/Convex";
7
+ import { Ray } from "../../shape/Ray";
8
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
9
+ import { CastCollector, CastResult, RayCastSettings } from "./cast";
10
+ import { castRayVsConvex } from "./castRayVsConvex";
11
+
12
+ export function castRayVsCompound(
13
+ penetrationDepthModule: PenetrationDepthModule,
14
+ ioCollector: CastCollector,
15
+ inRay: Ray,
16
+ inShapeB: CompoundShape,
17
+ isometryB: Isometry,
18
+ inScaleB: number,
19
+ offset: Vec3,
20
+ inSettings: RayCastSettings,
21
+ bodyB: Body | null = null
22
+ ) {
23
+ for (const shapeObj of inShapeB.shapes) {
24
+ const shape = shapeObj.shape as ConvexShape;
25
+ const transform = shapeObj.transform as BasicTransform;
26
+
27
+ transformSubShapeBToB.fromRotationAndTranslation(transform.rotation, transform.position);
28
+ transformSubShapeBToWorld.matrix.multiplyMatrices(isometryB.matrix, transformSubShapeBToB.matrix);
29
+ castRayVsConvex(
30
+ penetrationDepthModule,
31
+ ioCollector,
32
+ inRay,
33
+ shape,
34
+ transformSubShapeBToWorld,
35
+ inScaleB,
36
+ offset,
37
+ inSettings,
38
+ bodyB
39
+ );
40
+ }
41
+ }
42
+
43
+ const transformSubShapeBToB = /*@__PURE__*/ Isometry.create();
44
+ const transformSubShapeBToWorld = /*@__PURE__*/ Isometry.create();
@@ -0,0 +1,45 @@
1
+ import { Isometry } from "../../math/isometry";
2
+ import { Vec3 } from "../../math/vec3";
3
+ import { Body } from "../../physics/Body";
4
+ import { ConvexWithcomputeSupportShape, SupportMode } from "../../shape/Convex";
5
+ import { Ray } from "../../shape/Ray";
6
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
7
+ import { CastCollector, CastResult, RayCastSettings } from "./cast";
8
+
9
+ export function castRayVsConvex(
10
+ penetrationDepthModule: PenetrationDepthModule,
11
+ ioCollector: CastCollector,
12
+ inRay: Ray,
13
+ inShapeB: ConvexWithcomputeSupportShape,
14
+ isometryB: Isometry,
15
+ inScaleB: number,
16
+ offset: Vec3,
17
+ inSettings: RayCastSettings,
18
+ bodyB: Body | null = null
19
+ ) {
20
+ const convexB = inShapeB.computeSupportShape(SupportMode.IncludeConvexRadius, 1);
21
+ raycast.fraction = ioCollector.getEarlyOutFraction();
22
+ worldToB.matrix.invertMatrix(isometryB.matrix);
23
+ transformedRay.copy(inRay).transform(worldToB);
24
+ transformedRay.direction.scale(transformedRay.length);
25
+ const hitFound = penetrationDepthModule.gjkModule.castRay(
26
+ transformedRay.origin,
27
+ transformedRay.direction,
28
+ 1e-3,
29
+ convexB,
30
+ raycast
31
+ );
32
+ if (hitFound) {
33
+ result.hasContact = true;
34
+ result.bodyB = bodyB;
35
+ result.fraction = raycast.fraction;
36
+ ioCollector.addHit(result);
37
+ } else {
38
+ ioCollector.addMiss();
39
+ }
40
+ }
41
+
42
+ const result = /*@__PURE__*/ CastResult.create();
43
+ const raycast = { fraction: 0 };
44
+ const transformedRay = /*@__PURE__*/ Ray.create();
45
+ const worldToB = /*@__PURE__*/ Isometry.create();
@@ -0,0 +1,58 @@
1
+ import { Isometry } from "../../math/isometry";
2
+ import { Vec3 } from "../../math/vec3";
3
+ import { Body } from "../../physics/Body";
4
+ import { HeightMap } from "../../shape/HeightMap";
5
+ import { Ray } from "../../shape/Ray";
6
+ import { Triangle } from "../../shape/Triangle";
7
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
8
+ import { CastCollector, CastResult, RayCastSettings } from "./cast";
9
+
10
+ let collector: CastCollector;
11
+ let ray: Ray;
12
+ let body: Body | null;
13
+
14
+ function onHit(triangle: Triangle): boolean {
15
+ result.reset();
16
+ result.hasContact = true;
17
+
18
+ raycasterResult.fraction = 1.0;
19
+ raycasterResult.hit = false;
20
+ ray.intersectsTriangle(raycasterResult, triangle);
21
+
22
+ if (!raycasterResult.hit || raycasterResult.fraction >= collector.getEarlyOutFraction()) {
23
+ collector.addMiss();
24
+ return false;
25
+ }
26
+
27
+ result.hasContact = true;
28
+ result.bodyB = body;
29
+ result.fraction = raycasterResult.fraction;
30
+ collector.earlyOutFraction = raycasterResult.fraction;
31
+ collector.addHit(result);
32
+ return false;
33
+ }
34
+
35
+ export function castRayVsHeightMap(
36
+ penetrationDepthModule: PenetrationDepthModule,
37
+ ioCollector: CastCollector,
38
+ inRay: Ray,
39
+ inShapeB: HeightMap,
40
+ isometryB: Isometry,
41
+ inScaleB: number,
42
+ offset: Vec3,
43
+ inSettings: RayCastSettings,
44
+ bodyB: Body | null = null
45
+ ) {
46
+ ioCollector.reset();
47
+ isometryWorldToB.matrix.invertMatrix(isometryB.matrix);
48
+ transformedRay.copy(inRay).transform(isometryWorldToB);
49
+ collector = ioCollector;
50
+ ray = transformedRay;
51
+ body = bodyB;
52
+ inShapeB.castRay(onHit, transformedRay);
53
+ }
54
+
55
+ const result = /*@__PURE__*/ CastResult.create();
56
+ const raycasterResult = { fraction: 1.0, hit: false };
57
+ const isometryWorldToB = /*@__PURE__*/ Isometry.create();
58
+ const transformedRay = /*@__PURE__*/ Ray.create();
@@ -0,0 +1,58 @@
1
+ import { Isometry } from "../../math/isometry";
2
+ import { Vec3 } from "../../math/vec3";
3
+ import { Body } from "../../physics/Body";
4
+ import { Ray } from "../../shape/Ray";
5
+ import { Triangle } from "../../shape/Triangle";
6
+ import { TriangleMesh } from "../../shape/TriangleMesh";
7
+ import { PenetrationDepthModule } from "../gjk/PenetrationDepthModule";
8
+ import { CastCollector, CastResult, RayCastSettings } from "./cast";
9
+
10
+ let collector: CastCollector;
11
+ let ray: Ray;
12
+ let body: Body | null;
13
+
14
+ function onHit(triangle: Triangle): boolean {
15
+ result.reset();
16
+ result.hasContact = true;
17
+
18
+ raycasterResult.fraction = 1.0;
19
+ raycasterResult.hit = false;
20
+ ray.intersectsTriangle(raycasterResult, triangle);
21
+
22
+ if (!raycasterResult.hit || raycasterResult.fraction >= collector.getEarlyOutFraction()) {
23
+ collector.addMiss();
24
+ return false;
25
+ }
26
+
27
+ result.hasContact = true;
28
+ result.bodyB = body;
29
+ result.fraction = raycasterResult.fraction;
30
+ collector.earlyOutFraction = raycasterResult.fraction;
31
+ collector.addHit(result);
32
+ return false;
33
+ }
34
+
35
+ export function castRayVsTriangleMesh(
36
+ penetrationDepthModule: PenetrationDepthModule,
37
+ ioCollector: CastCollector,
38
+ inRay: Ray,
39
+ inShapeB: TriangleMesh,
40
+ isometryB: Isometry,
41
+ inScaleB: number,
42
+ offset: Vec3,
43
+ inSettings: RayCastSettings,
44
+ bodyB: Body | null = null
45
+ ) {
46
+ ioCollector.reset();
47
+ isometryWorldToB.matrix.invertMatrix(isometryB.matrix);
48
+ transformedRay.copy(inRay).transform(isometryWorldToB);
49
+ collector = ioCollector;
50
+ ray = transformedRay;
51
+ body = bodyB;
52
+ inShapeB.bvh!.castRay(onHit, transformedRay);
53
+ }
54
+
55
+ const result = /*@__PURE__*/ CastResult.create();
56
+ const raycasterResult = { fraction: 1.0, hit: false };
57
+ const isometryWorldToB = /*@__PURE__*/ Isometry.create();
58
+ const transformedRay = /*@__PURE__*/ Ray.create();
@@ -0,0 +1,23 @@
1
+ import { BooleanType, createClass, MonomorphType, NumberType, PropertyDefinitionMap } from "monomorph";
2
+ import { Vec3 } from "../../math/vec3";
3
+
4
+ const closestPointResultProps = {
5
+ point: MonomorphType(Vec3),
6
+ pointSet: NumberType(0),
7
+ } as const satisfies PropertyDefinitionMap;
8
+
9
+ export class ClosestPointResult extends createClass<ClosestPointResult, typeof closestPointResultProps>(
10
+ closestPointResultProps
11
+ ) {}
12
+
13
+ const barycentricCoordinatesResultProps = {
14
+ u: NumberType(0),
15
+ v: NumberType(0),
16
+ w: NumberType(0),
17
+ isValid: BooleanType(false),
18
+ } as const satisfies PropertyDefinitionMap;
19
+
20
+ export class BarycentricCoordinatesResult extends createClass<
21
+ BarycentricCoordinatesResult,
22
+ typeof barycentricCoordinatesResultProps
23
+ >(barycentricCoordinatesResultProps) {}
@@ -0,0 +1,32 @@
1
+ import { Vec3 } from "../../math/vec3";
2
+ import { BarycentricCoordinatesResult } from "./closestPoints";
3
+
4
+ const ab = /*@__PURE__*/ Vec3.create();
5
+
6
+ export function computeBarycentricCoordinates2d(
7
+ outBarycentric: BarycentricCoordinatesResult,
8
+ a: Vec3,
9
+ b: Vec3,
10
+ squaredTolerance: number = 1e-10
11
+ ) {
12
+ ab.subtractVectors(b, a);
13
+ const denominator = ab.squaredLength();
14
+ if (denominator < squaredTolerance) {
15
+ // Degenerate line segment, fallback to points
16
+ if (a.squaredLength() < b.squaredLength()) {
17
+ // A closest
18
+ outBarycentric.u = 1.0;
19
+ outBarycentric.v = 0.0;
20
+ } else {
21
+ // B closest
22
+ outBarycentric.u = 0.0;
23
+ outBarycentric.v = 1.0;
24
+ }
25
+ outBarycentric.isValid = false;
26
+ return;
27
+ } else {
28
+ outBarycentric.v = -a.dot(ab) / denominator;
29
+ outBarycentric.u = 1.0 - outBarycentric.v;
30
+ }
31
+ outBarycentric.isValid = true;
32
+ }
@@ -0,0 +1,81 @@
1
+ import { Vec3 } from "../../math/vec3";
2
+ import { BarycentricCoordinatesResult } from "./closestPoints";
3
+ import { computeBarycentricCoordinates2d } from "./computeBarycentricCoordinates2d";
4
+
5
+ const ab = /*@__PURE__*/ Vec3.create();
6
+ const ac = /*@__PURE__*/ Vec3.create();
7
+ const bc = /*@__PURE__*/ Vec3.create();
8
+ const otherBarycentric = /*@__PURE__*/ BarycentricCoordinatesResult.create();
9
+
10
+ export function computeBarycentricCoordinates3d(
11
+ outBarycentric: BarycentricCoordinatesResult,
12
+ a: Vec3,
13
+ b: Vec3,
14
+ c: Vec3,
15
+ squaredTolerance: number = 1e-10
16
+ ) {
17
+ ab.subtractVectors(b, a);
18
+ ac.subtractVectors(c, a);
19
+ bc.subtractVectors(c, b);
20
+
21
+ const d00 = ab.dot(ab);
22
+ const d11 = ac.dot(ac);
23
+ const d22 = bc.dot(bc);
24
+
25
+ if (d00 <= d22) {
26
+ // Use v0 and v1 to calculate barycentric coordinates
27
+ const d01 = ab.dot(ac);
28
+
29
+ const denominator = d00 * d11 - d01 * d01;
30
+ if (Math.abs(denominator) < 1.0e-12) {
31
+ // Degenerate triangle, return coordinates along longest edge
32
+ if (d00 > d11) {
33
+ computeBarycentricCoordinates2d(otherBarycentric, a, b, squaredTolerance);
34
+ outBarycentric.u = otherBarycentric.u;
35
+ outBarycentric.v = otherBarycentric.v;
36
+ outBarycentric.w = 0.0;
37
+ } else {
38
+ computeBarycentricCoordinates2d(otherBarycentric, a, c, squaredTolerance);
39
+ outBarycentric.u = otherBarycentric.u;
40
+ outBarycentric.w = otherBarycentric.v;
41
+ outBarycentric.v = 0.0;
42
+ }
43
+ outBarycentric.isValid = false;
44
+ return;
45
+ } else {
46
+ const a0 = a.dot(ab);
47
+ const a1 = a.dot(ac);
48
+ outBarycentric.v = (d01 * a1 - d11 * a0) / denominator;
49
+ outBarycentric.w = (d01 * a0 - d00 * a1) / denominator;
50
+ outBarycentric.u = 1.0 - outBarycentric.v - outBarycentric.w;
51
+ }
52
+ } else {
53
+ // Use v1 and v2 to calculate barycentric coordinates
54
+ const d12 = ac.dot(bc);
55
+
56
+ const denominator = d11 * d22 - d12 * d12;
57
+ if (Math.abs(denominator) < 1.0e-12) {
58
+ // Degenerate triangle, return coordinates along longest edge
59
+ if (d11 > d22) {
60
+ computeBarycentricCoordinates2d(otherBarycentric, a, c, squaredTolerance);
61
+ outBarycentric.u = otherBarycentric.u;
62
+ outBarycentric.w = otherBarycentric.v;
63
+ outBarycentric.v = 0.0;
64
+ } else {
65
+ computeBarycentricCoordinates2d(otherBarycentric, b, c, squaredTolerance);
66
+ outBarycentric.v = otherBarycentric.u;
67
+ outBarycentric.w = otherBarycentric.v;
68
+ outBarycentric.u = 0.0;
69
+ }
70
+ outBarycentric.isValid = false;
71
+ return;
72
+ } else {
73
+ const c1 = c.dot(ac);
74
+ const c2 = c.dot(bc);
75
+ outBarycentric.u = (d22 * c1 - d12 * c2) / denominator;
76
+ outBarycentric.v = (d11 * c2 - d12 * c1) / denominator;
77
+ outBarycentric.w = 1.0 - outBarycentric.u - outBarycentric.v;
78
+ }
79
+ }
80
+ outBarycentric.isValid = true;
81
+ }