@perplexdotgg/bounce 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/build/bounce.d.ts +39501 -0
  2. package/build/bounce.js +17166 -0
  3. package/package.json +1 -1
  4. package/src/builders/ConvexHullBuilder.ts +0 -437
  5. package/src/builders/ConvexHullBuilder2d.ts +0 -344
  6. package/src/builders/ConvexHullBuilder3d.ts +0 -1689
  7. package/src/builders/HeightMapBuilder.ts +0 -414
  8. package/src/builders/TriangleMeshBuilder.ts +0 -92
  9. package/src/collision/CastShapesModule.ts +0 -184
  10. package/src/collision/CollideShapesModule.ts +0 -152
  11. package/src/collision/HeightMapCaster.ts +0 -38
  12. package/src/collision/HeightMapCollider.ts +0 -33
  13. package/src/collision/TriangleCaster.ts +0 -249
  14. package/src/collision/TriangleCollider.ts +0 -308
  15. package/src/collision/TriangleCollider2.ts +0 -379
  16. package/src/collision/activeEdge.ts +0 -146
  17. package/src/collision/cast/cast.ts +0 -139
  18. package/src/collision/cast/castCompoundVsCompound.ts +0 -59
  19. package/src/collision/cast/castCompoundVsConvex.ts +0 -116
  20. package/src/collision/cast/castConvexVsCompound.ts +0 -123
  21. package/src/collision/cast/castConvexVsConvex.ts +0 -213
  22. package/src/collision/cast/castConvexVsHeightMap.ts +0 -73
  23. package/src/collision/cast/castConvexVsTriangleMesh.ts +0 -56
  24. package/src/collision/cast/castRayVsCompound.ts +0 -44
  25. package/src/collision/cast/castRayVsConvex.ts +0 -45
  26. package/src/collision/cast/castRayVsHeightMap.ts +0 -58
  27. package/src/collision/cast/castRayVsTriangleMesh.ts +0 -58
  28. package/src/collision/closestPoints/closestPoints.ts +0 -23
  29. package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +0 -32
  30. package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +0 -81
  31. package/src/collision/closestPoints/computeClosestPointOnLine.ts +0 -30
  32. package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +0 -96
  33. package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +0 -195
  34. package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +0 -25
  35. package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +0 -72
  36. package/src/collision/collide/collide.ts +0 -146
  37. package/src/collision/collide/collideCompoundVsCompound.ts +0 -60
  38. package/src/collision/collide/collideCompoundVsConvex.ts +0 -59
  39. package/src/collision/collide/collideCompoundVsHeightMap.ts +0 -73
  40. package/src/collision/collide/collideCompoundVsTriangleMesh.ts +0 -56
  41. package/src/collision/collide/collideConvexVsCompound.ts +0 -57
  42. package/src/collision/collide/collideConvexVsConvex.ts +0 -225
  43. package/src/collision/collide/collideConvexVsConvexImp.ts +0 -236
  44. package/src/collision/collide/collideConvexVsHeightMap.ts +0 -53
  45. package/src/collision/collide/collideConvexVsTriangleMesh.ts +0 -58
  46. package/src/collision/collide/collideHeightMapVsCompound.ts +0 -69
  47. package/src/collision/collide/collideHeightMapVsConvex.ts +0 -53
  48. package/src/collision/collide/collideSphereVsSphere.ts +0 -81
  49. package/src/collision/collide/collideTriangleMeshVsCompound.ts +0 -58
  50. package/src/collision/collide/collideTriangleMeshVsConvex.ts +0 -58
  51. package/src/collision/epa/EpaConvexHullBuilder.ts +0 -397
  52. package/src/collision/epa/StaticArray.ts +0 -154
  53. package/src/collision/epa/TriangleFactory.ts +0 -32
  54. package/src/collision/epa/arrays.ts +0 -99
  55. package/src/collision/epa/binaryHeap.ts +0 -82
  56. package/src/collision/epa/structs.ts +0 -227
  57. package/src/collision/gjk/GjkModule.ts +0 -864
  58. package/src/collision/gjk/PenetrationDepthModule.ts +0 -493
  59. package/src/collision/gjk/SupportPoints.ts +0 -50
  60. package/src/collision/imp/MinkowskiDifference.ts +0 -36
  61. package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +0 -40
  62. package/src/collision/imp/finalizeImpResult.ts +0 -69
  63. package/src/collision/imp/findContactImp.ts +0 -196
  64. package/src/collision/imp/imp.ts +0 -28
  65. package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +0 -207
  66. package/src/collision/mpr/findPortal.ts +0 -152
  67. package/src/collision/mpr/mpr.ts +0 -29
  68. package/src/collision/mpr/updatePortal.ts +0 -52
  69. package/src/constraints/BaseConstraint.ts +0 -50
  70. package/src/constraints/ConstraintOptions.ts +0 -22
  71. package/src/constraints/ConstraintSolver.ts +0 -119
  72. package/src/constraints/DistanceConstraint.ts +0 -229
  73. package/src/constraints/FixedConstraint.ts +0 -203
  74. package/src/constraints/HingeConstraint.ts +0 -460
  75. package/src/constraints/PointConstraint.ts +0 -108
  76. package/src/constraints/components/AngleComponent.ts +0 -226
  77. package/src/constraints/components/AxisComponent.ts +0 -263
  78. package/src/constraints/components/HingeComponent.ts +0 -215
  79. package/src/constraints/components/Motor.ts +0 -36
  80. package/src/constraints/components/PointConstraintComponent.ts +0 -179
  81. package/src/constraints/components/RotationEulerComponent.ts +0 -139
  82. package/src/constraints/components/Spring.ts +0 -30
  83. package/src/constraints/components/SpringComponent.ts +0 -71
  84. package/src/constraints/types.ts +0 -6
  85. package/src/helpers.ts +0 -147
  86. package/src/index.ts +0 -50
  87. package/src/math/BasicTransform.ts +0 -19
  88. package/src/math/NumberValue.ts +0 -13
  89. package/src/math/isometry.ts +0 -64
  90. package/src/math/mat3.ts +0 -529
  91. package/src/math/mat4.ts +0 -588
  92. package/src/math/quat.ts +0 -193
  93. package/src/math/scalar.ts +0 -81
  94. package/src/math/tensor.ts +0 -17
  95. package/src/math/vec3.ts +0 -589
  96. package/src/math/vec4.ts +0 -10
  97. package/src/physics/Body.ts +0 -581
  98. package/src/physics/CollisionFilter.ts +0 -52
  99. package/src/physics/SleepModule.ts +0 -163
  100. package/src/physics/broadphase/BodyPairsModule.ts +0 -363
  101. package/src/physics/broadphase/BvhModule.ts +0 -237
  102. package/src/physics/broadphase/BvhTree.ts +0 -803
  103. package/src/physics/broadphase/ConstraintPairsModule.ts +0 -385
  104. package/src/physics/broadphase/TriangleMeshBvhTree.ts +0 -379
  105. package/src/physics/manifold/ContactManifold.ts +0 -227
  106. package/src/physics/manifold/ContactManifoldModule.ts +0 -623
  107. package/src/physics/manifold/Face.ts +0 -119
  108. package/src/physics/manifold/ManifoldCache.ts +0 -116
  109. package/src/physics/manifold/clipping/clipPolyVsEdge.ts +0 -131
  110. package/src/physics/manifold/clipping/clipPolyVsPlane.ts +0 -73
  111. package/src/physics/manifold/clipping/clipPolyVsPoly.ts +0 -72
  112. package/src/physics/narrowphase/CollideBodiesModule.ts +0 -755
  113. package/src/physics/solver/ContactConstraintModule.ts +0 -659
  114. package/src/physics/solver/ManifoldConstraint.ts +0 -420
  115. package/src/physics/solver/estimateCollisionResponse.ts +0 -146
  116. package/src/shape/Aabb.ts +0 -400
  117. package/src/shape/Box.ts +0 -231
  118. package/src/shape/Capsule.ts +0 -332
  119. package/src/shape/CompoundShape.ts +0 -288
  120. package/src/shape/Convex.ts +0 -130
  121. package/src/shape/ConvexHull.ts +0 -423
  122. package/src/shape/Cylinder.ts +0 -313
  123. package/src/shape/HeightMap.ts +0 -511
  124. package/src/shape/Line.ts +0 -14
  125. package/src/shape/Plane.ts +0 -116
  126. package/src/shape/Ray.ts +0 -81
  127. package/src/shape/Segment.ts +0 -25
  128. package/src/shape/Shape.ts +0 -77
  129. package/src/shape/Sphere.ts +0 -181
  130. package/src/shape/TransformedShape.ts +0 -51
  131. package/src/shape/Triangle.ts +0 -122
  132. package/src/shape/TriangleMesh.ts +0 -186
  133. package/src/types.ts +0 -1
  134. package/src/world.ts +0 -1335
  135. package/tests/BodyPairsModule.test.ts +0 -71
  136. package/tests/BvhTree.test.ts +0 -406
  137. package/tests/test.md +0 -642
  138. package/tests/vec3.test.ts +0 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perplexdotgg/bounce",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "license": "MIT",
5
5
  "description": "Bounce",
6
6
  "main": "./build/bounce.js",
@@ -1,437 +0,0 @@
1
- import { Mat3 } from "../math/mat3";
2
- import { Vec3 } from "../math/vec3";
3
- import { NumberValue } from "../math/NumberValue";
4
- import { Plane } from "../shape/Plane";
5
- import ConvexHull, {
6
- ConvexHullFace,
7
- ConvexHullNoConvex,
8
- ConvexHullPoint,
9
- ConvexHullWithConvex,
10
- updateShape,
11
- } from "../shape/ConvexHull";
12
- import { ConvexHullBuilder3d, ConvexHullBuilderResult } from "./ConvexHullBuilder3d";
13
- import { degreesToRadians } from "../math/scalar";
14
-
15
- const covarianceCanonical = /*@__PURE__*/ Mat3.create();
16
- covarianceCanonical.fillDiagonal(1 / 60);
17
- covarianceCanonical.fillOffDiagonal(1 / 120);
18
- const covarianceAccumulated = /*@__PURE__*/ Mat3.create();
19
- const covarianceTransformed = /*@__PURE__*/ Mat3.create();
20
- const transform = /*@__PURE__*/ Mat3.create();
21
- const transposedTransform = /*@__PURE__*/ Mat3.create();
22
- const v1 = /*@__PURE__*/ Vec3.create();
23
- const v2 = /*@__PURE__*/ Vec3.create();
24
- const v3 = /*@__PURE__*/ Vec3.create();
25
- const zero = /*@__PURE__*/ Vec3.create({ x: 0, y: 0, z: 0 });
26
- const p = /*@__PURE__*/ Vec3.create();
27
- const faceCentroid = /*@__PURE__*/ Vec3.create();
28
- const faceNormal = /*@__PURE__*/ Vec3.create();
29
- const tempVector = /*@__PURE__*/ Vec3.create();
30
- const normal1 = /*@__PURE__*/ Vec3.create();
31
- const normal2 = /*@__PURE__*/ Vec3.create();
32
- const crossNormal1Normal2 = /*@__PURE__*/ Vec3.create();
33
- const normal3 = /*@__PURE__*/ Vec3.create();
34
- const p1 = /*@__PURE__*/ Plane.create();
35
- const p2 = /*@__PURE__*/ Plane.create();
36
- let p3 = /*@__PURE__*/ Plane.create();
37
- const offsetMask = /*@__PURE__*/ Vec3.create();
38
- const crossN1N2 = /*@__PURE__*/ Vec3.create();
39
- const n = /*@__PURE__*/ Mat3.create();
40
- const adj_n = /*@__PURE__*/ Mat3.create();
41
- const transformedOffset = /*@__PURE__*/ Vec3.create();
42
-
43
- export class ConvexHullBuilder {
44
- buildFromPoints(
45
- vertices: Float32Array,
46
- convexRadius: number = 0.02,
47
- hullTolerance: number = 1e-3,
48
- convexHullPool: typeof ConvexHull.Pool = new ConvexHull.Pool(),
49
- facePool: typeof ConvexHullFace.Pool = new ConvexHullFace.Pool(),
50
- numberValuePool: typeof NumberValue.Pool = new NumberValue.Pool(),
51
- planePool: typeof Plane.Pool = new Plane.Pool(),
52
- pointPool: typeof ConvexHullPoint.Pool = new ConvexHullPoint.Pool(),
53
- shapeNoConvexPointsPool: typeof Vec3.Pool = new Vec3.Pool(),
54
- ): ConvexHull {
55
- const maxPoints = 1000;
56
- const maxVertexIndices = 1000;
57
-
58
- // get counts from item buffers and use as max counts
59
- const hull = ConvexHull.create({
60
- convexRadius,
61
- faces: { pool: facePool },
62
- vertexIdx: { pool: numberValuePool },
63
- planes: { pool: planePool },
64
- points: { pool: pointPool },
65
- shapeNoConvexPoints: { pool: shapeNoConvexPointsPool },
66
- }, convexHullPool) as ConvexHull;
67
- hull.shapeNoConvex = new ConvexHullNoConvex(hull, hull.shapeNoConvexPoints);
68
- hull.shapeWithConvex = new ConvexHullWithConvex(hull);
69
-
70
- // Check convex radius
71
- if (hull.convexRadius < 0.0) {
72
- throw new Error("Invalid convex radius");
73
- }
74
-
75
- // set vertex data on polyhedron 3d
76
- const polyhedron3d = new Vec3.Pool();
77
- const polyhedron2d = new Vec3.Pool();
78
- for (let i = 0; i < vertices.length; i += 3) {
79
- Vec3.create({ x: vertices[i + 0], y: vertices[i + 1], z: vertices[i + 2] }, polyhedron3d);
80
- Vec3.create({ x: vertices[i + 0], y: vertices[i + 1], z: vertices[i + 2] }, polyhedron2d);
81
- }
82
-
83
- // Build convex hull
84
- const builder = new ConvexHullBuilder3d();
85
- const result = builder.buildConvexHull(polyhedron3d, polyhedron2d, hullTolerance, maxPoints);
86
- if (result !== ConvexHullBuilderResult.Success && result !== ConvexHullBuilderResult.MaxVerticesReached) {
87
- throw new Error("Hull building failed");
88
- }
89
-
90
- const builder_faces = builder.faces;
91
-
92
- // // Check the consistency of the resulting hull if we fully built it
93
- // // TODO: revisit this error check because it seems to be failing even when the hull looks good visually
94
- // if (result === ConvexHullBuilderResult.Success) {
95
- // const [max_error_face, max_error_distance, max_error_idx, coplaner_distance] = builder.determineMaxError();
96
- // if (max_error_distance > 4 * Math.max(coplaner_distance, hullTolerance)) {
97
- // // Coplanar distance could be bigger than the allowed tolerance if the points are far apart
98
- // throw new Error(
99
- // `Hull building failed, point ${max_error_idx} had an error of ${max_error_distance} (relative to tolerance: ${
100
- // max_error_distance / hullTolerance
101
- // })`
102
- // );
103
- // }
104
- // }
105
-
106
- // Calculate center of mass and volume
107
- hull.computedVolume = builder.getCenterOfMassAndVolume(hull.computedCenterOfMass);
108
- // make center of mass zero if it is close to zero
109
- if (hull.computedCenterOfMass.isCloseToZero(1e-6)) {
110
- hull.computedCenterOfMass.zero();
111
- }
112
-
113
- // Calculate covariance matrix
114
- // See:
115
- // - Why the inertia tensor is the inertia tensor - Jonathan Blow (http://number-none.com/blow/inertia/deriving_i.html)
116
- // - How to find the inertia tensor (or other mass properties) of a 3D solid body represented by a triangle mesh (Draft) - Jonathan Blow, Atman J Binstock (http://number-none.com/blow/inertia/bb_inertia.doc)
117
-
118
- // compute canonical covariance matrix
119
- // this is the covariance matrix for a unit tetrahedron
120
- // with vertices (0, 0, 0), (1, 0, 0), (0, 1, 0) and (0, 0, 1)
121
- // with density 1 kg/m^3
122
- // because of symmetry, we only need to "calculate". diagonal = 1 / 60, off-diagonal = 1 / 120
123
-
124
- // start covariance actual at zero as it will be used for accumulation
125
- covarianceAccumulated.fill(0);
126
-
127
- for (const face of builder_faces) {
128
- // Fourth point of the tetrahedron is at the center of mass, we subtract it from the other points so we get a tetrahedron with one vertex at zero
129
- // The first point on the face will be used to form a triangle fan
130
- let edge = face.firstEdge;
131
- v1.subtractVectors(polyhedron3d.array[edge!.startIndex], hull.computedCenterOfMass);
132
-
133
- // Get the 2nd point
134
- edge = edge!.nextEdge;
135
- v2.subtractVectors(polyhedron3d.array[edge!.startIndex], hull.computedCenterOfMass);
136
-
137
- // Loop over the triangle fan
138
- for (edge = edge!.nextEdge; edge !== face.firstEdge; edge = edge!.nextEdge) {
139
- v3.subtractVectors(polyhedron3d.array[edge!.startIndex], hull.computedCenterOfMass);
140
-
141
- // Affine transform that transforms a unit tetrahedon (with vertices (0, 0, 0), (1, 0, 0), (0, 1, 0) and (0, 0, 1) to this tetrahedron
142
- transform.setColumns(v1, v2, v3);
143
-
144
- // Calculate covariance matrix for this tetrahedron
145
- const det_a = transform.computeDeterminant();
146
-
147
- // C_transformed = det_a * (A * C_canonical * A^T)
148
- transposedTransform.transposeMatrix(transform);
149
- covarianceTransformed.multiplyMat3s(transform, covarianceCanonical);
150
- covarianceTransformed.multiplyMat3s(covarianceTransformed, transposedTransform);
151
- covarianceTransformed.multiplyByScalar(det_a);
152
-
153
- // Add it
154
- covarianceAccumulated.addMatrices(covarianceAccumulated, covarianceTransformed);
155
-
156
- // Prepare for next triangle
157
- v2.copy(v3);
158
- }
159
- }
160
-
161
- // Calculate inertia matrix assuming density is 1
162
- hull.inertia.identity();
163
- hull.inertia.multiplyByScalar(covarianceAccumulated.e0 + covarianceAccumulated.e4 + covarianceAccumulated.e8);
164
- hull.inertia.subtractMatrices(hull.inertia, covarianceAccumulated);
165
-
166
- // Convert polygons from the builder to our internal representation
167
- const vertexMap = new Map<number, number>();
168
-
169
- for (const builder_face of builder_faces) {
170
- // Determine where the vertices go
171
- if (hull.vertexIdx.length > maxVertexIndices) {
172
- throw new Error(`vertex index array too large: (${hull.vertexIdx.length}), max allowed ${maxVertexIndices}`);
173
- }
174
- let firstVertex = hull.vertexIdx.length;
175
- let numVertices = 0;
176
-
177
- // Loop over vertices in face
178
- let edge = builder_face.firstEdge;
179
- do {
180
- // Remap to new index, not all points in the original input set are required to form the hull
181
- // TODO: is it okay to set new_idx to 0 here?
182
- let newIdx: number = 0;
183
- const originalIdx = edge!.startIndex;
184
- const m = vertexMap.get(originalIdx);
185
- if (m !== undefined) {
186
- // Found, reuse
187
- newIdx = m;
188
- } else {
189
- // This is a new point
190
- // Make relative to center of mass
191
-
192
- p.subtractVectors(polyhedron3d.array[originalIdx], hull.computedCenterOfMass);
193
-
194
- // TODO: Update local bounds
195
-
196
- // Add to point list
197
- if (hull.points.length <= maxPoints) {
198
- newIdx = hull.points.length;
199
- hull.points.create({ position: p, numFaces: 0, faces: zero });
200
- vertexMap.set(originalIdx, newIdx);
201
- }
202
- }
203
-
204
- // Append to vertex list
205
- if (hull.vertexIdx.length >= maxVertexIndices) {
206
- throw new Error(`vertex index array too large: (${hull.vertexIdx.length}), max allowed ${maxVertexIndices}`);
207
- }
208
-
209
- // TODO: should newIdx be initialized to some value?
210
- hull.vertexIdx.create({ value: newIdx });
211
- numVertices++;
212
-
213
- edge = edge!.nextEdge;
214
- } while (edge !== builder_face.firstEdge);
215
-
216
- // Add face
217
- hull.faces.create({ firstVertex: firstVertex, numVertices: numVertices });
218
-
219
- // Add plane
220
- faceCentroid.fromArray(builder_face.centroid);
221
- faceNormal.fromArray(builder_face.normal);
222
- tempVector.subtractVectors(faceCentroid, hull.computedCenterOfMass);
223
- faceNormal.normalize();
224
-
225
- const plane = hull.planes.create(undefined);
226
- plane.fromPointAndNormal(tempVector, faceNormal);
227
- }
228
-
229
- // Test if GetSupportFunction can support this many points
230
- if (hull.points.length > maxPoints) {
231
- throw new Error(`Internal error: Too many points in hull (${hull.points.length}), max allowed ${maxPoints}`);
232
- }
233
-
234
- for (let p = 0; p < hull.points.length; ++p) {
235
- // For each point, find faces that use the point
236
- let faces: number[] = [];
237
-
238
- for (let f = 0; f < hull.faces.length; ++f) {
239
- const face = hull.faces.getAtIndex(f)!;
240
-
241
- for (let v = 0; v < face.numVertices; ++v) {
242
- const vertexIndex = hull.vertexIdx.getAtIndex(face.firstVertex + v)!;
243
- if (vertexIndex.value === p) {
244
- faces.push(f);
245
- break;
246
- }
247
- }
248
- }
249
-
250
- if (faces.length < 2) {
251
- throw new Error("A point must be connected to 2 or more faces!");
252
- }
253
-
254
- // Find the 3 normals that form the largest tetrahedron
255
- // The largest tetrahedron we can get is ((1, 0, 0) x (0, 1, 0)) . (0, 0, 1) = 1, if the volume is only 5% of that,
256
- // the three vectors are too coplanar and we fall back to using only 2 plane normals
257
- let biggest_volume = 0.05;
258
- const best3 = [-1, -1, -1];
259
-
260
- // When using 2 normals, we get the two with the biggest angle between them with a minimal difference of 1 degree
261
- // otherwise we fall back to just using 1 plane normal
262
- let smallest_dot = Math.cos(degreesToRadians(1.0));
263
- const best2 = [-1, -1];
264
-
265
- for (let face1 = 0; face1 < faces.length; ++face1) {
266
- const plane1 = hull.planes.getAtIndex(faces[face1])!;
267
- normal1.copy(plane1.normal);
268
-
269
- for (let face2 = face1 + 1; face2 < faces.length; ++face2) {
270
- const plane2 = hull.planes.getAtIndex(faces[face2])!;
271
- normal2.copy(plane2.normal);
272
-
273
- crossNormal1Normal2.crossVectors(normal1, normal2);
274
-
275
- // Determine the 2 face normals that are most apart
276
- const dot = normal1.dot(normal2);
277
- if (dot < smallest_dot) {
278
- smallest_dot = dot;
279
- best2[0] = faces[face1];
280
- best2[1] = faces[face2];
281
- }
282
-
283
- // Determine the 3 face normals that form the largest tetrahedron
284
- for (let face3 = face2 + 1; face3 < faces.length; ++face3) {
285
- const plane3 = hull.planes.getAtIndex(faces[face3])!;
286
- normal3.copy(plane3.normal);
287
-
288
- const volume = Math.abs(crossNormal1Normal2.dot(normal3));
289
- if (volume > biggest_volume) {
290
- biggest_volume = volume;
291
- best3[0] = faces[face1];
292
- best3[1] = faces[face2];
293
- best3[2] = faces[face3];
294
- }
295
- }
296
- }
297
- }
298
-
299
- // If we didn't find 3 planes, use 2, if we didn't find 2 use 1
300
- let pointFaces: [number, number, number];
301
- if (best3[0] !== -1) {
302
- faces = [best3[0], best3[1], best3[2]];
303
- pointFaces = [best3[0], best3[1], best3[2]];
304
- } else if (best2[0] !== -1) {
305
- faces = [best2[0], best2[1]];
306
- pointFaces = [best2[0], best2[1], -1];
307
- } else {
308
- faces = [faces[0], -1, -1];
309
- pointFaces = [faces[0], -1, -1];
310
- }
311
-
312
- // Copy the faces to the points buffer
313
- const point = hull.points.getAtIndex(p)!;
314
- point.numFaces = faces.length;
315
- point.faces.fromArray(pointFaces);
316
- }
317
-
318
- // If the convex radius is already zero, there's no point in further reducing it
319
- if (hull.convexRadius > 0.0) {
320
- // Find out how thin the hull is by walking over all planes and checking the thickness of the hull in that direction
321
- let minSize = Number.MAX_VALUE;
322
-
323
- for (let i = 0; i < hull.planes.length; i++) {
324
- const plane = hull.planes.getAtIndex(i)!;
325
-
326
- // Take the point that is furthest away from the plane as thickness of this hull
327
- let maxDist = 0.0;
328
-
329
- for (let j = 0; j < hull.points.length; j++) {
330
- const point = hull.points.getAtIndex(j)!;
331
-
332
- const dist = -plane.signedDistance(point.position); // Point is always behind plane, so we need to negate
333
- if (dist > maxDist) {
334
- maxDist = dist;
335
- }
336
- }
337
- minSize = Math.min(minSize, maxDist);
338
- }
339
-
340
- // We need to fit in 2x the convex radius in min_size, so reduce the convex radius if it's bigger than that
341
- hull.convexRadius = Math.min(hull.convexRadius, 0.5 * minSize);
342
- }
343
-
344
- // Now walk over all points and see if we have to further reduce the convex radius because of sharp edges
345
- if (hull.convexRadius > 0.0) {
346
- for (let i = 0; i < hull.points.length; i++) {
347
- const point = hull.points.getAtIndex(i)!;
348
-
349
- // If we have a single face, shifting back is easy and we don't need to reduce the convex radius
350
- if (point.numFaces !== 1) {
351
- // Get first two planes
352
- p1.copy(hull.planes.getAtIndex(point.faces.x)!);
353
- p2.copy(hull.planes.getAtIndex(point.faces.y)!);
354
-
355
- if (point.numFaces === 3) {
356
- // Get third plane
357
- p3.copy(hull.planes.getAtIndex(point.faces.z)!);
358
-
359
- // All 3 planes will be offset by the convex radius
360
- offsetMask.replicate(1);
361
- } else {
362
- // Third plane has normal perpendicular to the other two planes and goes through the vertex position
363
- if (point.numFaces !== 2) {
364
- throw new Error("Invalid number of faces");
365
- }
366
-
367
- crossN1N2.crossVectors(p1.normal, p2.normal);
368
- p3.fromPointAndNormal(point.position, crossN1N2);
369
-
370
- // Only the first and 2nd plane will be offset, the 3rd plane is only there to guide the intersection point
371
- offsetMask.set({ x: 1, y: 1, z: 0 });
372
- }
373
-
374
- // Plane equation: point . normal + constant = 0
375
- // Offsetting the plane backwards with convex radius r: point . normal + constant + r = 0
376
- // To find the intersection 'point' of 3 planes we solve:
377
- // |n1x n1y n1z| |x| | r + c1 |
378
- // |n2x n2y n2z| |y| = - | r + c2 | <=> n point = -r (1, 1, 1) - (c1, c2, c3)
379
- // |n3x n3y n3z| |z| | r + c3 |
380
- // Where point = (x, y, z), n1x is the x component of the first plane, c1 = plane constant of plane 1, etc.
381
- // The relation between how much the intersection point shifts as a function of r is: -r * n^-1 (1, 1, 1) = r * offset
382
- // Where offset = -n^-1 (1, 1, 1) or -n^-1 (1, 1, 0) in case only the first 2 planes are offset
383
- // The error that is introduced by a convex radius r is: error = r * |offset| - r
384
- // So the max convex radius given error is: r = error / (|offset| - 1)
385
-
386
- // TODO: using a mat3 here instead of a mat4 because mat4.3x3 functions not implemented, as a result, not sure if this is correct
387
-
388
- n.e0 = p1.normal.x;
389
- n.e1 = p1.normal.y;
390
- n.e2 = p1.normal.z;
391
- n.e3 = p2.normal.x;
392
- n.e4 = p2.normal.y;
393
- n.e5 = p2.normal.z;
394
- n.e6 = p3.normal.x;
395
- n.e7 = p3.normal.y;
396
- n.e8 = p3.normal.z;
397
- n.transpose();
398
-
399
- const det_n = n.computeDeterminant();
400
- if (det_n === 0.0) {
401
- // If the determinant is zero, the matrix is not invertible so no solution exists to move the point backwards and we have to choose a convex radius of zero
402
- hull.convexRadius = 0.0;
403
- break;
404
- }
405
-
406
- adj_n.adjointMatrix(n);
407
-
408
- transformedOffset.transformVectorFromMat3(offsetMask, adj_n);
409
- transformedOffset.scale(1 / det_n);
410
- const offset = transformedOffset.length();
411
- if (offset <= 1.0) {
412
- throw new Error("Invalid offset");
413
- }
414
- const max_convex_radius = hullTolerance / (offset - 1.0);
415
- hull.convexRadius = Math.min(hull.convexRadius, max_convex_radius);
416
- }
417
- }
418
- }
419
-
420
- // Calculate the inner radius by getting the minimum distance from the origin to the planes of the hull
421
- hull.innerRadius = Number.MAX_VALUE;
422
- for (let i = 0; i < hull.planes.length; i++) {
423
- const plane = hull.planes.getAtIndex(i)!;
424
- hull.innerRadius = Math.min(hull.innerRadius, -plane.constant);
425
- }
426
- // Clamp against zero, this should do nothing as the shape is centered around the
427
- // center of mass but for flat convex hulls there may be numerical round off issues
428
- hull.innerRadius = Math.max(0.0, hull.innerRadius);
429
-
430
- for (let i = 0; i < hull.points.length; i++) {
431
- hull.shapeNoConvexPoints.create();
432
- }
433
-
434
- updateShape(hull);
435
- return hull;
436
- }
437
- }