@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.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/package.json +32 -0
- package/src/builders/ConvexHullBuilder.ts +437 -0
- package/src/builders/ConvexHullBuilder2d.ts +344 -0
- package/src/builders/ConvexHullBuilder3d.ts +1689 -0
- package/src/builders/HeightMapBuilder.ts +414 -0
- package/src/builders/TriangleMeshBuilder.ts +92 -0
- package/src/collision/CastShapesModule.ts +184 -0
- package/src/collision/CollideShapesModule.ts +152 -0
- package/src/collision/HeightMapCaster.ts +38 -0
- package/src/collision/HeightMapCollider.ts +33 -0
- package/src/collision/TriangleCaster.ts +249 -0
- package/src/collision/TriangleCollider.ts +308 -0
- package/src/collision/TriangleCollider2.ts +379 -0
- package/src/collision/activeEdge.ts +146 -0
- package/src/collision/cast/cast.ts +139 -0
- package/src/collision/cast/castCompoundVsCompound.ts +59 -0
- package/src/collision/cast/castCompoundVsConvex.ts +116 -0
- package/src/collision/cast/castConvexVsCompound.ts +123 -0
- package/src/collision/cast/castConvexVsConvex.ts +213 -0
- package/src/collision/cast/castConvexVsHeightMap.ts +73 -0
- package/src/collision/cast/castConvexVsTriangleMesh.ts +56 -0
- package/src/collision/cast/castRayVsCompound.ts +44 -0
- package/src/collision/cast/castRayVsConvex.ts +45 -0
- package/src/collision/cast/castRayVsHeightMap.ts +58 -0
- package/src/collision/cast/castRayVsTriangleMesh.ts +58 -0
- package/src/collision/closestPoints/closestPoints.ts +23 -0
- package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +32 -0
- package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +81 -0
- package/src/collision/closestPoints/computeClosestPointOnLine.ts +30 -0
- package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +96 -0
- package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +195 -0
- package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +25 -0
- package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +72 -0
- package/src/collision/collide/collide.ts +146 -0
- package/src/collision/collide/collideCompoundVsCompound.ts +60 -0
- package/src/collision/collide/collideCompoundVsConvex.ts +59 -0
- package/src/collision/collide/collideCompoundVsHeightMap.ts +73 -0
- package/src/collision/collide/collideCompoundVsTriangleMesh.ts +56 -0
- package/src/collision/collide/collideConvexVsCompound.ts +57 -0
- package/src/collision/collide/collideConvexVsConvex.ts +225 -0
- package/src/collision/collide/collideConvexVsConvexImp.ts +236 -0
- package/src/collision/collide/collideConvexVsHeightMap.ts +53 -0
- package/src/collision/collide/collideConvexVsTriangleMesh.ts +58 -0
- package/src/collision/collide/collideHeightMapVsCompound.ts +69 -0
- package/src/collision/collide/collideHeightMapVsConvex.ts +53 -0
- package/src/collision/collide/collideSphereVsSphere.ts +81 -0
- package/src/collision/collide/collideTriangleMeshVsCompound.ts +58 -0
- package/src/collision/collide/collideTriangleMeshVsConvex.ts +58 -0
- package/src/collision/epa/EpaConvexHullBuilder.ts +397 -0
- package/src/collision/epa/StaticArray.ts +154 -0
- package/src/collision/epa/TriangleFactory.ts +32 -0
- package/src/collision/epa/arrays.ts +99 -0
- package/src/collision/epa/binaryHeap.ts +82 -0
- package/src/collision/epa/structs.ts +227 -0
- package/src/collision/gjk/GjkModule.ts +864 -0
- package/src/collision/gjk/PenetrationDepthModule.ts +493 -0
- package/src/collision/gjk/SupportPoints.ts +50 -0
- package/src/collision/imp/MinkowskiDifference.ts +36 -0
- package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +40 -0
- package/src/collision/imp/finalizeImpResult.ts +69 -0
- package/src/collision/imp/findContactImp.ts +196 -0
- package/src/collision/imp/imp.ts +28 -0
- package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +207 -0
- package/src/collision/mpr/findPortal.ts +152 -0
- package/src/collision/mpr/mpr.ts +29 -0
- package/src/collision/mpr/updatePortal.ts +52 -0
- package/src/constraints/BaseConstraint.ts +50 -0
- package/src/constraints/ConstraintOptions.ts +22 -0
- package/src/constraints/ConstraintSolver.ts +119 -0
- package/src/constraints/DistanceConstraint.ts +229 -0
- package/src/constraints/FixedConstraint.ts +203 -0
- package/src/constraints/HingeConstraint.ts +460 -0
- package/src/constraints/PointConstraint.ts +108 -0
- package/src/constraints/components/AngleComponent.ts +226 -0
- package/src/constraints/components/AxisComponent.ts +263 -0
- package/src/constraints/components/HingeComponent.ts +215 -0
- package/src/constraints/components/Motor.ts +36 -0
- package/src/constraints/components/PointConstraintComponent.ts +179 -0
- package/src/constraints/components/RotationEulerComponent.ts +139 -0
- package/src/constraints/components/Spring.ts +30 -0
- package/src/constraints/components/SpringComponent.ts +71 -0
- package/src/constraints/types.ts +6 -0
- package/src/helpers.ts +147 -0
- package/src/index.ts +50 -0
- package/src/math/BasicTransform.ts +19 -0
- package/src/math/NumberValue.ts +13 -0
- package/src/math/isometry.ts +64 -0
- package/src/math/mat3.ts +529 -0
- package/src/math/mat4.ts +588 -0
- package/src/math/quat.ts +193 -0
- package/src/math/scalar.ts +81 -0
- package/src/math/tensor.ts +17 -0
- package/src/math/vec3.ts +589 -0
- package/src/math/vec4.ts +10 -0
- package/src/physics/Body.ts +581 -0
- package/src/physics/CollisionFilter.ts +52 -0
- package/src/physics/SleepModule.ts +163 -0
- package/src/physics/broadphase/BodyPairsModule.ts +363 -0
- package/src/physics/broadphase/BvhModule.ts +237 -0
- package/src/physics/broadphase/BvhTree.ts +803 -0
- package/src/physics/broadphase/ConstraintPairsModule.ts +385 -0
- package/src/physics/broadphase/TriangleMeshBvhTree.ts +379 -0
- package/src/physics/manifold/ContactManifold.ts +227 -0
- package/src/physics/manifold/ContactManifoldModule.ts +623 -0
- package/src/physics/manifold/Face.ts +119 -0
- package/src/physics/manifold/ManifoldCache.ts +116 -0
- package/src/physics/manifold/clipping/clipPolyVsEdge.ts +131 -0
- package/src/physics/manifold/clipping/clipPolyVsPlane.ts +73 -0
- package/src/physics/manifold/clipping/clipPolyVsPoly.ts +72 -0
- package/src/physics/narrowphase/CollideBodiesModule.ts +755 -0
- package/src/physics/solver/ContactConstraintModule.ts +659 -0
- package/src/physics/solver/ManifoldConstraint.ts +420 -0
- package/src/physics/solver/estimateCollisionResponse.ts +146 -0
- package/src/shape/Aabb.ts +400 -0
- package/src/shape/Box.ts +231 -0
- package/src/shape/Capsule.ts +332 -0
- package/src/shape/CompoundShape.ts +288 -0
- package/src/shape/Convex.ts +130 -0
- package/src/shape/ConvexHull.ts +423 -0
- package/src/shape/Cylinder.ts +313 -0
- package/src/shape/HeightMap.ts +511 -0
- package/src/shape/Line.ts +14 -0
- package/src/shape/Plane.ts +116 -0
- package/src/shape/Ray.ts +81 -0
- package/src/shape/Segment.ts +25 -0
- package/src/shape/Shape.ts +77 -0
- package/src/shape/Sphere.ts +181 -0
- package/src/shape/TransformedShape.ts +51 -0
- package/src/shape/Triangle.ts +122 -0
- package/src/shape/TriangleMesh.ts +186 -0
- package/src/types.ts +1 -0
- package/src/world.ts +1335 -0
- package/tests/BodyPairsModule.test.ts +71 -0
- package/tests/BvhTree.test.ts +406 -0
- package/tests/test.md +642 -0
- package/tests/vec3.test.ts +12 -0
- package/tsconfig.json +20 -0
- package/vite.config.js +40 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createClass, MonomorphType, NumberType, PropertyDefinitionMap } from "monomorph";
|
|
2
|
+
import { Isometry } from "../math/isometry";
|
|
3
|
+
import { Vec3 } from "../math/vec3";
|
|
4
|
+
import { Face } from "../physics/manifold/Face";
|
|
5
|
+
import { Mat4 } from "../math/mat4";
|
|
6
|
+
|
|
7
|
+
export interface SupportShape {
|
|
8
|
+
computeSupport(out: Vec3, direction: Vec3): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const enum SupportMode {
|
|
12
|
+
ExcludeConvexRadius,
|
|
13
|
+
IncludeConvexRadius,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ConvexWithcomputeSupportShape {
|
|
17
|
+
computeSupportShape(mode: SupportMode, scale: number): SupportShapeWithConvexRadius;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SupportShapeWithConvexRadius extends SupportShape {
|
|
21
|
+
getConvexRadius(): number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const localDirection = /*@__PURE__*/ Vec3.create();
|
|
25
|
+
|
|
26
|
+
export class TransformedConvexObject implements SupportShape {
|
|
27
|
+
transform: Isometry | null;
|
|
28
|
+
convexShape: SupportShape | null;
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
this.transform = null;
|
|
32
|
+
this.convexShape = null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setData(transform: Isometry, convexShape: SupportShape): void {
|
|
36
|
+
this.transform = transform;
|
|
37
|
+
this.convexShape = convexShape;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
computeSupport(out: Vec3, direction: Vec3): void {
|
|
41
|
+
this.transform!.matrix.multiply3x3Transposed(localDirection, direction);
|
|
42
|
+
this.convexShape!.computeSupport(out, localDirection);
|
|
43
|
+
out.transformFromMat4(this.transform!.matrix);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const transformedConvexShapeProps = {
|
|
48
|
+
transform: MonomorphType(Isometry),
|
|
49
|
+
} as const satisfies PropertyDefinitionMap;
|
|
50
|
+
|
|
51
|
+
const direction = /*@__PURE__*/ Vec3.create();
|
|
52
|
+
|
|
53
|
+
export class TransformedConvexShape extends createClass<TransformedConvexShape, typeof transformedConvexShapeProps>(
|
|
54
|
+
transformedConvexShapeProps
|
|
55
|
+
) {
|
|
56
|
+
object: SupportShape | null;
|
|
57
|
+
|
|
58
|
+
constructor() {
|
|
59
|
+
super();
|
|
60
|
+
this.object = null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Calculate the support vector for this convex shape.
|
|
64
|
+
computeSupport(out: Vec3, inDirection: Vec3): void {
|
|
65
|
+
this.transform.matrix.multiply3x3Transposed(direction, inDirection);
|
|
66
|
+
this.object!.computeSupport(out, direction);
|
|
67
|
+
out.transformByMat4(this.transform.matrix);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const convexRadiusObjectProps = {
|
|
72
|
+
radius: NumberType(0.0),
|
|
73
|
+
} as const satisfies PropertyDefinitionMap;
|
|
74
|
+
|
|
75
|
+
export class ConvexRadiusObject extends createClass<ConvexRadiusObject, typeof convexRadiusObjectProps>(
|
|
76
|
+
convexRadiusObjectProps
|
|
77
|
+
) {
|
|
78
|
+
// TODO: this is an actual reference, should this be changed?
|
|
79
|
+
convexShape: SupportShape | null;
|
|
80
|
+
|
|
81
|
+
constructor() {
|
|
82
|
+
super();
|
|
83
|
+
this.convexShape = null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setData(radius: number, convexShape: SupportShape): void {
|
|
87
|
+
this.radius = radius;
|
|
88
|
+
this.convexShape = convexShape;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Calculate the support vector for this convex shape.
|
|
92
|
+
computeSupport(out: Vec3, inDirection: Vec3): void {
|
|
93
|
+
const length = inDirection.length();
|
|
94
|
+
this.convexShape!.computeSupport(out, inDirection);
|
|
95
|
+
if (length > 0.0) {
|
|
96
|
+
out.addScaled(inDirection, this.radius / length);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const vertex = /*@__PURE__*/ Vec3.create();
|
|
102
|
+
|
|
103
|
+
export class PolygonConvexSupport implements SupportShape {
|
|
104
|
+
declare vertices: Face;
|
|
105
|
+
|
|
106
|
+
computeSupport(out: Vec3, direction: Vec3): void {
|
|
107
|
+
this.vertices.getVertex(out, 0);
|
|
108
|
+
let bestDot = out.dot(direction);
|
|
109
|
+
|
|
110
|
+
// iterate over the vertices of the face
|
|
111
|
+
for (let i = 0; i < this.vertices.numVertices; i++) {
|
|
112
|
+
this.vertices.getVertex(vertex, i);
|
|
113
|
+
const dot = vertex.dot(direction);
|
|
114
|
+
if (dot > bestDot) {
|
|
115
|
+
bestDot = dot;
|
|
116
|
+
out.copy(vertex);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
computeSupportingFace(
|
|
122
|
+
out: Face,
|
|
123
|
+
subShapeID: number,
|
|
124
|
+
direction: Vec3,
|
|
125
|
+
scale: number,
|
|
126
|
+
centerOfMassTransform: Mat4
|
|
127
|
+
): void {
|
|
128
|
+
throw new Error("Method not implemented.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createClass,
|
|
3
|
+
LazyReferenceType,
|
|
4
|
+
MonomorphType,
|
|
5
|
+
NumberType,
|
|
6
|
+
PropertyDefinitionMap,
|
|
7
|
+
PropertyDefinitionReference,
|
|
8
|
+
ReferenceListType,
|
|
9
|
+
} from "monomorph";
|
|
10
|
+
import { Vec3 } from "../math/vec3";
|
|
11
|
+
import { ConvexShapeInterface, ShapeType } from "./Shape";
|
|
12
|
+
import { Aabb } from "./Aabb";
|
|
13
|
+
import { Mat3 } from "../math/mat3";
|
|
14
|
+
import { Plane } from "./Plane";
|
|
15
|
+
import { NumberValue } from "../math/NumberValue";
|
|
16
|
+
import { SupportMode, SupportShapeWithConvexRadius } from "./Convex";
|
|
17
|
+
import { Face } from "../physics/manifold/Face";
|
|
18
|
+
import { Mat4 } from "../math/mat4";
|
|
19
|
+
import { Isometry } from "../math/isometry";
|
|
20
|
+
import { Quat } from "../math/quat";
|
|
21
|
+
import type { World } from "../world";
|
|
22
|
+
|
|
23
|
+
const maxPointsInHull = 1000;
|
|
24
|
+
const isometry = /*@__PURE__*/ Isometry.create();
|
|
25
|
+
const cross_n1_n2 = /*@__PURE__*/ Vec3.create();
|
|
26
|
+
let newPoint = /*@__PURE__*/ Vec3.create();
|
|
27
|
+
|
|
28
|
+
const p1 = /*@__PURE__*/ Plane.create();
|
|
29
|
+
const p2 = /*@__PURE__*/ Plane.create();
|
|
30
|
+
const p3 = /*@__PURE__*/ Plane.create();
|
|
31
|
+
|
|
32
|
+
export class ConvexHullNoConvex implements SupportShapeWithConvexRadius {
|
|
33
|
+
shape: ConvexHull;
|
|
34
|
+
points: typeof ConvexHull.prototype.shapeNoConvexPoints;
|
|
35
|
+
|
|
36
|
+
constructor(shape: ConvexHull, points: typeof ConvexHull.prototype.shapeNoConvexPoints) {
|
|
37
|
+
this.shape = shape;
|
|
38
|
+
this.points = points;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getConvexRadius() {
|
|
42
|
+
return this.shape.convexRadius;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
computeSupport(out: Vec3, direction: Vec3) {
|
|
46
|
+
// Find the point with the highest projection on inDirection
|
|
47
|
+
let bestDot = -Infinity;
|
|
48
|
+
let bestPointIndex = -1;
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < this.points!.length; i++) {
|
|
51
|
+
const point = this.points!.getAtIndex(i)!;
|
|
52
|
+
|
|
53
|
+
// Check if its support is bigger than the current max
|
|
54
|
+
const dot = point.dot(direction);
|
|
55
|
+
if (dot > bestDot) {
|
|
56
|
+
bestDot = dot;
|
|
57
|
+
bestPointIndex = i;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
out.copy(this.points!.getAtIndex(bestPointIndex)!);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
computeSupportingFace(out: Face, subShapeID: number, direction: Vec3, scale: number, centerOfMassTransform: Mat4) {
|
|
65
|
+
throw new Error("Method not implemented.");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class ConvexHullWithConvex implements SupportShapeWithConvexRadius {
|
|
70
|
+
shape: ConvexHull;
|
|
71
|
+
|
|
72
|
+
constructor(shape: ConvexHull) {
|
|
73
|
+
this.shape = shape;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getConvexRadius() {
|
|
77
|
+
return 0.0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
computeSupport(out: Vec3, direction: Vec3) {
|
|
81
|
+
// Find the point with the highest projection on inDirection
|
|
82
|
+
let bestDot = -Infinity;
|
|
83
|
+
let bestPointIndex = -1;
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < this.shape.points!.length; i++) {
|
|
86
|
+
const point = this.shape.points!.getAtIndex(i)!;
|
|
87
|
+
|
|
88
|
+
// Check if its support is bigger than the current max
|
|
89
|
+
const dot = point.position.dot(direction);
|
|
90
|
+
if (dot > bestDot) {
|
|
91
|
+
bestDot = dot;
|
|
92
|
+
bestPointIndex = i;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
out.copy(this.shape.points!.getAtIndex(bestPointIndex)!.position);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
computeSupportingFace(out: Face, subShapeID: number, direction: Vec3, scale: number, centerOfMassTransform: Mat4) {
|
|
100
|
+
throw new Error("Method not implemented.");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const convexHullPointProps = {
|
|
105
|
+
position: MonomorphType(Vec3),
|
|
106
|
+
numFaces: NumberType(0),
|
|
107
|
+
faces: MonomorphType(Vec3),
|
|
108
|
+
} as const satisfies PropertyDefinitionMap;
|
|
109
|
+
|
|
110
|
+
export class ConvexHullPoint extends createClass<ConvexHullPoint, typeof convexHullPointProps>(convexHullPointProps) {
|
|
111
|
+
toObject() {
|
|
112
|
+
return {
|
|
113
|
+
position: this.position.toObject(),
|
|
114
|
+
numFaces: this.numFaces,
|
|
115
|
+
faces: this.faces.toObject(),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const convexHullFaceProps = {
|
|
121
|
+
firstVertex: NumberType(0),
|
|
122
|
+
numVertices: NumberType(0),
|
|
123
|
+
} as const satisfies PropertyDefinitionMap;
|
|
124
|
+
|
|
125
|
+
export class ConvexHullFace extends createClass<ConvexHullFace, typeof convexHullFaceProps>(convexHullFaceProps) {
|
|
126
|
+
toObject() {
|
|
127
|
+
return {
|
|
128
|
+
firstVertex: this.firstVertex,
|
|
129
|
+
numVertices: this.numVertices,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const convexHullProps = {
|
|
135
|
+
computedCenterOfMass: MonomorphType(Vec3, undefined, true),
|
|
136
|
+
computedVolume: NumberType(0.0, true),
|
|
137
|
+
computedAabb: MonomorphType(Aabb, undefined, true),
|
|
138
|
+
convexRadius: NumberType(0.0),
|
|
139
|
+
innerRadius: NumberType(0.0, true),
|
|
140
|
+
inertia: MonomorphType(Mat3, undefined, true),
|
|
141
|
+
points: ReferenceListType(ConvexHullPoint), // { array: Float64Array(b), itemMaxCount: b / 7, itemSize: 7 } [ConvexHullPoint], points on the convex hull surface
|
|
142
|
+
faces: ReferenceListType(ConvexHullFace), // { array: Float64Array(c), itemMaxCount: c / 2, itemSize: 2 } [ConvexHullFace], faces of the convex hull surface
|
|
143
|
+
planes: ReferenceListType(Plane), // { array: Float64Array(d), itemMaxCount: d / 4, itemSize: 4 } [Plane], planes of the convex hull surface
|
|
144
|
+
vertexIdx: ReferenceListType(NumberValue), // { array: Float64Array(e), itemMaxCount: e, itemSize: 1 } [Uint32], vertex indices for each of the faces
|
|
145
|
+
shapeNoConvexPoints: ReferenceListType(Vec3), // { array: Float64Array(f), itemMaxCount: f / 3, itemSize: 3 } [Vec3], transformed points used by ConvexHullNoConvex
|
|
146
|
+
translation: MonomorphType(Vec3, { x: 0, y: 0, z: 0 }),
|
|
147
|
+
copyForDiff: LazyReferenceType((() => ConvexHull) as () => never) as PropertyDefinitionReference<
|
|
148
|
+
ConvexHull | null,
|
|
149
|
+
true
|
|
150
|
+
>,
|
|
151
|
+
} as const satisfies PropertyDefinitionMap;
|
|
152
|
+
|
|
153
|
+
const afterConstructorCode = `
|
|
154
|
+
this.world = null;
|
|
155
|
+
this.shapeNoConvex = null;
|
|
156
|
+
this.shapeWithConvex = null;
|
|
157
|
+
this.type = ${ShapeType.convexHull};
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
export default class ConvexHull
|
|
161
|
+
extends createClass<ConvexHull, typeof convexHullProps>(convexHullProps, { afterConstructorCode })
|
|
162
|
+
implements ConvexShapeInterface
|
|
163
|
+
{
|
|
164
|
+
declare world: World | null;
|
|
165
|
+
declare shapeNoConvex: ConvexHullNoConvex;
|
|
166
|
+
declare shapeWithConvex: ConvexHullWithConvex;
|
|
167
|
+
declare type: ShapeType.convexHull;
|
|
168
|
+
|
|
169
|
+
computeSupportShape(inMode: SupportMode, inScale: number): SupportShapeWithConvexRadius {
|
|
170
|
+
// If there's no convex radius, we don't need to shrink the hull
|
|
171
|
+
if (this.convexRadius === 0.0) {
|
|
172
|
+
// TODO: implement scale helpers logic
|
|
173
|
+
this.shapeWithConvex.shape = this;
|
|
174
|
+
return this.shapeWithConvex;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
switch (inMode) {
|
|
178
|
+
case SupportMode.IncludeConvexRadius: {
|
|
179
|
+
if (inScale === 1.0) {
|
|
180
|
+
this.shapeWithConvex.shape = this;
|
|
181
|
+
return this.shapeWithConvex;
|
|
182
|
+
} else {
|
|
183
|
+
throw new Error("Not implemented");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
case SupportMode.ExcludeConvexRadius: {
|
|
187
|
+
if (inScale === 1.0) {
|
|
188
|
+
// Create support function
|
|
189
|
+
const hull = this.shapeNoConvex;
|
|
190
|
+
|
|
191
|
+
// #v-ifdef DEV
|
|
192
|
+
// assert
|
|
193
|
+
if (this.points!.length > maxPointsInHull) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Not enough space, this should have been caught during shape creation!, points: ${
|
|
196
|
+
this.points!.length
|
|
197
|
+
}, max: ${maxPointsInHull}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
// #v-endif
|
|
201
|
+
|
|
202
|
+
let numPoints = 0;
|
|
203
|
+
|
|
204
|
+
for (let i = 0; i < this.points!.length; i++) {
|
|
205
|
+
const point = this.points!.getAtIndex(i)!;
|
|
206
|
+
newPoint.zero();
|
|
207
|
+
|
|
208
|
+
if (point.numFaces === 1) {
|
|
209
|
+
// Simply shift back by the convex radius using our 1 plane
|
|
210
|
+
// plane.copyFromList(this.planes, point.faces.x);
|
|
211
|
+
newPoint.addScaledToVector(point.position, this.planes!.getAtIndex(point.faces.x)!.normal, -this.convexRadius);
|
|
212
|
+
} else {
|
|
213
|
+
// Get first two planes and offset inwards by convex radius
|
|
214
|
+
p1.offsetPlaneAlongNormal(this.planes!.getAtIndex(point.faces.x)!, -this.convexRadius);
|
|
215
|
+
p2.offsetPlaneAlongNormal(this.planes!.getAtIndex(point.faces.y)!, -this.convexRadius);
|
|
216
|
+
|
|
217
|
+
if (point.numFaces === 3) {
|
|
218
|
+
// Get third plane and offset inwards by convex radius
|
|
219
|
+
p3.offsetPlaneAlongNormal(this.planes!.getAtIndex(point.faces.z)!, -this.convexRadius);
|
|
220
|
+
} else {
|
|
221
|
+
// Third plane has normal perpendicular to the other two planes and goes through the vertex position
|
|
222
|
+
// #v-ifdef DEV
|
|
223
|
+
// assert
|
|
224
|
+
if (point.numFaces !== 2) {
|
|
225
|
+
throw new Error(`Invalid number of faces: ${point.numFaces}`);
|
|
226
|
+
}
|
|
227
|
+
// #v-endif
|
|
228
|
+
cross_n1_n2.crossVectors(p1.normal, p2.normal);
|
|
229
|
+
p3.fromPointAndNormal(point.position, cross_n1_n2);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Find intersection point between the three planes
|
|
233
|
+
const intersection = Plane.intersectPlanes(p1, p2, p3, newPoint);
|
|
234
|
+
if (!intersection) {
|
|
235
|
+
// Fallback: Just push point back using the first plane
|
|
236
|
+
newPoint.addScaledToVector(point.position, p1.normal, -this.convexRadius);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Add point
|
|
241
|
+
// new_point.pushToList(hull.points);
|
|
242
|
+
hull.points!.getAtIndex(numPoints)!.copy(newPoint);
|
|
243
|
+
numPoints++;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
hull.points!.length = numPoints;
|
|
247
|
+
|
|
248
|
+
return hull;
|
|
249
|
+
} else {
|
|
250
|
+
throw new Error("Not implemented");
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
default: {
|
|
254
|
+
throw new Error(`Invalid support mode: ${inMode}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
computeSupportingFace(
|
|
260
|
+
out: Face,
|
|
261
|
+
subShapeID: number,
|
|
262
|
+
direction: Vec3,
|
|
263
|
+
scale: number,
|
|
264
|
+
centerOfMassTransform: Mat4
|
|
265
|
+
): void {
|
|
266
|
+
out.clear();
|
|
267
|
+
|
|
268
|
+
// scaling is not implemented yet
|
|
269
|
+
if (scale !== 1.0) {
|
|
270
|
+
throw new Error("scaling is not implemented yet");
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// find the plane that has a normal as similar as possible to the search direction vector
|
|
274
|
+
let bestDot = +Infinity;
|
|
275
|
+
let bestFaceIndex = -1;
|
|
276
|
+
for (let i = 0; i < this.planes!.length; i++) {
|
|
277
|
+
const plane = this.planes!.getAtIndex(i)!;
|
|
278
|
+
const dot = plane.normal.dot(direction);
|
|
279
|
+
if (dot < bestDot) {
|
|
280
|
+
bestDot = dot;
|
|
281
|
+
bestFaceIndex = i;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// get the best face
|
|
286
|
+
const face = this.faces!.getAtIndex(bestFaceIndex)!;
|
|
287
|
+
|
|
288
|
+
// TODO: handle inverse scale
|
|
289
|
+
const maxVerticesToReturn = out.buffer!.maxLength / 2;
|
|
290
|
+
const deltaVtx = Math.floor((face.numVertices + maxVerticesToReturn) / maxVerticesToReturn);
|
|
291
|
+
|
|
292
|
+
// TODO: Calculate transform with scale
|
|
293
|
+
for (let i = 0; i < face.numVertices; i += deltaVtx) {
|
|
294
|
+
const index = this.vertexIdx!.getAtIndex(face.firstVertex + i)!;
|
|
295
|
+
const point = this.points!.getAtIndex(index.value)!;
|
|
296
|
+
out.pushVertex(point.position);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// transform the out face to world space
|
|
300
|
+
out.transform(centerOfMassTransform);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
computeInertiaTensor(out: Mat3, mass: number): void {
|
|
304
|
+
out.multiplyMatrixByScalar(this.inertia, mass / this.computedVolume);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
computeInverseInertiaTensor(out: Mat3, mass: number): void {
|
|
308
|
+
this.computeInertiaTensor(out, mass);
|
|
309
|
+
out.invert();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
computeWorldBounds(out: Aabb, translation: Vec3, rotation: Quat) {
|
|
313
|
+
isometry.fromRotationAndTranslation(rotation, translation);
|
|
314
|
+
out.transformAabb(this.computedAabb, isometry);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
createTriangulatedVerticesAndNormalsArray(): [Float32Array, Float32Array] {
|
|
318
|
+
const vertices = [];
|
|
319
|
+
const normals = [];
|
|
320
|
+
// loop over faces
|
|
321
|
+
for (let i = 0; i < this.faces!.length; i++) {
|
|
322
|
+
const face = this.faces!.getAtIndex(i)!;
|
|
323
|
+
const plane = this.planes!.getAtIndex(i)!;
|
|
324
|
+
|
|
325
|
+
for (let j = 1; j < face.numVertices - 1; j++) {
|
|
326
|
+
// Triangle made up of the first vertex, and every subsequent pair
|
|
327
|
+
const indices = [0, j, j + 1];
|
|
328
|
+
for (let k of indices) {
|
|
329
|
+
// Adjusted to use the first vertex and the current pair to form triangles
|
|
330
|
+
const index = this.vertexIdx!.getAtIndex(face.firstVertex + k)!;
|
|
331
|
+
const point = this.points!.getAtIndex(index.value)!;
|
|
332
|
+
|
|
333
|
+
// Add vertex
|
|
334
|
+
vertices.push(point.position.x + this.computedCenterOfMass.x);
|
|
335
|
+
vertices.push(point.position.y + this.computedCenterOfMass.y);
|
|
336
|
+
vertices.push(point.position.z + this.computedCenterOfMass.z);
|
|
337
|
+
|
|
338
|
+
// Add normal (same for all vertices of the face)
|
|
339
|
+
normals.push(plane.normal.x);
|
|
340
|
+
normals.push(plane.normal.y);
|
|
341
|
+
normals.push(plane.normal.z);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return [new Float32Array(vertices), new Float32Array(normals)];
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
computeSurfaceNormal(out: Vec3, inLocalSurfacePosition: Vec3, subShapeId?: number): void {
|
|
350
|
+
const first_plane = this.planes!.getAtIndex(0)!;
|
|
351
|
+
best_normal.set(first_plane.normal);
|
|
352
|
+
let best_dist = Math.abs(first_plane.signedDistance(inLocalSurfacePosition));
|
|
353
|
+
|
|
354
|
+
// Find the face that has the shortest distance to the surface point
|
|
355
|
+
for (let i = 1; i < this.faces!.length; ++i) {
|
|
356
|
+
const plane = this.planes!.getAtIndex(i)!;
|
|
357
|
+
const dist = Math.abs(plane.signedDistance(inLocalSurfacePosition));
|
|
358
|
+
if (dist < best_dist) {
|
|
359
|
+
best_dist = dist;
|
|
360
|
+
best_normal.copy(plane.normal);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
out.copy(best_normal);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
hasChanged() {
|
|
368
|
+
// TODO: we don't currently support changes for this shape
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
commitChanges() {
|
|
373
|
+
if (this.hasChanged()) {
|
|
374
|
+
updateShape(this);
|
|
375
|
+
// this.world?.updateBodyProperties();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const best_normal = /*@__PURE__*/ Vec3.create();
|
|
381
|
+
|
|
382
|
+
function updateVolume(shape: ConvexHull) {
|
|
383
|
+
// recomputing volume for this shape not supported yet
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function updateLocalBounds(shape: ConvexHull) {
|
|
387
|
+
const min = shape.computedAabb.min;
|
|
388
|
+
const max = shape.computedAabb.max;
|
|
389
|
+
|
|
390
|
+
// Set the min and max to the first point
|
|
391
|
+
min.set({ x: +Infinity, y: +Infinity, z: +Infinity });
|
|
392
|
+
max.set({ x: -Infinity, y: -Infinity, z: -Infinity });
|
|
393
|
+
|
|
394
|
+
// Loop over the rest of the points
|
|
395
|
+
for (let i = 0; i < shape.points!.length; i++) {
|
|
396
|
+
const point = shape.points!.getAtIndex(i)!;
|
|
397
|
+
min.x = Math.min(min.x, point.position.x);
|
|
398
|
+
min.y = Math.min(min.y, point.position.y);
|
|
399
|
+
min.z = Math.min(min.z, point.position.z);
|
|
400
|
+
|
|
401
|
+
max.x = Math.max(max.x, point.position.x);
|
|
402
|
+
max.y = Math.max(max.y, point.position.y);
|
|
403
|
+
max.z = Math.max(max.z, point.position.z);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function updateCenterOfMass(shape: ConvexHull) {
|
|
408
|
+
// recomputing center of mass for this shape not supported yet
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function updateCopyForDiff(shape: ConvexHull) {
|
|
412
|
+
if (shape.copyForDiff) {
|
|
413
|
+
shape.copyForDiff.copy(shape);
|
|
414
|
+
shape.copyForDiff.copyForDiff = null;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export function updateShape(shape: ConvexHull) {
|
|
419
|
+
updateCopyForDiff(shape);
|
|
420
|
+
updateCenterOfMass(shape);
|
|
421
|
+
updateVolume(shape);
|
|
422
|
+
updateLocalBounds(shape);
|
|
423
|
+
}
|