avbd-babylon 0.2.0 → 0.4.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/README.md +864 -116
- package/dist/avbd.d.ts +2 -0
- package/dist/avbd.global.js +617 -153
- package/dist/avbd.js +617 -153
- package/dist/babylonAvbd.d.ts +31 -6
- package/dist/native.d.ts +1 -0
- package/dist/native.js +1 -1
- package/dist/nativeScenes.d.ts +81 -5
- package/dist/solverPipeline.d.ts +62 -0
- package/dist/utilities.d.ts +161 -0
- package/dist/utilities.js +1 -0
- package/docs/BABYLON_API.md +34 -5
- package/docs/HPLOC.md +119 -115
- package/docs/README.md +58 -14
- package/docs/RELEASE.md +26 -2
- package/package.json +38 -4
- package/tests/README.md +188 -25
package/dist/babylonAvbd.d.ts
CHANGED
|
@@ -2,6 +2,18 @@ import type { Vector3, Quaternion } from "@babylonjs/core/Maths/math.vector.js";
|
|
|
2
2
|
import type { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh.js";
|
|
3
3
|
import type { Scene } from "@babylonjs/core/scene.js";
|
|
4
4
|
import type { PhysicsShapeType } from "@babylonjs/core/Physics/v2/IPhysicsEnginePlugin.js";
|
|
5
|
+
import type {
|
|
6
|
+
AvbdSleepOptions,
|
|
7
|
+
AvbdHeightfieldOptions,
|
|
8
|
+
AvbdCookedTerrain,
|
|
9
|
+
AvbdTerrainMaterial,
|
|
10
|
+
} from "./nativeScenes.js";
|
|
11
|
+
export interface AvbdTerrain {
|
|
12
|
+
readonly bodies: AvbdPhysicsBody[];
|
|
13
|
+
readonly triangleCount: number;
|
|
14
|
+
readonly kind: "heightfield" | "static-mesh";
|
|
15
|
+
dispose(): void;
|
|
16
|
+
}
|
|
5
17
|
export const AvbdShapeType: Readonly<{
|
|
6
18
|
BOX: "box";
|
|
7
19
|
SPHERE: "sphere";
|
|
@@ -31,9 +43,11 @@ export interface AvbdWorldOptions {
|
|
|
31
43
|
maxSyncedBodies?: number;
|
|
32
44
|
broadphase?: "auto" | "grid" | "hploc";
|
|
33
45
|
solverMode?: AvbdSolverMode;
|
|
46
|
+
/** Automatically batch a closed jointless world of up to 32 bodies. */
|
|
47
|
+
smallGroups?: boolean;
|
|
34
48
|
bvh?: { rebuildInterval?: number };
|
|
35
|
-
/** Optional
|
|
36
|
-
sleeping?: boolean |
|
|
49
|
+
/** Optional GPU sleeping. Large worlds wake conservative connected groups on impact. */
|
|
50
|
+
sleeping?: boolean | AvbdSleepOptions;
|
|
37
51
|
maxContactPairs?: number;
|
|
38
52
|
maxContactEvents?: number;
|
|
39
53
|
}
|
|
@@ -116,6 +130,17 @@ export class AvbdPhysicsConstraint {
|
|
|
116
130
|
dispose(): void;
|
|
117
131
|
}
|
|
118
132
|
export class AvbdPhysics {
|
|
133
|
+
/** Register static collision pieces before initialize(); reserve body capacity. */
|
|
134
|
+
addHeightfield(options: AvbdHeightfieldOptions): AvbdTerrain;
|
|
135
|
+
/** Captures the mesh world transform; later mesh edits do not move terrain. */
|
|
136
|
+
addStaticMesh(
|
|
137
|
+
mesh: AbstractMesh,
|
|
138
|
+
options?: AvbdTerrainMaterial & { thickness?: number },
|
|
139
|
+
): AvbdTerrain;
|
|
140
|
+
addTerrain(
|
|
141
|
+
cooked: AvbdCookedTerrain,
|
|
142
|
+
options?: AvbdTerrainMaterial,
|
|
143
|
+
): AvbdTerrain;
|
|
119
144
|
sphereCast(
|
|
120
145
|
origin: AvbdVector,
|
|
121
146
|
radius: number,
|
|
@@ -151,10 +176,9 @@ export class AvbdPhysics {
|
|
|
151
176
|
readonly solverDecision: AvbdSolverDecision;
|
|
152
177
|
setSolverMode(mode: AvbdSolverMode): AvbdSolverDecision;
|
|
153
178
|
setGravity(gravity: AvbdVector): void;
|
|
154
|
-
enableSleeping(options?:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}): this;
|
|
179
|
+
enableSleeping(options?: AvbdSleepOptions): this;
|
|
180
|
+
/** Wake all sleeping bodies and disable automatic sleeping. */
|
|
181
|
+
disableSleeping(): this;
|
|
158
182
|
initialize(): void;
|
|
159
183
|
step(): void;
|
|
160
184
|
flushCommands(): void;
|
|
@@ -281,5 +305,6 @@ export class AvbdPhysicsBody {
|
|
|
281
305
|
effectiveMass: number;
|
|
282
306
|
sleeping: boolean;
|
|
283
307
|
}>;
|
|
308
|
+
/** Mesh-origin position; preserves live rotation and velocities when omitted. */
|
|
284
309
|
teleport(position: Vector3, rotation?: Quaternion): this;
|
|
285
310
|
}
|
package/dist/native.d.ts
CHANGED
package/dist/native.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { AvbdScene2D, AvbdScene3D, createWebGPUDevice, prepareWebGPUDevice3D } from "./avbd.js";
|
|
1
|
+
export { AvbdScene2D, AvbdScene3D, createWebGPUDevice, prepareWebGPUDevice3D, createSolverPipeline, cookHeightfield, cookStaticMesh } from "./avbd.js";
|
package/dist/nativeScenes.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AvbdSolverPipeline,
|
|
3
|
+
AvbdSolver2D,
|
|
4
|
+
AvbdSolver3D,
|
|
5
|
+
} from "./solverPipeline.js";
|
|
1
6
|
export type AvbdTuple3 = readonly [number, number, number];
|
|
2
7
|
export type AvbdTuple2 = readonly [number, number];
|
|
3
8
|
export interface AvbdQueryOptions {
|
|
@@ -22,6 +27,55 @@ export interface AvbdQueryHit<V> {
|
|
|
22
27
|
center: V;
|
|
23
28
|
}
|
|
24
29
|
export type AvbdQuaternion = readonly [number, number, number, number];
|
|
30
|
+
export interface AvbdTerrainMaterial {
|
|
31
|
+
friction?: number;
|
|
32
|
+
restitution?: number;
|
|
33
|
+
group?: number;
|
|
34
|
+
collidesWith?: number;
|
|
35
|
+
mass?: 0;
|
|
36
|
+
}
|
|
37
|
+
export interface AvbdHeightfieldOptions extends AvbdTerrainMaterial {
|
|
38
|
+
heights: ArrayLike<number>;
|
|
39
|
+
columns: number;
|
|
40
|
+
rows: number;
|
|
41
|
+
spacing?: number | AvbdTuple2;
|
|
42
|
+
origin?: AvbdTuple3;
|
|
43
|
+
upAxis?: 0 | 1 | 2;
|
|
44
|
+
/** Local height below every sample; defaults to the minimum height minus 2. */
|
|
45
|
+
baseHeight?: number;
|
|
46
|
+
/** Row-major cells; a nonzero entry leaves a hole. */
|
|
47
|
+
holes?: ArrayLike<number>;
|
|
48
|
+
}
|
|
49
|
+
export interface AvbdStaticMeshOptions extends AvbdTerrainMaterial {
|
|
50
|
+
/** World-space xyz triples. */
|
|
51
|
+
positions: ArrayLike<number>;
|
|
52
|
+
indices?: ArrayLike<number>;
|
|
53
|
+
/** Backing behind triangle winding, in world units. Defaults to 0.1. */
|
|
54
|
+
thickness?: number;
|
|
55
|
+
}
|
|
56
|
+
/** Serializable preprocessing output; can be cooked in a separate worker. */
|
|
57
|
+
export interface AvbdCookedTerrain {
|
|
58
|
+
kind: "heightfield" | "static-mesh";
|
|
59
|
+
triangleCount: number;
|
|
60
|
+
pieces: Array<{
|
|
61
|
+
shape: object;
|
|
62
|
+
position: AvbdTuple3;
|
|
63
|
+
rotation: AvbdQuaternion;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
export interface AvbdNativeTerrain {
|
|
67
|
+
readonly bodies: AvbdRigid[];
|
|
68
|
+
readonly triangleCount: number;
|
|
69
|
+
readonly kind: "heightfield" | "static-mesh";
|
|
70
|
+
/** Disable collision participation; live indices remain stable. */
|
|
71
|
+
dispose(): void;
|
|
72
|
+
}
|
|
73
|
+
export function cookHeightfield(
|
|
74
|
+
options: AvbdHeightfieldOptions,
|
|
75
|
+
): AvbdCookedTerrain;
|
|
76
|
+
export function cookStaticMesh(
|
|
77
|
+
options: AvbdStaticMeshOptions,
|
|
78
|
+
): AvbdCookedTerrain;
|
|
25
79
|
export interface AvbdNativeState3D {
|
|
26
80
|
position: [number, number, number];
|
|
27
81
|
rotation: [number, number, number, number];
|
|
@@ -186,6 +240,13 @@ export interface AvbdGpuParameters2D extends AvbdGpuParameters {
|
|
|
186
240
|
vbd: boolean;
|
|
187
241
|
vbdStiffness: number;
|
|
188
242
|
}
|
|
243
|
+
/** 3D can retain conservative connected groups between explicit world edits. */
|
|
244
|
+
export interface AvbdSleepOptions {
|
|
245
|
+
speedThreshold?: number;
|
|
246
|
+
timeThreshold?: number;
|
|
247
|
+
/** 3D: automatic for large jointless desktop worlds; false selects whole-world waking. */
|
|
248
|
+
islands?: boolean;
|
|
249
|
+
}
|
|
189
250
|
export interface AvbdGpuOptions {
|
|
190
251
|
bodyBuffer?: GPUBuffer;
|
|
191
252
|
bodyCapacity?: number;
|
|
@@ -193,6 +254,8 @@ export interface AvbdGpuOptions {
|
|
|
193
254
|
spatialSort?: boolean;
|
|
194
255
|
broadphase?: "auto" | "grid" | "hploc";
|
|
195
256
|
solverMode?: "auto" | "standard" | "optimized" | "points";
|
|
257
|
+
/** 3D: automatically fuse closed jointless worlds of at most 32 bodies. */
|
|
258
|
+
smallGroups?: boolean;
|
|
196
259
|
bvh?: { rebuildInterval?: number };
|
|
197
260
|
capacity?: {
|
|
198
261
|
contacts?: number;
|
|
@@ -201,9 +264,10 @@ export interface AvbdGpuOptions {
|
|
|
201
264
|
colors?: number;
|
|
202
265
|
joints?: number;
|
|
203
266
|
};
|
|
267
|
+
/** Reserve coloring capacity when sleeping bodies wake. */
|
|
204
268
|
minimumColors?: number;
|
|
205
269
|
minimumColorRounds?: number;
|
|
206
|
-
sleeping?: boolean |
|
|
270
|
+
sleeping?: boolean | AvbdSleepOptions;
|
|
207
271
|
}
|
|
208
272
|
export interface AvbdGpuSolver {
|
|
209
273
|
readonly bodyBuffer: GPUBuffer;
|
|
@@ -273,10 +337,7 @@ export interface AvbdGpuSolver3D extends AvbdGpuSolver {
|
|
|
273
337
|
rotation?: AvbdQuaternion,
|
|
274
338
|
): this;
|
|
275
339
|
readBodyState(index: number): Promise<AvbdNativeState3D>;
|
|
276
|
-
enableSleeping(options?:
|
|
277
|
-
speedThreshold?: number;
|
|
278
|
-
timeThreshold?: number;
|
|
279
|
-
}): this;
|
|
340
|
+
enableSleeping(options?: AvbdSleepOptions): this;
|
|
280
341
|
disableSleeping(): this;
|
|
281
342
|
setSleepEnabled(index: number, enabled: boolean): this;
|
|
282
343
|
watchContacts(options?: AvbdNativeContactOptions): this;
|
|
@@ -508,6 +569,12 @@ export interface AvbdNativeConstraint {
|
|
|
508
569
|
destroy(): void;
|
|
509
570
|
}
|
|
510
571
|
export class AvbdScene3D {
|
|
572
|
+
addHeightfield(options: AvbdHeightfieldOptions): AvbdNativeTerrain;
|
|
573
|
+
addStaticMesh(options: AvbdStaticMeshOptions): AvbdNativeTerrain;
|
|
574
|
+
addTerrain(
|
|
575
|
+
cooked: AvbdCookedTerrain,
|
|
576
|
+
options?: AvbdTerrainMaterial,
|
|
577
|
+
): AvbdNativeTerrain;
|
|
511
578
|
addMotor(
|
|
512
579
|
a: AvbdRigid | null,
|
|
513
580
|
b: AvbdRigid,
|
|
@@ -620,6 +687,10 @@ export class AvbdScene3D {
|
|
|
620
687
|
},
|
|
621
688
|
): AvbdNativeConstraint;
|
|
622
689
|
createSolver(device: GPUDevice, options?: AvbdGpuOptions): AvbdGpuSolver3D;
|
|
690
|
+
createSolver(
|
|
691
|
+
pipeline: AvbdSolverPipeline,
|
|
692
|
+
options?: AvbdGpuOptions,
|
|
693
|
+
): AvbdSolver3D;
|
|
623
694
|
}
|
|
624
695
|
export interface AvbdNativeAngularOptions {
|
|
625
696
|
axisA?: AvbdTuple3;
|
|
@@ -729,7 +800,12 @@ export class AvbdScene2D {
|
|
|
729
800
|
bodyBuffer?: GPUBuffer;
|
|
730
801
|
bodyCapacity?: number;
|
|
731
802
|
colorRounds?: number;
|
|
803
|
+
minimumColors?: number;
|
|
732
804
|
sleeping?: boolean | { speedThreshold?: number; timeThreshold?: number };
|
|
733
805
|
},
|
|
734
806
|
): AvbdGpuSolver2D;
|
|
807
|
+
createSolver(
|
|
808
|
+
pipeline: AvbdSolverPipeline,
|
|
809
|
+
options?: AvbdGpuOptions,
|
|
810
|
+
): AvbdSolver2D;
|
|
735
811
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AvbdScene2D,
|
|
3
|
+
AvbdScene3D,
|
|
4
|
+
AvbdGpuOptions,
|
|
5
|
+
AvbdGpuSolver,
|
|
6
|
+
AvbdGpuSolver2D,
|
|
7
|
+
AvbdGpuSolver3D,
|
|
8
|
+
AvbdAdvanceOptions,
|
|
9
|
+
} from "./nativeScenes.js";
|
|
10
|
+
import type { createWebGPUDevice } from "./gpuDevice.js";
|
|
11
|
+
|
|
12
|
+
export type AvbdSolverBackend = "webgpu" | "cpu";
|
|
13
|
+
/** Shared world settings. GPU scheduling fields apply only to GPU execution. */
|
|
14
|
+
export type AvbdSolverOptions = AvbdGpuOptions;
|
|
15
|
+
/** Drawing buffers belong to the selected backend; simulation operations are shared. */
|
|
16
|
+
type SharedMethods<T, Self> = {
|
|
17
|
+
[K in keyof T]: T[K] extends (...args: infer A) => infer R
|
|
18
|
+
? (...args: A) => R extends AvbdGpuSolver ? Self : R
|
|
19
|
+
: T[K];
|
|
20
|
+
};
|
|
21
|
+
export interface AvbdSolver2D extends SharedMethods<
|
|
22
|
+
Omit<AvbdGpuSolver2D, "bodyBuffer" | "shapeBuffer" | "attachToScene">,
|
|
23
|
+
AvbdSolver2D
|
|
24
|
+
> {
|
|
25
|
+
readonly backend: AvbdSolverBackend;
|
|
26
|
+
readonly bodyBuffer?: GPUBuffer;
|
|
27
|
+
readonly shapeBuffer?: GPUBuffer;
|
|
28
|
+
attachToScene(
|
|
29
|
+
scene: Parameters<AvbdGpuSolver2D["attachToScene"]>[0],
|
|
30
|
+
options?: AvbdAdvanceOptions & {
|
|
31
|
+
afterStep?: (solver: AvbdSolver2D) => void;
|
|
32
|
+
},
|
|
33
|
+
): this;
|
|
34
|
+
}
|
|
35
|
+
export interface AvbdSolver3D extends SharedMethods<
|
|
36
|
+
Omit<AvbdGpuSolver3D, "bodyBuffer" | "attachToScene">,
|
|
37
|
+
AvbdSolver3D
|
|
38
|
+
> {
|
|
39
|
+
readonly backend: AvbdSolverBackend;
|
|
40
|
+
readonly bodyBuffer?: GPUBuffer;
|
|
41
|
+
attachToScene(
|
|
42
|
+
scene: Parameters<AvbdGpuSolver3D["attachToScene"]>[0],
|
|
43
|
+
options?: AvbdAdvanceOptions & {
|
|
44
|
+
afterStep?: (solver: AvbdSolver3D) => void;
|
|
45
|
+
},
|
|
46
|
+
): this;
|
|
47
|
+
}
|
|
48
|
+
export interface AvbdSolverPipeline {
|
|
49
|
+
readonly backend: AvbdSolverBackend;
|
|
50
|
+
readonly device?: GPUDevice;
|
|
51
|
+
readonly adapter?: GPUAdapter;
|
|
52
|
+
createSolver(scene: AvbdScene2D, options?: AvbdSolverOptions): AvbdSolver2D;
|
|
53
|
+
createSolver(scene: AvbdScene3D, options?: AvbdSolverOptions): AvbdSolver3D;
|
|
54
|
+
/** Destroys its worlds and its own device. A supplied device remains caller-owned. */
|
|
55
|
+
destroy(): void;
|
|
56
|
+
}
|
|
57
|
+
export function createSolverPipeline(
|
|
58
|
+
options?: NonNullable<Parameters<typeof createWebGPUDevice>[0]> & {
|
|
59
|
+
backend?: AvbdSolverBackend;
|
|
60
|
+
device?: GPUDevice;
|
|
61
|
+
},
|
|
62
|
+
): Promise<AvbdSolverPipeline>;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/** Nonblocking GPU pass timestamps; null when timestamp-query is unavailable. */
|
|
2
|
+
export class GpuTimer {
|
|
3
|
+
constructor(device: GPUDevice);
|
|
4
|
+
readonly latestMs: number | null;
|
|
5
|
+
readonly samples: number;
|
|
6
|
+
begin(): object | null;
|
|
7
|
+
descriptor(slot: object | null): {
|
|
8
|
+
timestampWrites?: GPUComputePassTimestampWrites;
|
|
9
|
+
};
|
|
10
|
+
encode(encoder: GPUCommandEncoder, slot: object | null): void;
|
|
11
|
+
resolve(slot: object | null): Promise<void> | undefined;
|
|
12
|
+
settled(): Promise<unknown[]>;
|
|
13
|
+
destroy(): void;
|
|
14
|
+
}
|
|
15
|
+
/** Reuse released buffers with compatible usage, without CPU pose transfers. */
|
|
16
|
+
export class GPUBufferRecycler {
|
|
17
|
+
constructor(device: GPUDevice, options?: { maxFreeBytes?: number });
|
|
18
|
+
readonly freeBytes: number;
|
|
19
|
+
acquire(
|
|
20
|
+
byteSize: number,
|
|
21
|
+
usage: GPUBufferUsageFlags,
|
|
22
|
+
label?: string,
|
|
23
|
+
): GPUBuffer;
|
|
24
|
+
release(
|
|
25
|
+
buffer: GPUBuffer,
|
|
26
|
+
byteSize: number,
|
|
27
|
+
usage: GPUBufferUsageFlags,
|
|
28
|
+
): void;
|
|
29
|
+
trim(maxFreeBytes?: number): void;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|
|
32
|
+
export const PARTICLE_BYTE_STRIDE: 48;
|
|
33
|
+
export interface SurfaceParticleStep {
|
|
34
|
+
dt: number;
|
|
35
|
+
count?: number;
|
|
36
|
+
speed?: number;
|
|
37
|
+
life?: number;
|
|
38
|
+
bulletRadius?: number;
|
|
39
|
+
spawnRadius?: number;
|
|
40
|
+
jitter?: number;
|
|
41
|
+
frame?: number;
|
|
42
|
+
}
|
|
43
|
+
/** Spherical emitter aimed at the origin. Particles hit triangle surfaces and
|
|
44
|
+
* respawn; they ignore each other. Five rays approximate the particle sweep. */
|
|
45
|
+
export class GpuSurfaceParticles {
|
|
46
|
+
constructor(
|
|
47
|
+
device: GPUDevice,
|
|
48
|
+
options: { capacity: number; triangleCount: number; readback?: boolean },
|
|
49
|
+
);
|
|
50
|
+
readonly device: GPUDevice;
|
|
51
|
+
readonly capacity: number;
|
|
52
|
+
readonly triangleCount: number;
|
|
53
|
+
/** 48 bytes: position/life vec4f, velocity/radius vec4f, seed vec4u. */
|
|
54
|
+
readonly particleBuffer: GPUBuffer;
|
|
55
|
+
readonly triangleBuffer: GPUBuffer;
|
|
56
|
+
readonly counterBuffer: GPUBuffer;
|
|
57
|
+
readonly timer: GpuTimer;
|
|
58
|
+
/** 12 float32 values per triangle: [ax,ay,az,0,bx,by,bz,0,cx,cy,cz,0]. */
|
|
59
|
+
writeTriangles(vertices: Float32Array): void;
|
|
60
|
+
/** Returns the latest asynchronous counters, or null with readback disabled. */
|
|
61
|
+
step(options: SurfaceParticleStep): { hits: number; alive: number } | null;
|
|
62
|
+
clear(): void;
|
|
63
|
+
destroy(): void;
|
|
64
|
+
}
|
|
65
|
+
export const sampledContactShader: string;
|
|
66
|
+
/** Gather a bounded GPU contact overlay, without reading the full contact set. */
|
|
67
|
+
export class GpuContactSample {
|
|
68
|
+
constructor(device: GPUDevice, options?: { count?: number });
|
|
69
|
+
readonly count: number;
|
|
70
|
+
readonly buffer: GPUBuffer;
|
|
71
|
+
encode(
|
|
72
|
+
encoder: GPUCommandEncoder,
|
|
73
|
+
resources: {
|
|
74
|
+
bodyBuffer: GPUBuffer;
|
|
75
|
+
/** Native 3D camera uniform: mat4 vp, vec4 eye, vec4 light/viewport. */
|
|
76
|
+
cameraBuffer: GPUBuffer;
|
|
77
|
+
contactStorage: {
|
|
78
|
+
manifolds: GPUBuffer;
|
|
79
|
+
contacts: GPUBuffer;
|
|
80
|
+
counters: GPUBuffer;
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
): void;
|
|
84
|
+
dispose(): void;
|
|
85
|
+
}
|
|
86
|
+
/** Optional one-time native constraint-graph seed; live GPU coloring still checks contacts. */
|
|
87
|
+
export function seedConstraintColoring(
|
|
88
|
+
gpu: {
|
|
89
|
+
device: GPUDevice;
|
|
90
|
+
bodyCapacity: number;
|
|
91
|
+
colorBuffer: GPUBuffer;
|
|
92
|
+
colorCap: number;
|
|
93
|
+
gpuIndex(index: number): number;
|
|
94
|
+
},
|
|
95
|
+
world: {
|
|
96
|
+
bodies: { mass: number }[];
|
|
97
|
+
forces: { bodyA: object | null; bodyB: object | null }[];
|
|
98
|
+
},
|
|
99
|
+
minimum?: number,
|
|
100
|
+
): void;
|
|
101
|
+
export const INPUT_WORDS: 9;
|
|
102
|
+
/** Custom compute/copy work in the solver's existing command encoder. Callbacks
|
|
103
|
+
* are synchronous, end their own passes, and must not submit or finish the encoder.
|
|
104
|
+
* Dispose the registration before destroying its buffers. CPU solvers are rejected. */
|
|
105
|
+
export function addGpuStepPass<
|
|
106
|
+
T extends { bodyBuffer: GPUBuffer; step(): void },
|
|
107
|
+
>(
|
|
108
|
+
solver: T,
|
|
109
|
+
hooks: {
|
|
110
|
+
before?: (encoder: GPUCommandEncoder, solver: T) => void;
|
|
111
|
+
after?: (encoder: GPUCommandEncoder, solver: T) => void;
|
|
112
|
+
},
|
|
113
|
+
): () => void;
|
|
114
|
+
/** DOM-free sizing and event adapter around a caller-owned canvas. */
|
|
115
|
+
export class WorkerCanvas {
|
|
116
|
+
constructor(
|
|
117
|
+
canvas: OffscreenCanvas | HTMLCanvasElement,
|
|
118
|
+
width: number,
|
|
119
|
+
height: number,
|
|
120
|
+
);
|
|
121
|
+
readonly offscreenCanvas: OffscreenCanvas | HTMLCanvasElement;
|
|
122
|
+
readonly clientWidth: number;
|
|
123
|
+
readonly clientHeight: number;
|
|
124
|
+
readonly revision: number;
|
|
125
|
+
width: number;
|
|
126
|
+
height: number;
|
|
127
|
+
resize(width: number, height: number): void;
|
|
128
|
+
getContext(type: "webgpu"): GPUCanvasContext | null;
|
|
129
|
+
getContext(type: string, options?: object): unknown;
|
|
130
|
+
getBoundingClientRect(): {
|
|
131
|
+
left: number;
|
|
132
|
+
top: number;
|
|
133
|
+
width: number;
|
|
134
|
+
height: number;
|
|
135
|
+
};
|
|
136
|
+
addEventListener(type: string, callback: (event: any) => void): void;
|
|
137
|
+
removeEventListener(type: string, callback: (event: any) => void): void;
|
|
138
|
+
setPointerCapture(): void;
|
|
139
|
+
dispatch(type: string, data: object): void;
|
|
140
|
+
}
|
|
141
|
+
export interface SharedPointerState {
|
|
142
|
+
clientX: number;
|
|
143
|
+
clientY: number;
|
|
144
|
+
pointerId?: number;
|
|
145
|
+
buttons?: number;
|
|
146
|
+
altKey?: boolean;
|
|
147
|
+
shiftKey?: boolean;
|
|
148
|
+
ctrlKey?: boolean;
|
|
149
|
+
}
|
|
150
|
+
/** Returns null without cross-origin isolation / SharedArrayBuffer support. */
|
|
151
|
+
export function createSharedInput(): Int32Array<SharedArrayBuffer> | null;
|
|
152
|
+
/** One producer; continuous state only. Send discrete events as ordered messages. */
|
|
153
|
+
export function writeSharedInput(
|
|
154
|
+
view: Int32Array<SharedArrayBuffer>,
|
|
155
|
+
event: SharedPointerState,
|
|
156
|
+
wheel?: number,
|
|
157
|
+
): void;
|
|
158
|
+
export function readSharedInput(
|
|
159
|
+
view: Int32Array<SharedArrayBuffer>,
|
|
160
|
+
previous?: number,
|
|
161
|
+
): { sequence: number; event: SharedPointerState; wheel: number } | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { GpuTimer, GPUBufferRecycler, GpuSurfaceParticles, PARTICLE_BYTE_STRIDE, GpuContactSample, sampledContactShader, seedConstraintColoring, addGpuStepPass, WorkerCanvas, INPUT_WORDS, createSharedInput, writeSharedInput, readSharedInput } from "./avbd.js";
|
package/docs/BABYLON_API.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Babylon.js integration
|
|
2
2
|
|
|
3
|
+
Static terrain can be added with `physics.addHeightfield(options)` or
|
|
4
|
+
`physics.addStaticMesh(mesh, { thickness, friction, group, collidesWith })`.
|
|
5
|
+
The mesh helper captures current world-space triangles, including parent transforms.
|
|
6
|
+
Both return `{ bodies, triangleCount, kind, dispose() }`. Add terrain before
|
|
7
|
+
`initialize()` or the first render, and reserve body capacity for its collision
|
|
8
|
+
pieces. These pieces do not synchronize meshes each frame. `dispose()` disables
|
|
9
|
+
their collisions while leaving the caller's mesh intact.
|
|
10
|
+
|
|
11
|
+
Heightfields use two solid prisms per cell. Mesh terrain gives each triangle
|
|
12
|
+
finite backing behind its winding; concavities and overhangs remain open. This
|
|
13
|
+
uses the existing convex contact and grid/HPLOC pipelines. Internal tile edges
|
|
14
|
+
can affect sliding, and a rendering mesh should usually have a simpler collision
|
|
15
|
+
mesh. Terrain is static and does not track subsequent mesh transformations.
|
|
16
|
+
See [terrain examples](../README.md#static-terrain-hills-caves-and-overhangs)
|
|
17
|
+
for the native API, holes, coordinate conventions and worker cooking helpers.
|
|
18
|
+
|
|
3
19
|
Start with the [integration README](README.md) for a complete scene, bundler setup,
|
|
4
20
|
instance rendering examples and reproducible collision/solver benchmarks.
|
|
5
21
|
|
|
@@ -79,8 +95,10 @@ impacts below 1 m/s do not bounce. Use `body.setRestitution()` for live changes.
|
|
|
79
95
|
`isTrigger:true` detects dynamic-body overlaps without contact forces;
|
|
80
96
|
`body.setTrigger()` changes the mode. Events include `isTrigger`, and masks
|
|
81
97
|
apply to sensors too. Static–static pairs are not scanned. CCD,
|
|
82
|
-
|
|
83
|
-
interface are not implemented. Static
|
|
98
|
+
dynamic concave meshes and the full Physics V2 plugin
|
|
99
|
+
interface are not implemented. Static triangle meshes and heightfields use
|
|
100
|
+
`addStaticMesh()` and `addHeightfield()` terrain cooking, including caves and
|
|
101
|
+
overhangs. Static bodies given velocity move kinematically.
|
|
84
102
|
|
|
85
103
|
`addHinge(a,b,{axisA,axisB,anchorA,anchorB,minAngle,maxAngle,motor})` constrains
|
|
86
104
|
rotation to one axis, with optional angle stops and a torque-limited motor.
|
|
@@ -129,18 +147,29 @@ reserve storage; `readContactEvents()` reports dropped events or a full pair
|
|
|
129
147
|
table. End events do not retain an old position. Callbacks run asynchronously.
|
|
130
148
|
|
|
131
149
|
`sleeping: true` or `{ speedThreshold: 0.03, timeThreshold: 0.5 }` enables an
|
|
132
|
-
optional GPU policy. Supported quiet bodies sleep
|
|
133
|
-
|
|
150
|
+
optional GPU policy. Supported quiet bodies sleep. Large jointless desktop 3D worlds
|
|
151
|
+
automatically wake conservative connected groups on impact, keeping unrelated
|
|
152
|
+
piles asleep; the shared static floor does not join them. `islands:true` opts
|
|
153
|
+
into group waking in smaller worlds, and `islands:false` selects whole-world
|
|
154
|
+
waking. Explicit edits wake the world and reset group history. Unsupported bodies
|
|
134
155
|
under gravity stay awake. `wakeAll()`, `body.wakeUp()` and `readSleepStats()` are
|
|
135
156
|
available. Suspended jointed objects are not guaranteed to sleep. Defaults and
|
|
136
157
|
paper-comparison benchmarks keep sleeping disabled.
|
|
137
158
|
|
|
159
|
+
Closed jointless 3D worlds with at most 32 bodies automatically batch movement
|
|
160
|
+
iterations in one GPU workgroup. Body poses stay in shared memory, with the
|
|
161
|
+
same contact order, reductions and equations. Adding a joint or exceeding the
|
|
162
|
+
body limit selects the ordinary pipeline. Qualified mobile compatibility paths
|
|
163
|
+
retain their existing execution policy. `smallGroups:false` disables batching
|
|
164
|
+
for controlled comparisons.
|
|
165
|
+
|
|
138
166
|
`body.setLinearVelocity()`, `setAngularVelocity()`, `applyImpulse()`,
|
|
139
167
|
`applyAngularImpulse()` and `teleport(position, quaternion)` enqueue compact
|
|
140
168
|
GPU commands. Commands for the same body are combined before submission;
|
|
141
169
|
impulses use the current GPU mass, inertia and position. They never replace a
|
|
142
170
|
body with a stale CPU pose. `teleport` retains velocity unless a velocity setter
|
|
143
|
-
is also called.
|
|
171
|
+
is also called. Omitting its quaternion preserves the live GPU rotation and
|
|
172
|
+
places the mesh origin at the requested position. New aggregates can be added within reserved capacity after
|
|
144
173
|
initialization; disposed body slots are not reused. For repeated spawning,
|
|
145
174
|
reserve projectile bodies and teleport them. `applyForce()` and `applyTorque()`
|
|
146
175
|
apply forces for one fixed step, using impulses on live GPU state.
|