@perplexdotgg/bounce 1.0.0 → 1.0.1
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/build/bounce.d.ts +39501 -0
- package/build/bounce.js +17166 -0
- package/package.json +1 -1
- package/src/builders/ConvexHullBuilder.ts +0 -437
- package/src/builders/ConvexHullBuilder2d.ts +0 -344
- package/src/builders/ConvexHullBuilder3d.ts +0 -1689
- package/src/builders/HeightMapBuilder.ts +0 -414
- package/src/builders/TriangleMeshBuilder.ts +0 -92
- package/src/collision/CastShapesModule.ts +0 -184
- package/src/collision/CollideShapesModule.ts +0 -152
- package/src/collision/HeightMapCaster.ts +0 -38
- package/src/collision/HeightMapCollider.ts +0 -33
- package/src/collision/TriangleCaster.ts +0 -249
- package/src/collision/TriangleCollider.ts +0 -308
- package/src/collision/TriangleCollider2.ts +0 -379
- package/src/collision/activeEdge.ts +0 -146
- package/src/collision/cast/cast.ts +0 -139
- package/src/collision/cast/castCompoundVsCompound.ts +0 -59
- package/src/collision/cast/castCompoundVsConvex.ts +0 -116
- package/src/collision/cast/castConvexVsCompound.ts +0 -123
- package/src/collision/cast/castConvexVsConvex.ts +0 -213
- package/src/collision/cast/castConvexVsHeightMap.ts +0 -73
- package/src/collision/cast/castConvexVsTriangleMesh.ts +0 -56
- package/src/collision/cast/castRayVsCompound.ts +0 -44
- package/src/collision/cast/castRayVsConvex.ts +0 -45
- package/src/collision/cast/castRayVsHeightMap.ts +0 -58
- package/src/collision/cast/castRayVsTriangleMesh.ts +0 -58
- package/src/collision/closestPoints/closestPoints.ts +0 -23
- package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +0 -32
- package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +0 -81
- package/src/collision/closestPoints/computeClosestPointOnLine.ts +0 -30
- package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +0 -96
- package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +0 -195
- package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +0 -25
- package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +0 -72
- package/src/collision/collide/collide.ts +0 -146
- package/src/collision/collide/collideCompoundVsCompound.ts +0 -60
- package/src/collision/collide/collideCompoundVsConvex.ts +0 -59
- package/src/collision/collide/collideCompoundVsHeightMap.ts +0 -73
- package/src/collision/collide/collideCompoundVsTriangleMesh.ts +0 -56
- package/src/collision/collide/collideConvexVsCompound.ts +0 -57
- package/src/collision/collide/collideConvexVsConvex.ts +0 -225
- package/src/collision/collide/collideConvexVsConvexImp.ts +0 -236
- package/src/collision/collide/collideConvexVsHeightMap.ts +0 -53
- package/src/collision/collide/collideConvexVsTriangleMesh.ts +0 -58
- package/src/collision/collide/collideHeightMapVsCompound.ts +0 -69
- package/src/collision/collide/collideHeightMapVsConvex.ts +0 -53
- package/src/collision/collide/collideSphereVsSphere.ts +0 -81
- package/src/collision/collide/collideTriangleMeshVsCompound.ts +0 -58
- package/src/collision/collide/collideTriangleMeshVsConvex.ts +0 -58
- package/src/collision/epa/EpaConvexHullBuilder.ts +0 -397
- package/src/collision/epa/StaticArray.ts +0 -154
- package/src/collision/epa/TriangleFactory.ts +0 -32
- package/src/collision/epa/arrays.ts +0 -99
- package/src/collision/epa/binaryHeap.ts +0 -82
- package/src/collision/epa/structs.ts +0 -227
- package/src/collision/gjk/GjkModule.ts +0 -864
- package/src/collision/gjk/PenetrationDepthModule.ts +0 -493
- package/src/collision/gjk/SupportPoints.ts +0 -50
- package/src/collision/imp/MinkowskiDifference.ts +0 -36
- package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +0 -40
- package/src/collision/imp/finalizeImpResult.ts +0 -69
- package/src/collision/imp/findContactImp.ts +0 -196
- package/src/collision/imp/imp.ts +0 -28
- package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +0 -207
- package/src/collision/mpr/findPortal.ts +0 -152
- package/src/collision/mpr/mpr.ts +0 -29
- package/src/collision/mpr/updatePortal.ts +0 -52
- package/src/constraints/BaseConstraint.ts +0 -50
- package/src/constraints/ConstraintOptions.ts +0 -22
- package/src/constraints/ConstraintSolver.ts +0 -119
- package/src/constraints/DistanceConstraint.ts +0 -229
- package/src/constraints/FixedConstraint.ts +0 -203
- package/src/constraints/HingeConstraint.ts +0 -460
- package/src/constraints/PointConstraint.ts +0 -108
- package/src/constraints/components/AngleComponent.ts +0 -226
- package/src/constraints/components/AxisComponent.ts +0 -263
- package/src/constraints/components/HingeComponent.ts +0 -215
- package/src/constraints/components/Motor.ts +0 -36
- package/src/constraints/components/PointConstraintComponent.ts +0 -179
- package/src/constraints/components/RotationEulerComponent.ts +0 -139
- package/src/constraints/components/Spring.ts +0 -30
- package/src/constraints/components/SpringComponent.ts +0 -71
- package/src/constraints/types.ts +0 -6
- package/src/helpers.ts +0 -147
- package/src/index.ts +0 -50
- package/src/math/BasicTransform.ts +0 -19
- package/src/math/NumberValue.ts +0 -13
- package/src/math/isometry.ts +0 -64
- package/src/math/mat3.ts +0 -529
- package/src/math/mat4.ts +0 -588
- package/src/math/quat.ts +0 -193
- package/src/math/scalar.ts +0 -81
- package/src/math/tensor.ts +0 -17
- package/src/math/vec3.ts +0 -589
- package/src/math/vec4.ts +0 -10
- package/src/physics/Body.ts +0 -581
- package/src/physics/CollisionFilter.ts +0 -52
- package/src/physics/SleepModule.ts +0 -163
- package/src/physics/broadphase/BodyPairsModule.ts +0 -363
- package/src/physics/broadphase/BvhModule.ts +0 -237
- package/src/physics/broadphase/BvhTree.ts +0 -803
- package/src/physics/broadphase/ConstraintPairsModule.ts +0 -385
- package/src/physics/broadphase/TriangleMeshBvhTree.ts +0 -379
- package/src/physics/manifold/ContactManifold.ts +0 -227
- package/src/physics/manifold/ContactManifoldModule.ts +0 -623
- package/src/physics/manifold/Face.ts +0 -119
- package/src/physics/manifold/ManifoldCache.ts +0 -116
- package/src/physics/manifold/clipping/clipPolyVsEdge.ts +0 -131
- package/src/physics/manifold/clipping/clipPolyVsPlane.ts +0 -73
- package/src/physics/manifold/clipping/clipPolyVsPoly.ts +0 -72
- package/src/physics/narrowphase/CollideBodiesModule.ts +0 -755
- package/src/physics/solver/ContactConstraintModule.ts +0 -659
- package/src/physics/solver/ManifoldConstraint.ts +0 -420
- package/src/physics/solver/estimateCollisionResponse.ts +0 -146
- package/src/shape/Aabb.ts +0 -400
- package/src/shape/Box.ts +0 -231
- package/src/shape/Capsule.ts +0 -332
- package/src/shape/CompoundShape.ts +0 -288
- package/src/shape/Convex.ts +0 -130
- package/src/shape/ConvexHull.ts +0 -423
- package/src/shape/Cylinder.ts +0 -313
- package/src/shape/HeightMap.ts +0 -511
- package/src/shape/Line.ts +0 -14
- package/src/shape/Plane.ts +0 -116
- package/src/shape/Ray.ts +0 -81
- package/src/shape/Segment.ts +0 -25
- package/src/shape/Shape.ts +0 -77
- package/src/shape/Sphere.ts +0 -181
- package/src/shape/TransformedShape.ts +0 -51
- package/src/shape/Triangle.ts +0 -122
- package/src/shape/TriangleMesh.ts +0 -186
- package/src/types.ts +0 -1
- package/src/world.ts +0 -1335
package/src/shape/HeightMap.ts
DELETED
|
@@ -1,511 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createClass,
|
|
3
|
-
LazyReferenceType,
|
|
4
|
-
MonomorphType,
|
|
5
|
-
NumberType,
|
|
6
|
-
PropertyDefinitionMap,
|
|
7
|
-
PropertyDefinitionReference,
|
|
8
|
-
} from "monomorph";
|
|
9
|
-
import { ShapeCollectionInterface, ShapeType } from "./Shape";
|
|
10
|
-
import { Face } from "../physics/manifold/Face";
|
|
11
|
-
import { Mat4 } from "../math/mat4";
|
|
12
|
-
import { Mat3 } from "../math/mat3";
|
|
13
|
-
import { Aabb } from "./Aabb";
|
|
14
|
-
import { Vec3 } from "../math/vec3";
|
|
15
|
-
import { Triangle } from "./Triangle";
|
|
16
|
-
import { Isometry } from "../math/isometry";
|
|
17
|
-
import { Quat } from "../math/quat";
|
|
18
|
-
import { Tuple4 } from "../types";
|
|
19
|
-
import type { World } from "../world";
|
|
20
|
-
import { Ray } from "./Ray";
|
|
21
|
-
|
|
22
|
-
export interface HeightMapVisitor {
|
|
23
|
-
shouldVisitBlock(block: Aabb): boolean;
|
|
24
|
-
visitTriangle(triangle: Triangle, activeEdges: number, triangleId: number): void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
class HeightMapRaycaster implements HeightMapVisitor {
|
|
28
|
-
declare ray: Ray;
|
|
29
|
-
declare onHit: (triangle: Triangle) => boolean;
|
|
30
|
-
|
|
31
|
-
init(onHit: (triangle: Triangle) => boolean, ray: Ray): void {
|
|
32
|
-
this.ray = ray;
|
|
33
|
-
this.onHit = onHit;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
shouldVisitBlock(block: Aabb): boolean {
|
|
37
|
-
return this.ray.intersectsAabb(block);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
visitTriangle(triangle: Triangle, activeEdges: number, triangleId: number): void {
|
|
41
|
-
this.onHit(triangle);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const heightMapRaycaster = /*@__PURE__*/ new HeightMapRaycaster();
|
|
46
|
-
|
|
47
|
-
export function computeNumberOfLevels(numberOfSubdivisions: number): number {
|
|
48
|
-
return Math.log2(numberOfSubdivisions) + 1;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function computeNumberOfCells(numberOfSubdivisions: number): number {
|
|
52
|
-
let numberOfCells = 0;
|
|
53
|
-
let currentNumberOfSubdivisions = numberOfSubdivisions;
|
|
54
|
-
|
|
55
|
-
while (currentNumberOfSubdivisions >= 1) {
|
|
56
|
-
numberOfCells += currentNumberOfSubdivisions ** 2;
|
|
57
|
-
currentNumberOfSubdivisions = currentNumberOfSubdivisions / 2;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return numberOfCells;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function computeCornerIndicesInGrid(out: Tuple4<number>, x: number, z: number, stride: number): void {
|
|
64
|
-
const bottomLeft = x * stride + z;
|
|
65
|
-
const bottomRight = bottomLeft + 1;
|
|
66
|
-
const topLeft = bottomLeft + stride;
|
|
67
|
-
const topRight = topLeft + 1;
|
|
68
|
-
|
|
69
|
-
out[0] = bottomLeft;
|
|
70
|
-
out[1] = bottomRight;
|
|
71
|
-
out[2] = topLeft;
|
|
72
|
-
out[3] = topRight;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const triangle = /*@__PURE__*/ Triangle.create();
|
|
76
|
-
const isometry = /*@__PURE__*/ Isometry.create();
|
|
77
|
-
const interpolatedPoint = /*@__PURE__*/ Vec3.create();
|
|
78
|
-
const a = /*@__PURE__*/ Vec3.create();
|
|
79
|
-
const b = /*@__PURE__*/ Vec3.create();
|
|
80
|
-
const c = /*@__PURE__*/ Vec3.create();
|
|
81
|
-
const d = /*@__PURE__*/ Vec3.create();
|
|
82
|
-
const scale = /*@__PURE__*/ Vec3.create();
|
|
83
|
-
const blockAabb = /*@__PURE__*/ Aabb.create();
|
|
84
|
-
const normal = /*@__PURE__*/ Vec3.create();
|
|
85
|
-
|
|
86
|
-
const heightMapProps = {
|
|
87
|
-
computedCenterOfMass: MonomorphType(Vec3, undefined, true),
|
|
88
|
-
computedVolume: NumberType(0.0, true),
|
|
89
|
-
computedAabb: MonomorphType(Aabb, {}, true),
|
|
90
|
-
copyForDiff: LazyReferenceType((() => HeightMap) as () => never) as PropertyDefinitionReference<
|
|
91
|
-
HeightMap | null,
|
|
92
|
-
true
|
|
93
|
-
>,
|
|
94
|
-
subdivisionsCount: NumberType(0),
|
|
95
|
-
scale: MonomorphType(Vec3),
|
|
96
|
-
positionOffset: MonomorphType(Vec3),
|
|
97
|
-
// heights: PoolReferenceType(Vec1),
|
|
98
|
-
// minHeights: PoolReferenceType(Vec1),
|
|
99
|
-
// maxHeights: PoolReferenceType(Vec1),
|
|
100
|
-
// levels: PoolReferenceType(Vec1),
|
|
101
|
-
// activeEdges: PoolReferenceType(Vec1),
|
|
102
|
-
} as const satisfies PropertyDefinitionMap;
|
|
103
|
-
|
|
104
|
-
const afterConstructorCode = `
|
|
105
|
-
this.world = null;
|
|
106
|
-
this.heights = [];
|
|
107
|
-
this.minHeights = [];
|
|
108
|
-
this.maxHeights = [];
|
|
109
|
-
this.levels = [];
|
|
110
|
-
this.activeEdges = [];
|
|
111
|
-
this.stack = [];
|
|
112
|
-
this.children = [0, 0, 0, 0];
|
|
113
|
-
`;
|
|
114
|
-
|
|
115
|
-
export class HeightMap
|
|
116
|
-
extends createClass<HeightMap, typeof heightMapProps>(heightMapProps, { afterConstructorCode })
|
|
117
|
-
implements ShapeCollectionInterface
|
|
118
|
-
{
|
|
119
|
-
type: ShapeType.heightMap = ShapeType.heightMap;
|
|
120
|
-
|
|
121
|
-
declare world: World | null;
|
|
122
|
-
declare heights: number[];
|
|
123
|
-
declare minHeights: number[];
|
|
124
|
-
declare maxHeights: number[];
|
|
125
|
-
declare levels: number[];
|
|
126
|
-
declare activeEdges: number[];
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* a stack to hold the indices of the blocks to visit during when walking the heightMap
|
|
130
|
-
*/
|
|
131
|
-
declare stack: Array<number>;
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* a stack to hold the indices of the children of the current block when walking the heightMap
|
|
135
|
-
*/
|
|
136
|
-
declare children: Tuple4<number>;
|
|
137
|
-
|
|
138
|
-
computeSupportingFace(
|
|
139
|
-
out: Face,
|
|
140
|
-
subShapeID: number,
|
|
141
|
-
direction: Vec3,
|
|
142
|
-
scale: number,
|
|
143
|
-
centerOfMassTransform: Mat4
|
|
144
|
-
): void {
|
|
145
|
-
// get the triangle
|
|
146
|
-
|
|
147
|
-
this.computeTriangle(triangle, subShapeID);
|
|
148
|
-
|
|
149
|
-
// TODO: flip the triangle if scaled inside out
|
|
150
|
-
|
|
151
|
-
// TODO: prescale the transform
|
|
152
|
-
|
|
153
|
-
// transform to world space
|
|
154
|
-
triangle.transform(centerOfMassTransform);
|
|
155
|
-
|
|
156
|
-
// push world space triangle vertices to face
|
|
157
|
-
out.pushVertex(triangle.a);
|
|
158
|
-
out.pushVertex(triangle.b);
|
|
159
|
-
out.pushVertex(triangle.c);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
computeInverseInertiaTensor(out: Mat3, mass: number): void {
|
|
163
|
-
out.zero();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
computeWorldBounds(out: Aabb, translation: Vec3, rotation: Quat): void {
|
|
167
|
-
isometry.fromRotationAndTranslation(rotation, translation);
|
|
168
|
-
out.transformAabb(this.computedAabb, isometry);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
computeInterpolatedHeight(localPosition: Vec3): number {
|
|
172
|
-
this.computeInterpolatedLocalPoint(interpolatedPoint, localPosition);
|
|
173
|
-
return interpolatedPoint.y;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
computeInterpolatedLocalPoint(out: Vec3, localPosition: Vec3): void {
|
|
177
|
-
// TODO: clamp the local position?
|
|
178
|
-
const localPositionZ = localPosition.z;
|
|
179
|
-
const localPositionX = localPosition.x;
|
|
180
|
-
|
|
181
|
-
// get grid cell
|
|
182
|
-
let columnIndex = Math.floor((localPositionZ - this.positionOffset.z) / this.scale.z);
|
|
183
|
-
let rowIndex = Math.floor((localPositionX - this.positionOffset.x) / this.scale.x);
|
|
184
|
-
|
|
185
|
-
// if either of the indices are out of bounds (< 0, or > subdivisionsCount), we return the local position as is
|
|
186
|
-
if (
|
|
187
|
-
columnIndex < 0 ||
|
|
188
|
-
columnIndex >= this.subdivisionsCount ||
|
|
189
|
-
rowIndex < 0 ||
|
|
190
|
-
rowIndex >= this.subdivisionsCount
|
|
191
|
-
) {
|
|
192
|
-
out.copy(localPosition);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// get the local position within the cell
|
|
197
|
-
let normalizedZ = (localPositionZ - this.positionOffset.z) / this.scale.z - columnIndex;
|
|
198
|
-
let normalizedX = (localPositionX - this.positionOffset.x) / this.scale.x - rowIndex;
|
|
199
|
-
|
|
200
|
-
// get the quad vertices
|
|
201
|
-
|
|
202
|
-
this.computeVertex(a, columnIndex + 0, rowIndex + 0); // bottom left
|
|
203
|
-
this.computeVertex(b, columnIndex + 1, rowIndex + 0); // bottom right
|
|
204
|
-
this.computeVertex(c, columnIndex + 0, rowIndex + 1); // top left
|
|
205
|
-
this.computeVertex(d, columnIndex + 1, rowIndex + 1); // top right
|
|
206
|
-
|
|
207
|
-
// we will use barycentric coordinates to get the height of the point
|
|
208
|
-
let interpolatedHeight: number;
|
|
209
|
-
|
|
210
|
-
// case: we project onto triangle ABC
|
|
211
|
-
if (normalizedX + normalizedZ <= 1) {
|
|
212
|
-
const u = normalizedZ;
|
|
213
|
-
const v = normalizedX;
|
|
214
|
-
const w = 1 - u - v;
|
|
215
|
-
interpolatedHeight = a.y * w + b.y * u + c.y * v;
|
|
216
|
-
}
|
|
217
|
-
// case: we project onto triangle DCB
|
|
218
|
-
else {
|
|
219
|
-
const u = 1 - normalizedZ;
|
|
220
|
-
const v = 1 - normalizedX;
|
|
221
|
-
const w = 1 - u - v;
|
|
222
|
-
interpolatedHeight = d.y * w + c.y * u + b.y * v;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// set the out point
|
|
226
|
-
out.x = localPositionX;
|
|
227
|
-
out.y = interpolatedHeight;
|
|
228
|
-
out.z = localPositionZ;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
castRay(onHit: (triangle: Triangle) => boolean, ray: Ray) {
|
|
232
|
-
heightMapRaycaster.init(onHit, ray);
|
|
233
|
-
this.walkHeightMap(heightMapRaycaster);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
walkHeightMap(visitor: HeightMapVisitor): void {
|
|
237
|
-
// get a stack to hold the indices of the blocks to visit
|
|
238
|
-
const stack = this.stack;
|
|
239
|
-
stack.length = 0;
|
|
240
|
-
let stackCount = 0;
|
|
241
|
-
let triangleId: number;
|
|
242
|
-
|
|
243
|
-
const children = this.children;
|
|
244
|
-
children.fill(0);
|
|
245
|
-
|
|
246
|
-
// add the index of the root block
|
|
247
|
-
stack[stackCount] = 0;
|
|
248
|
-
stackCount++;
|
|
249
|
-
|
|
250
|
-
// TODO: this can be cached
|
|
251
|
-
const numberOfLevels = computeNumberOfLevels(this.subdivisionsCount);
|
|
252
|
-
|
|
253
|
-
// iterate until the stack is empty
|
|
254
|
-
while (stackCount > 0) {
|
|
255
|
-
// visit the block at the top of the stack
|
|
256
|
-
stackCount--;
|
|
257
|
-
|
|
258
|
-
const index = stack[stackCount];
|
|
259
|
-
const level = this.levels[index];
|
|
260
|
-
const minHeight = this.positionOffset.y + this.minHeights[index] * this.scale.y;
|
|
261
|
-
const maxHeight = this.positionOffset.y + this.maxHeights[index] * this.scale.y;
|
|
262
|
-
// const currentNumberOfSubDivisions = Math.pow(2, level);
|
|
263
|
-
const currentNumberOfSubDivisions = 1 << level;
|
|
264
|
-
|
|
265
|
-
// get the scale at this level, which would be doubled for each level underneath
|
|
266
|
-
const numberOfLevelsBelow = numberOfLevels - level - 1;
|
|
267
|
-
// vec3.scale(scale, this.scale, Math.pow(2, numberOfLevelsBelow));
|
|
268
|
-
scale.scaleVector(this.scale, 1 << numberOfLevelsBelow);
|
|
269
|
-
|
|
270
|
-
// if at base level, row and column index are zero
|
|
271
|
-
let rowIndex: number = 0;
|
|
272
|
-
let columnIndex: number = 0;
|
|
273
|
-
if (level > 0) {
|
|
274
|
-
// get the offset of the upper level
|
|
275
|
-
const offset = computeNumberOfCells(currentNumberOfSubDivisions / 2);
|
|
276
|
-
|
|
277
|
-
const indexWithoutOffset = index - offset;
|
|
278
|
-
|
|
279
|
-
// get the row and column index of the block
|
|
280
|
-
rowIndex = Math.floor(indexWithoutOffset / currentNumberOfSubDivisions);
|
|
281
|
-
// columnIndex = indexWithoutOffset % currentNumberOfSubDivisions;
|
|
282
|
-
columnIndex = indexWithoutOffset & (currentNumberOfSubDivisions - 1);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// get the min x and min z position of the block
|
|
286
|
-
const minX = this.positionOffset.x + rowIndex * scale.x;
|
|
287
|
-
const minZ = this.positionOffset.z + columnIndex * scale.z;
|
|
288
|
-
|
|
289
|
-
// get the max x and max z position of the block
|
|
290
|
-
const maxX = minX + scale.x;
|
|
291
|
-
const maxZ = minZ + scale.z;
|
|
292
|
-
|
|
293
|
-
// create the aabb for the block
|
|
294
|
-
|
|
295
|
-
blockAabb.min.fromArray([minX, minHeight, minZ]);
|
|
296
|
-
blockAabb.max.fromArray([maxX, maxHeight, maxZ]);
|
|
297
|
-
// expand the block aabb height by a small margin to account for flat planes
|
|
298
|
-
blockAabb.min.y -= 0.1;
|
|
299
|
-
blockAabb.max.y += 0.1;
|
|
300
|
-
|
|
301
|
-
// case: we should not visit the block, skip
|
|
302
|
-
if (visitor.shouldVisitBlock(blockAabb) === false) {
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
// case: we should visit the block, get this block's children (blocks if not on last level, triangles if on last level)
|
|
306
|
-
else {
|
|
307
|
-
// case: on last level
|
|
308
|
-
if (level === numberOfLevels - 1) {
|
|
309
|
-
// console.log("visiting block", index - getNumberOfCells(currentNumberOfSubDivisions / 2));
|
|
310
|
-
|
|
311
|
-
// get the 4 vertices of the quad
|
|
312
|
-
this.computeVertex(a, columnIndex + 0, rowIndex + 0); // bottom left
|
|
313
|
-
this.computeVertex(b, columnIndex + 1, rowIndex + 0); // bottom right
|
|
314
|
-
this.computeVertex(c, columnIndex + 0, rowIndex + 1); // top left
|
|
315
|
-
this.computeVertex(d, columnIndex + 1, rowIndex + 1); // top right
|
|
316
|
-
|
|
317
|
-
// get the activeEdges for each triangle
|
|
318
|
-
const firstTriangleIndex = index * 2 + 0;
|
|
319
|
-
const secondTriangleIndex = index * 2 + 1;
|
|
320
|
-
|
|
321
|
-
const activeEdges0 = this.activeEdges[firstTriangleIndex];
|
|
322
|
-
const activeEdges1 = this.activeEdges[secondTriangleIndex];
|
|
323
|
-
|
|
324
|
-
// visit the 2 triangles in the quad
|
|
325
|
-
triangle.set({ a: a, b: b, c: c });
|
|
326
|
-
triangleId = this.computeTriangleId(columnIndex, rowIndex, 0);
|
|
327
|
-
// if (this.world.debug) {
|
|
328
|
-
// console.log("visiting triangle", { columnIndex, rowIndex, triangleIndex: 0, triangleId });
|
|
329
|
-
// }
|
|
330
|
-
visitor.visitTriangle(triangle, activeEdges0, triangleId);
|
|
331
|
-
|
|
332
|
-
triangle.set({ a: d, b: c, c: b });
|
|
333
|
-
triangleId = this.computeTriangleId(columnIndex, rowIndex, 1);
|
|
334
|
-
// if (this.world.debug) {
|
|
335
|
-
// console.log("visiting triangle", { columnIndex, rowIndex, triangleIndex: 1, triangleId });
|
|
336
|
-
// }
|
|
337
|
-
visitor.visitTriangle(triangle, activeEdges1, triangleId);
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// case: not on last level
|
|
342
|
-
|
|
343
|
-
// get the children of the block
|
|
344
|
-
computeCornerIndicesInGrid(children, rowIndex * 2, columnIndex * 2, currentNumberOfSubDivisions * 2);
|
|
345
|
-
|
|
346
|
-
// get the starting offset of the children
|
|
347
|
-
const offset = computeNumberOfCells(currentNumberOfSubDivisions);
|
|
348
|
-
|
|
349
|
-
// add the children to the stack
|
|
350
|
-
stack[stackCount] = children[3] + offset;
|
|
351
|
-
stackCount++;
|
|
352
|
-
|
|
353
|
-
stack[stackCount] = children[2] + offset;
|
|
354
|
-
stackCount++;
|
|
355
|
-
|
|
356
|
-
stack[stackCount] = children[1] + offset;
|
|
357
|
-
stackCount++;
|
|
358
|
-
|
|
359
|
-
stack[stackCount] = children[0] + offset;
|
|
360
|
-
stackCount++;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* this function visits every block and triangle of the heightMap. take care when using it on high resolution heightMaps. it is intended to generate a debug visualization of the heightMap.
|
|
367
|
-
*/
|
|
368
|
-
createTriangulatedVerticesAndNormalsArray(): [Float64Array, Float64Array] {
|
|
369
|
-
// performance is not a concern for this function, so we can make new allocations here
|
|
370
|
-
|
|
371
|
-
const vertices: number[] = [];
|
|
372
|
-
const normals: number[] = [];
|
|
373
|
-
|
|
374
|
-
class MyVisitor implements HeightMapVisitor {
|
|
375
|
-
shouldVisitBlock(block: Aabb): boolean {
|
|
376
|
-
return true;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
visitTriangle(triangle: Triangle, activeEdges: number, triangleId: number): void {
|
|
380
|
-
triangle.computeNormal(normal);
|
|
381
|
-
|
|
382
|
-
vertices.push(triangle.a.x, triangle.a.y, triangle.a.z);
|
|
383
|
-
vertices.push(triangle.b.x, triangle.b.y, triangle.b.z);
|
|
384
|
-
vertices.push(triangle.c.x, triangle.c.y, triangle.c.z);
|
|
385
|
-
|
|
386
|
-
normals.push(normal.x, normal.y, normal.z);
|
|
387
|
-
normals.push(normal.x, normal.y, normal.z);
|
|
388
|
-
normals.push(normal.x, normal.y, normal.z);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
const visitor = new MyVisitor();
|
|
392
|
-
|
|
393
|
-
this.walkHeightMap(visitor);
|
|
394
|
-
return [new Float64Array(vertices), new Float64Array(normals)];
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
computeSurfaceNormal(out: Vec3, inLocalSurfacePosition: Vec3, subShapeId?: number): void {
|
|
398
|
-
// #v-ifdef DEV
|
|
399
|
-
// assert that we have a sub shape id
|
|
400
|
-
if (subShapeId === undefined) {
|
|
401
|
-
throw new Error("subShapeId is required");
|
|
402
|
-
}
|
|
403
|
-
// #v-endif
|
|
404
|
-
|
|
405
|
-
this.computeTriangle(triangle, subShapeId);
|
|
406
|
-
triangle.computeSurfaceNormal(out, inLocalSurfacePosition);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
computeColumnCount(): number {
|
|
410
|
-
return this.subdivisionsCount + 1;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
computeRowCount(): number {
|
|
414
|
-
return this.subdivisionsCount + 1;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
computeTriangleId(columnIndex: number, rowIndex: number, triangleIndex: 0 | 1): number {
|
|
418
|
-
return ((rowIndex * this.computeColumnCount() + columnIndex) << 1) | triangleIndex;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
decodeTriangleId(triangleId: number): { columnIndex: number; rowIndex: number; triangleIndex: number } {
|
|
422
|
-
const triangleIndex = triangleId & 1;
|
|
423
|
-
const quadId = triangleId >> 1;
|
|
424
|
-
const columnIndex = quadId % this.computeColumnCount();
|
|
425
|
-
const rowIndex = Math.floor(quadId / this.computeColumnCount());
|
|
426
|
-
return { columnIndex, rowIndex, triangleIndex };
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
computeTriangle(out: Triangle, triangleId: number): void {
|
|
430
|
-
const { columnIndex, rowIndex, triangleIndex } = this.decodeTriangleId(triangleId);
|
|
431
|
-
|
|
432
|
-
this.computeVertex(a, columnIndex + 0, rowIndex + 0); // bottom left
|
|
433
|
-
this.computeVertex(b, columnIndex + 1, rowIndex + 0); // bottom right
|
|
434
|
-
this.computeVertex(c, columnIndex + 0, rowIndex + 1); // top left
|
|
435
|
-
this.computeVertex(d, columnIndex + 1, rowIndex + 1); // top right
|
|
436
|
-
|
|
437
|
-
if (triangleIndex === 0) {
|
|
438
|
-
out.set({ a: a, b: b, c: c });
|
|
439
|
-
} else {
|
|
440
|
-
out.set({ a: d, b: c, c: b });
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
computeVertex(out: Vec3, columnIndex: number, rowIndex: number): void {
|
|
445
|
-
out.z = this.positionOffset.z + columnIndex * this.scale.z;
|
|
446
|
-
out.x = this.positionOffset.x + rowIndex * this.scale.x;
|
|
447
|
-
out.y = this.positionOffset.y + this.heights[columnIndex + rowIndex * (this.subdivisionsCount + 1)] * this.scale.y;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
hasChanged() {
|
|
451
|
-
// TODO: we don't currently support changes for this shape
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
commitChanges() {
|
|
456
|
-
if (this.hasChanged()) {
|
|
457
|
-
updateShape(this);
|
|
458
|
-
// this.world?.updateBodyProperties();
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function updateVolume(shape: HeightMap) {
|
|
464
|
-
shape.computedVolume = 0.0;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
export function updateLocalBounds(shape: HeightMap) {
|
|
468
|
-
// find the min and max height
|
|
469
|
-
let minHeight = Number.POSITIVE_INFINITY;
|
|
470
|
-
let maxHeight = Number.NEGATIVE_INFINITY;
|
|
471
|
-
for (let i = 0; i < shape.heights.length; i++) {
|
|
472
|
-
const height = shape.heights[i] * shape.scale.y;
|
|
473
|
-
minHeight = Math.min(minHeight, height);
|
|
474
|
-
maxHeight = Math.max(maxHeight, height);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// set the local bounds
|
|
478
|
-
shape.computedAabb.min.x = 0;
|
|
479
|
-
// TODO: apply scale?
|
|
480
|
-
// out.min.y = shape.scale * minHeight;
|
|
481
|
-
shape.computedAabb.min.y = minHeight;
|
|
482
|
-
shape.computedAabb.min.z = 0;
|
|
483
|
-
|
|
484
|
-
shape.computedAabb.max.x = shape.subdivisionsCount * shape.scale.x;
|
|
485
|
-
// TODO: apply scale?
|
|
486
|
-
// out.max.y = shape.scale * maxHeight;
|
|
487
|
-
shape.computedAabb.max.y = maxHeight;
|
|
488
|
-
shape.computedAabb.max.z = shape.subdivisionsCount * shape.scale.z;
|
|
489
|
-
|
|
490
|
-
// account for the position offset
|
|
491
|
-
shape.computedAabb.min.addVector(shape.positionOffset);
|
|
492
|
-
shape.computedAabb.max.addVector(shape.positionOffset);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function updateCopyForDiff(shape: HeightMap) {
|
|
496
|
-
if (shape.copyForDiff) {
|
|
497
|
-
shape.copyForDiff.copy(shape);
|
|
498
|
-
shape.copyForDiff.copyForDiff = null;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function updateCenterOfMass(shape: HeightMap) {
|
|
503
|
-
shape.computedCenterOfMass.zero();
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
export function updateShape(shape: HeightMap) {
|
|
507
|
-
updateCopyForDiff(shape);
|
|
508
|
-
updateCenterOfMass(shape);
|
|
509
|
-
updateVolume(shape);
|
|
510
|
-
updateLocalBounds(shape);
|
|
511
|
-
}
|
package/src/shape/Line.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { createClass, MonomorphType, PropertyDefinitionMap } from "monomorph";
|
|
2
|
-
import { Vec3 } from "../math/vec3";
|
|
3
|
-
|
|
4
|
-
const lineProps = {
|
|
5
|
-
a: MonomorphType(Vec3),
|
|
6
|
-
b: MonomorphType(Vec3),
|
|
7
|
-
} as const satisfies PropertyDefinitionMap;
|
|
8
|
-
|
|
9
|
-
export class Line extends createClass<Line, typeof lineProps>(lineProps) {
|
|
10
|
-
setFromPointAndDirection(point: Vec3, direction: Vec3, length: number): void {
|
|
11
|
-
this.a.copy(point);
|
|
12
|
-
this.b.addScaledToVector(point, direction, length);
|
|
13
|
-
}
|
|
14
|
-
}
|
package/src/shape/Plane.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { createClass, MonomorphType, NumberType, PropertyDefinitionMap } from "monomorph";
|
|
2
|
-
import { Vec3 } from "../math/vec3";
|
|
3
|
-
import { Ray } from "./Ray";
|
|
4
|
-
|
|
5
|
-
const cross_bn_cn = /*@__PURE__*/ Vec3.create();
|
|
6
|
-
|
|
7
|
-
const planeProps = {
|
|
8
|
-
normal: MonomorphType(Vec3),
|
|
9
|
-
constant: NumberType(0),
|
|
10
|
-
} as const satisfies PropertyDefinitionMap;
|
|
11
|
-
|
|
12
|
-
export class Plane extends createClass<Plane, typeof planeProps>(planeProps) {
|
|
13
|
-
toObject() {
|
|
14
|
-
return {
|
|
15
|
-
normal: this.normal.toObject(),
|
|
16
|
-
constant: this.constant,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fromPointAndNormal(point: Vec3, normal: Vec3): void {
|
|
21
|
-
this.normal.copy(normal);
|
|
22
|
-
this.constant = -normal.dot(point);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
signedDistance(point: Vec3): number {
|
|
26
|
-
return point.dot(this.normal) + this.constant;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
offsetAlongNormal(out: Plane, inDistance: number): void {
|
|
30
|
-
out.copy(this);
|
|
31
|
-
out.constant -= inDistance;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
offsetPlaneAlongNormal(plane: Plane, inDistance: number) {
|
|
35
|
-
this.normal.copy(plane.normal);
|
|
36
|
-
this.constant = plane.constant - inDistance;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
toString(): string {
|
|
40
|
-
return `Plane { normal: ${this.normal.toString()}, constant: ${this.constant} }`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static intersectPlanes(planeA: Plane, planeB: Plane, planeC: Plane, outPoint: Vec3): boolean {
|
|
44
|
-
// We solve the equation:
|
|
45
|
-
// |ax, ay, az, aw| | x | | 0 |
|
|
46
|
-
// |bx, by, bz, bw| * | y | = | 0 |
|
|
47
|
-
// |cx, cy, cz, cw| | z | | 0 |
|
|
48
|
-
// | 0, 0, 0, 1| | 1 | | 1 |
|
|
49
|
-
// Where normal of plane 1 = (ax, ay, az), plane constant of 1 = aw, normal of plane 2 = (bx, by, bz) etc.
|
|
50
|
-
// This involves inverting the matrix and multiplying it with [0, 0, 0, 1]
|
|
51
|
-
|
|
52
|
-
// Fetch the normals and plane constants for the three planes
|
|
53
|
-
|
|
54
|
-
cross_bn_cn.crossVectors(planeB.normal, planeC.normal);
|
|
55
|
-
|
|
56
|
-
const denominator = planeA.normal.dot(cross_bn_cn);
|
|
57
|
-
if (denominator === 0.0) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// The numerator is:
|
|
62
|
-
// [aw*(bz*cy-by*cz)+ay*(bw*cz-bz*cw)+az*(by*cw-bw*cy)]
|
|
63
|
-
// [aw*(bx*cz-bz*cx)+ax*(bz*cw-bw*cz)+az*(bw*cx-bx*cw)]
|
|
64
|
-
// [aw*(by*cx-bx*cy)+ax*(bw*cy-by*cw)+ay*(bx*cw-bw*cx)]
|
|
65
|
-
|
|
66
|
-
const a = planeA.normal;
|
|
67
|
-
const b = planeB.normal;
|
|
68
|
-
const c = planeC.normal;
|
|
69
|
-
|
|
70
|
-
const ax = a.x;
|
|
71
|
-
const ay = a.y;
|
|
72
|
-
const az = a.z;
|
|
73
|
-
|
|
74
|
-
const bx = b.x;
|
|
75
|
-
const by = b.y;
|
|
76
|
-
const bz = b.z;
|
|
77
|
-
|
|
78
|
-
const cx = c.x;
|
|
79
|
-
const cy = c.y;
|
|
80
|
-
const cz = c.z;
|
|
81
|
-
|
|
82
|
-
const aw = planeA.constant;
|
|
83
|
-
const bw = planeB.constant;
|
|
84
|
-
const cw = planeC.constant;
|
|
85
|
-
|
|
86
|
-
outPoint.x = aw * (bz * cy - by * cz) + ay * (bw * cz - bz * cw) + az * (by * cw - bw * cy);
|
|
87
|
-
outPoint.y = aw * (bx * cz - bz * cx) + ax * (bz * cw - bw * cz) + az * (bw * cx - bx * cw);
|
|
88
|
-
outPoint.z = aw * (by * cx - bx * cy) + ax * (bw * cy - by * cw) + ay * (bx * cw - bw * cx);
|
|
89
|
-
|
|
90
|
-
outPoint.scale(1 / denominator);
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* return the normalized fraction of the ray that intersects the plane in the interval [0.0, 1.0]
|
|
96
|
-
*/
|
|
97
|
-
castRay(ray: Ray): number {
|
|
98
|
-
const denominator = this.normal.dot(ray.direction);
|
|
99
|
-
|
|
100
|
-
// case: ray is nearly parallel to the plane
|
|
101
|
-
if (Math.abs(denominator) < 1e-6) {
|
|
102
|
-
return 1.0;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const t = (this.constant - this.normal.dot(ray.origin)) / denominator;
|
|
106
|
-
const fraction = t / ray.length;
|
|
107
|
-
|
|
108
|
-
// case: ray does not intersect the plane
|
|
109
|
-
if (fraction < 0.0 || fraction > 1.0) {
|
|
110
|
-
return 1.0;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// case: ray intersects the plane
|
|
114
|
-
return fraction;
|
|
115
|
-
}
|
|
116
|
-
}
|