@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
package/src/math/quat.ts
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { createClass, NumberType, PropertyDefinitionMap } from "monomorph";
|
|
2
|
+
import { Vec3 } from "./vec3";
|
|
3
|
+
import { Mat3, mat3Keys } from "./mat3";
|
|
4
|
+
import { Mat4 } from "./mat4";
|
|
5
|
+
|
|
6
|
+
export const quatKeys = ["x", "y", "z", "w"] as const;
|
|
7
|
+
|
|
8
|
+
const quatProps = {
|
|
9
|
+
x: NumberType(0.0),
|
|
10
|
+
y: NumberType(0.0),
|
|
11
|
+
z: NumberType(0.0),
|
|
12
|
+
w: NumberType(1.0),
|
|
13
|
+
} as const satisfies PropertyDefinitionMap;
|
|
14
|
+
|
|
15
|
+
export class Quat extends createClass<Quat, typeof quatProps>(quatProps) {
|
|
16
|
+
length() {
|
|
17
|
+
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
normalize() {
|
|
21
|
+
const length = this.length();
|
|
22
|
+
if (length > 0) {
|
|
23
|
+
this.x /= length;
|
|
24
|
+
this.y /= length;
|
|
25
|
+
this.z /= length;
|
|
26
|
+
this.w /= length;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
identity() {
|
|
33
|
+
this.x = 0;
|
|
34
|
+
this.y = 0;
|
|
35
|
+
this.z = 0;
|
|
36
|
+
this.w = 1;
|
|
37
|
+
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
conjugateQuat(a: Quat): Quat {
|
|
42
|
+
this.x = -a.x;
|
|
43
|
+
this.y = -a.y;
|
|
44
|
+
this.z = -a.z;
|
|
45
|
+
this.w = a.w;
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
multiplyQuats(a: Quat, b: Quat): Quat {
|
|
50
|
+
const ax = a.x;
|
|
51
|
+
const ay = a.y;
|
|
52
|
+
const az = a.z;
|
|
53
|
+
const aw = a.w;
|
|
54
|
+
const bx = b.x;
|
|
55
|
+
const by = b.y;
|
|
56
|
+
const bz = b.z;
|
|
57
|
+
const bw = b.w;
|
|
58
|
+
|
|
59
|
+
this.x = ax * bw + aw * bx + ay * bz - az * by;
|
|
60
|
+
this.y = ay * bw + aw * by + az * bx - ax * bz;
|
|
61
|
+
this.z = az * bw + aw * bz + ax * by - ay * bx;
|
|
62
|
+
this.w = aw * bw - ax * bx - ay * by - az * bz;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
normalizeQuat(a: Quat): Quat {
|
|
67
|
+
const x = a.x;
|
|
68
|
+
const y = a.y;
|
|
69
|
+
const z = a.z;
|
|
70
|
+
const w = a.w;
|
|
71
|
+
let len = x * x + y * y + z * z + w * w;
|
|
72
|
+
if (len > 0) {
|
|
73
|
+
len = 1 / Math.sqrt(len);
|
|
74
|
+
}
|
|
75
|
+
this.x = x * len;
|
|
76
|
+
this.y = y * len;
|
|
77
|
+
this.z = z * len;
|
|
78
|
+
this.w = w * len;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setAxisAngle(axis: Vec3, angle: number): Quat {
|
|
83
|
+
angle = angle * 0.5;
|
|
84
|
+
let s = Math.sin(angle);
|
|
85
|
+
this.x = s * axis.x;
|
|
86
|
+
this.y = s * axis.y;
|
|
87
|
+
this.z = s * axis.z;
|
|
88
|
+
this.w = Math.cos(angle);
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
dot(b: Quat) {
|
|
93
|
+
return this.x * b.x + this.y * b.y + this.z * b.z + this.w * b.w;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
notEquals(other: Quat, tolerance: number = 1e-6) {
|
|
97
|
+
return (
|
|
98
|
+
Math.abs(this.x - other.x) >= tolerance ||
|
|
99
|
+
Math.abs(this.y - other.y) >= tolerance ||
|
|
100
|
+
Math.abs(this.z - other.z) >= tolerance ||
|
|
101
|
+
Math.abs(this.w - other.w) >= tolerance
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
equals(other: Quat, tolerance: number = 1e-6) {
|
|
106
|
+
return (
|
|
107
|
+
Math.abs(this.x - other.x) < tolerance &&
|
|
108
|
+
Math.abs(this.y - other.y) < tolerance &&
|
|
109
|
+
Math.abs(this.z - other.z) < tolerance &&
|
|
110
|
+
Math.abs(this.w - other.w) < tolerance
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
intoEuler(out: Vec3) {
|
|
115
|
+
// if rotation angle is small, can use an approximation
|
|
116
|
+
// TODO: handle large angles
|
|
117
|
+
if (this.w < 0) {
|
|
118
|
+
out.x = -this.x * 2;
|
|
119
|
+
out.y = -this.y * 2;
|
|
120
|
+
out.z = -this.z * 2;
|
|
121
|
+
} else {
|
|
122
|
+
out.x = this.x * 2;
|
|
123
|
+
out.y = this.y * 2;
|
|
124
|
+
out.z = this.z * 2;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fromMat3(m: Mat3) {
|
|
131
|
+
// TODO: this will not work with structs due to array indexing
|
|
132
|
+
|
|
133
|
+
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
|
|
134
|
+
// article "Quaternion Calculus and Fast Animation".
|
|
135
|
+
let fTrace = m.e0 + m.e4 + m.e8;
|
|
136
|
+
let fRoot;
|
|
137
|
+
|
|
138
|
+
if (fTrace > 0.0) {
|
|
139
|
+
// |w| > 1/2, may as well choose w > 1/2
|
|
140
|
+
fRoot = Math.sqrt(fTrace + 1.0); // 2w
|
|
141
|
+
this.w = 0.5 * fRoot;
|
|
142
|
+
fRoot = 0.5 / fRoot; // 1/(4w)
|
|
143
|
+
this.x = (m.e5 - m.e7) * fRoot;
|
|
144
|
+
this.y = (m.e6 - m.e2) * fRoot;
|
|
145
|
+
this.z = (m.e1 - m.e3) * fRoot;
|
|
146
|
+
} else {
|
|
147
|
+
// |w| <= 1/2
|
|
148
|
+
let i = 0;
|
|
149
|
+
if (m.e4 > m.e0) i = 1;
|
|
150
|
+
if (m.e8 > m[mat3Keys[i * 3 + i]]) i = 2;
|
|
151
|
+
let j = (i + 1) % 3;
|
|
152
|
+
let k = (i + 2) % 3;
|
|
153
|
+
|
|
154
|
+
fRoot = Math.sqrt(m[mat3Keys[i * 3 + i]] - m[mat3Keys[j * 3 + j]] - m[mat3Keys[k * 3 + k]] + 1.0);
|
|
155
|
+
this[quatKeys[i]] = 0.5 * fRoot;
|
|
156
|
+
fRoot = 0.5 / fRoot;
|
|
157
|
+
this.w = (m[mat3Keys[j * 3 + k]] - m[mat3Keys[k * 3 + j]]) * fRoot;
|
|
158
|
+
this[quatKeys[j]] = (m[mat3Keys[j * 3 + i]] + m[mat3Keys[i * 3 + j]]) * fRoot;
|
|
159
|
+
this[quatKeys[k]] = (m[mat3Keys[k * 3 + i]] + m[mat3Keys[i * 3 + k]]) * fRoot;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
fromMat4(m: Mat4) {
|
|
166
|
+
tempMat3.fromMat4(m);
|
|
167
|
+
this.fromMat3(tempMat3);
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
computeRotationAngle(axis: Vec3) {
|
|
172
|
+
if (this.w === 0.0) {
|
|
173
|
+
return Math.PI;
|
|
174
|
+
} else {
|
|
175
|
+
vector.x = this.x;
|
|
176
|
+
vector.y = this.y;
|
|
177
|
+
vector.z = this.z;
|
|
178
|
+
return 2 * Math.atan(vector.dot(axis) / this.w);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
toObject() {
|
|
183
|
+
return {
|
|
184
|
+
x: this.x,
|
|
185
|
+
y: this.y,
|
|
186
|
+
z: this.z,
|
|
187
|
+
w: this.w,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const vector = /*@__PURE__*/ Vec3.create();
|
|
193
|
+
const tempMat3 = /*@__PURE__*/ Mat3.create();
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export function clamp(value: number, min: number, max: number) {
|
|
2
|
+
return Math.min(Math.max(min, value), max);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function isClose(a: number, b: number, epsilon: number = 1e-10) {
|
|
6
|
+
return Math.abs(a - b) < epsilon;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function squared(value: number) {
|
|
10
|
+
return value * value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function degreesToRadians(degrees: number) {
|
|
14
|
+
return degrees * (Math.PI / 180);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function average(a: number, b: number) {
|
|
18
|
+
return (a + b) * 0.5;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function equals(a: number, b: number, tolerance: number = 1e-6) {
|
|
22
|
+
return Math.abs(a - b) < tolerance;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isPowerOf2(value: number): boolean {
|
|
26
|
+
return Math.log2(value) % 1 === 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const negativeOnePi = -1 * Math.PI;
|
|
30
|
+
export const negativeTwoPi = -2 * Math.PI;
|
|
31
|
+
export const positiveOnePi = +1 * Math.PI;
|
|
32
|
+
export const positiveTwoPi = +2 * Math.PI;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Normalize an angle to be in the interval [-π, +π].
|
|
36
|
+
* - slow for large angles
|
|
37
|
+
* - fast for small angles
|
|
38
|
+
* - guaranteed to return an angle in the interval [-π, +π]
|
|
39
|
+
* - raises an exception for NaN or -/+ Infinity
|
|
40
|
+
*/
|
|
41
|
+
export function normalizeBetweenMinusPiAndPi(angle: number): number {
|
|
42
|
+
if (Number.isFinite(angle) === false) {
|
|
43
|
+
throw new Error(`expected finite angle, got ${angle} instead`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let result = angle;
|
|
47
|
+
|
|
48
|
+
// case: angle is less than -π
|
|
49
|
+
if (angle < negativeOnePi) {
|
|
50
|
+
while (result <= negativeOnePi) {
|
|
51
|
+
result += positiveTwoPi;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// case: angle is greater than +π
|
|
55
|
+
else if (angle > positiveOnePi) {
|
|
56
|
+
while (result >= positiveOnePi) {
|
|
57
|
+
result += negativeTwoPi;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function computeClosestPowersOfTwo(n: number): { previous: number; next: number } {
|
|
65
|
+
if (n < 1) {
|
|
66
|
+
throw new Error("n must be positive");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If n is already a power of two
|
|
70
|
+
if ((n & (n - 1)) === 0) {
|
|
71
|
+
return { previous: n, next: n };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Previous power of two (most significant bit)
|
|
75
|
+
const previous = 1 << Math.floor(Math.log2(n));
|
|
76
|
+
|
|
77
|
+
// Next power of two
|
|
78
|
+
const next = 1 << Math.ceil(Math.log2(n));
|
|
79
|
+
|
|
80
|
+
return { previous, next };
|
|
81
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Mat3 } from "./mat3";
|
|
2
|
+
import { Quat } from "./quat";
|
|
3
|
+
|
|
4
|
+
const normalizedOrientation = /*@__PURE__*/ Quat.create();
|
|
5
|
+
const localToWorldRotation = /*@__PURE__*/ Mat3.create();
|
|
6
|
+
const worldToLocalRotation = /*@__PURE__*/ Mat3.create();
|
|
7
|
+
|
|
8
|
+
export function transformTensor(out: Mat3, tensor: Mat3, orientation: Quat) {
|
|
9
|
+
// create rotation transformation matrices
|
|
10
|
+
normalizedOrientation.normalizeQuat(orientation);
|
|
11
|
+
localToWorldRotation.fromQuat(normalizedOrientation);
|
|
12
|
+
worldToLocalRotation.invertMat3(localToWorldRotation);
|
|
13
|
+
|
|
14
|
+
// transform tensor
|
|
15
|
+
out.multiplyMat3s(localToWorldRotation, tensor);
|
|
16
|
+
out.multiplyMat3s(out, worldToLocalRotation);
|
|
17
|
+
}
|