@holoscript/engine 6.0.3 → 6.0.4
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/dist/AutoMesher-CK47F6AV.js +17 -0
- package/dist/GPUBuffers-2LHBCD7X.js +9 -0
- package/dist/WebGPUContext-TNEUYU2Y.js +11 -0
- package/dist/animation/index.cjs +38 -38
- package/dist/animation/index.d.cts +1 -1
- package/dist/animation/index.d.ts +1 -1
- package/dist/animation/index.js +1 -1
- package/dist/audio/index.cjs +16 -6
- package/dist/audio/index.d.cts +1 -1
- package/dist/audio/index.d.ts +1 -1
- package/dist/audio/index.js +1 -1
- package/dist/camera/index.cjs +23 -23
- package/dist/camera/index.d.cts +1 -1
- package/dist/camera/index.d.ts +1 -1
- package/dist/camera/index.js +1 -1
- package/dist/character/index.cjs +6 -4
- package/dist/character/index.js +1 -1
- package/dist/choreography/index.cjs +1194 -0
- package/dist/choreography/index.d.cts +687 -0
- package/dist/choreography/index.d.ts +687 -0
- package/dist/choreography/index.js +1156 -0
- package/dist/chunk-2CSNRI2N.js +217 -0
- package/dist/chunk-33T2WINR.js +266 -0
- package/dist/chunk-35R73OFM.js +1257 -0
- package/dist/chunk-4MMDSUNP.js +1256 -0
- package/dist/chunk-5V6HOU72.js +319 -0
- package/dist/chunk-6QOP6PYF.js +1038 -0
- package/dist/chunk-7KMJVHIL.js +8944 -0
- package/dist/chunk-7VPUC62U.js +1106 -0
- package/dist/chunk-A2Y6RCAT.js +1878 -0
- package/dist/chunk-AHM42MK6.js +8944 -0
- package/dist/chunk-BL7IDTHE.js +218 -0
- package/dist/chunk-CITOMSWL.js +10462 -0
- package/dist/chunk-CXDPKW2K.js +8944 -0
- package/dist/chunk-CXZPLD4S.js +223 -0
- package/dist/chunk-CZYJE7IH.js +5169 -0
- package/dist/chunk-D2OP7YC7.js +6325 -0
- package/dist/chunk-EDRVQHUU.js +1544 -0
- package/dist/chunk-EJSLOOW2.js +3589 -0
- package/dist/chunk-F53SFGW5.js +1878 -0
- package/dist/chunk-HCFPELPY.js +919 -0
- package/dist/chunk-HNEE36PY.js +93 -0
- package/dist/chunk-HYXNV36F.js +1256 -0
- package/dist/chunk-IB7KHVFY.js +821 -0
- package/dist/chunk-IBBO7YYG.js +690 -0
- package/dist/chunk-ILIBGINU.js +5470 -0
- package/dist/chunk-IS4MHLKN.js +5479 -0
- package/dist/chunk-JT2PFKWD.js +5479 -0
- package/dist/chunk-K4CUB4NY.js +1038 -0
- package/dist/chunk-KATDQXRJ.js +10462 -0
- package/dist/chunk-KBQE6ZFJ.js +8944 -0
- package/dist/chunk-KBVD5K7E.js +560 -0
- package/dist/chunk-KCDPVQRY.js +4088 -0
- package/dist/chunk-KN4QJPKN.js +8944 -0
- package/dist/chunk-KWJ3ROSI.js +8944 -0
- package/dist/chunk-L45VF6DD.js +919 -0
- package/dist/chunk-LY4T37YK.js +307 -0
- package/dist/chunk-MDN5WZXA.js +1544 -0
- package/dist/chunk-MGCDP6VU.js +928 -0
- package/dist/chunk-NCX7X6G2.js +8681 -0
- package/dist/chunk-OF54BPVD.js +913 -0
- package/dist/chunk-OWSN2Q3Q.js +690 -0
- package/dist/chunk-PRRB5TTA.js +406 -0
- package/dist/chunk-PXWVQF76.js +4086 -0
- package/dist/chunk-PYCOIDT2.js +812 -0
- package/dist/chunk-PZCSADOV.js +928 -0
- package/dist/chunk-Q2XBVS2K.js +1038 -0
- package/dist/chunk-QDZRXWN5.js +1776 -0
- package/dist/chunk-RNWOZ6WQ.js +913 -0
- package/dist/chunk-ROLFT4CJ.js +1693 -0
- package/dist/chunk-SLTJRZ2N.js +266 -0
- package/dist/chunk-SRUS5XSU.js +4088 -0
- package/dist/chunk-TKCA3WZ5.js +5409 -0
- package/dist/chunk-TNRMXYI2.js +1650 -0
- package/dist/chunk-TQB3GJGM.js +9763 -0
- package/dist/chunk-TUFGXG6K.js +510 -0
- package/dist/chunk-U6KMTGQJ.js +632 -0
- package/dist/chunk-VMGJQST6.js +8681 -0
- package/dist/chunk-X4F4TCG4.js +5470 -0
- package/dist/chunk-ZIFROE75.js +1544 -0
- package/dist/chunk-ZIJQYHSQ.js +1204 -0
- package/dist/combat/index.cjs +4 -4
- package/dist/combat/index.d.cts +1 -1
- package/dist/combat/index.d.ts +1 -1
- package/dist/combat/index.js +1 -1
- package/dist/ecs/index.cjs +1 -1
- package/dist/ecs/index.js +1 -1
- package/dist/environment/index.cjs +14 -14
- package/dist/environment/index.d.cts +1 -1
- package/dist/environment/index.d.ts +1 -1
- package/dist/environment/index.js +1 -1
- package/dist/gpu/index.cjs +4810 -0
- package/dist/gpu/index.js +3714 -0
- package/dist/hologram/index.cjs +27 -1
- package/dist/hologram/index.js +1 -1
- package/dist/index-B2PIsAmR.d.cts +2180 -0
- package/dist/index-B2PIsAmR.d.ts +2180 -0
- package/dist/index-BHySEPX7.d.cts +2921 -0
- package/dist/index-BJV21zuy.d.cts +341 -0
- package/dist/index-BJV21zuy.d.ts +341 -0
- package/dist/index-BQutTphC.d.cts +790 -0
- package/dist/index-ByIq2XrS.d.cts +3910 -0
- package/dist/index-BysHjDSO.d.cts +224 -0
- package/dist/index-BysHjDSO.d.ts +224 -0
- package/dist/index-CKwAJGck.d.ts +455 -0
- package/dist/index-CUl3QstQ.d.cts +3006 -0
- package/dist/index-CUl3QstQ.d.ts +3006 -0
- package/dist/index-CmYtNiI-.d.cts +953 -0
- package/dist/index-CmYtNiI-.d.ts +953 -0
- package/dist/index-CnRzWxi_.d.cts +522 -0
- package/dist/index-CnRzWxi_.d.ts +522 -0
- package/dist/index-CwRWbSC7.d.ts +2921 -0
- package/dist/index-CxKIBstO.d.ts +790 -0
- package/dist/index-DJ6-R8vh.d.cts +455 -0
- package/dist/index-DQKisbcI.d.cts +4968 -0
- package/dist/index-DQKisbcI.d.ts +4968 -0
- package/dist/index-DRT2zJez.d.ts +3910 -0
- package/dist/index-DfNLiAka.d.cts +192 -0
- package/dist/index-DfNLiAka.d.ts +192 -0
- package/dist/index-nMvkoRm8.d.cts +405 -0
- package/dist/index-nMvkoRm8.d.ts +405 -0
- package/dist/index-s9yOFU37.d.cts +604 -0
- package/dist/index-s9yOFU37.d.ts +604 -0
- package/dist/index.cjs +22966 -6960
- package/dist/index.d.cts +864 -20
- package/dist/index.d.ts +864 -20
- package/dist/index.js +3062 -48
- package/dist/input/index.cjs +1 -1
- package/dist/input/index.js +1 -1
- package/dist/orbital/index.cjs +3 -3
- package/dist/orbital/index.d.cts +1 -1
- package/dist/orbital/index.d.ts +1 -1
- package/dist/orbital/index.js +1 -1
- package/dist/particles/index.cjs +16 -16
- package/dist/particles/index.d.cts +1 -1
- package/dist/particles/index.d.ts +1 -1
- package/dist/particles/index.js +1 -1
- package/dist/physics/index.cjs +2377 -21
- package/dist/physics/index.d.cts +1 -1
- package/dist/physics/index.d.ts +1 -1
- package/dist/physics/index.js +35 -1
- package/dist/postfx/index.cjs +3491 -0
- package/dist/postfx/index.js +93 -0
- package/dist/procedural/index.cjs +1 -1
- package/dist/procedural/index.js +1 -1
- package/dist/puppeteer-5VF6KDVO.js +52197 -0
- package/dist/puppeteer-IZVZ3SG4.js +52197 -0
- package/dist/rendering/index.cjs +33 -32
- package/dist/rendering/index.d.cts +1 -1
- package/dist/rendering/index.d.ts +1 -1
- package/dist/rendering/index.js +8 -6
- package/dist/runtime/index.cjs +23 -13
- package/dist/runtime/index.d.cts +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +8 -6
- package/dist/runtime/protocols/index.cjs +349 -0
- package/dist/runtime/protocols/index.js +15 -0
- package/dist/scene/index.cjs +8 -8
- package/dist/scene/index.d.cts +1 -1
- package/dist/scene/index.d.ts +1 -1
- package/dist/scene/index.js +1 -1
- package/dist/shader/index.cjs +3087 -0
- package/dist/shader/index.js +3044 -0
- package/dist/simulation/index.cjs +10680 -0
- package/dist/simulation/index.d.cts +3 -0
- package/dist/simulation/index.d.ts +3 -0
- package/dist/simulation/index.js +307 -0
- package/dist/spatial/index.cjs +2443 -0
- package/dist/spatial/index.d.cts +1545 -0
- package/dist/spatial/index.d.ts +1545 -0
- package/dist/spatial/index.js +2400 -0
- package/dist/terrain/index.cjs +1 -1
- package/dist/terrain/index.d.cts +1 -1
- package/dist/terrain/index.d.ts +1 -1
- package/dist/terrain/index.js +1 -1
- package/dist/transformers.node-4NKAPD5U.js +45620 -0
- package/dist/vm/index.cjs +7 -8
- package/dist/vm/index.d.cts +1 -1
- package/dist/vm/index.d.ts +1 -1
- package/dist/vm/index.js +1 -1
- package/dist/vm-bridge/index.cjs +2 -2
- package/dist/vm-bridge/index.d.cts +2 -2
- package/dist/vm-bridge/index.d.ts +2 -2
- package/dist/vm-bridge/index.js +1 -1
- package/dist/vr/index.cjs +6 -6
- package/dist/vr/index.js +1 -1
- package/dist/world/index.cjs +3 -3
- package/dist/world/index.d.cts +1 -1
- package/dist/world/index.d.ts +1 -1
- package/dist/world/index.js +1 -1
- package/package.json +53 -21
- package/LICENSE +0 -21
|
@@ -0,0 +1,2921 @@
|
|
|
1
|
+
import { B as BodyType, C as CollisionShape, a as IRigidBodyConfig, I as IVector3, b as IQuaternion, c as IPhysicsMaterial, d as ICollisionFilter, e as IRigidBodyState, f as ITransform, g as IPhysicsWorld, h as IPhysicsWorldConfig, i as Constraint, j as ICollisionEvent, k as ITriggerEvent, l as IRay, m as IRaycastOptions, n as IRaycastHit, o as IOverlapResult, p as ISoftBodyConfig, q as ISDFCollider, r as ISoftBodyState, s as IConstraintColoring, P as ParticleType, t as IParticleAttributes, u as COLLISION_GROUPS, v as IBallConstraint, w as IBoxShape, x as ICapsuleShape, y as ICompoundShape, z as IConeConstraint, A as IConeShape, D as IConvexShape, E as ICylinderShape, F as IDistanceConstraint, G as IFixedConstraint, H as IGeneric6DOFConstraint, J as IHeightfieldShape, K as IHingeConstraint, L as IMeshShape, M as IPBDAttachmentConstraint, N as IPBDBendingConstraint, O as IPBDCollisionConstraint, Q as IPBDDistanceConstraint, R as IPBDVolumeConstraint, S as ISliderConstraint, T as ISpatialHashGrid, U as ISphereShape, V as ISpringConstraint, W as PBDConstraint, X as PBDConstraintType, Y as PHYSICS_DEFAULTS, Z as SOFT_BODY_PRESETS, _ as SoftBodyPreset, $ as boxShape, a0 as capsuleShape, a1 as defaultMaterial, a2 as defaultTransform, a3 as dynamicBody, a4 as identityQuaternion, a5 as kinematicBody, a6 as sphereShape, a7 as staticBody, a8 as validateBodyConfig, a9 as zeroVector } from './PhysicsTypes-Dw6_oXuD.cjs';
|
|
2
|
+
import { WeatherBlackboardState, VRHand } from '@holoscript/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PhysicsBody.ts
|
|
6
|
+
*
|
|
7
|
+
* Rigid body implementation for the HoloScript physics system.
|
|
8
|
+
*
|
|
9
|
+
* @module physics
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Rigid body class for physics simulation
|
|
14
|
+
*/
|
|
15
|
+
declare class RigidBody {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly type: BodyType;
|
|
18
|
+
readonly shape: CollisionShape;
|
|
19
|
+
private _position;
|
|
20
|
+
private _rotation;
|
|
21
|
+
private _linearVelocity;
|
|
22
|
+
private _angularVelocity;
|
|
23
|
+
private _isSleeping;
|
|
24
|
+
private _isActive;
|
|
25
|
+
private _mass;
|
|
26
|
+
private _inverseMass;
|
|
27
|
+
private _inertia;
|
|
28
|
+
private _inverseInertia;
|
|
29
|
+
private _material;
|
|
30
|
+
private _filter;
|
|
31
|
+
private _linearDamping;
|
|
32
|
+
private _angularDamping;
|
|
33
|
+
private _gravityScale;
|
|
34
|
+
private _ccd;
|
|
35
|
+
private _userData;
|
|
36
|
+
private _force;
|
|
37
|
+
private _torque;
|
|
38
|
+
private _sleepTimer;
|
|
39
|
+
constructor(config: IRigidBodyConfig);
|
|
40
|
+
get position(): IVector3;
|
|
41
|
+
set position(value: IVector3);
|
|
42
|
+
get rotation(): IQuaternion;
|
|
43
|
+
set rotation(value: IQuaternion);
|
|
44
|
+
get linearVelocity(): IVector3;
|
|
45
|
+
set linearVelocity(value: IVector3);
|
|
46
|
+
get angularVelocity(): IVector3;
|
|
47
|
+
set angularVelocity(value: IVector3);
|
|
48
|
+
get isSleeping(): boolean;
|
|
49
|
+
get isActive(): boolean;
|
|
50
|
+
set isActive(value: boolean);
|
|
51
|
+
get mass(): number;
|
|
52
|
+
get inverseMass(): number;
|
|
53
|
+
get material(): IPhysicsMaterial;
|
|
54
|
+
set material(value: IPhysicsMaterial);
|
|
55
|
+
get filter(): ICollisionFilter;
|
|
56
|
+
set filter(value: ICollisionFilter);
|
|
57
|
+
get gravityScale(): number;
|
|
58
|
+
set gravityScale(value: number);
|
|
59
|
+
get ccd(): boolean;
|
|
60
|
+
set ccd(value: boolean);
|
|
61
|
+
get userData(): unknown;
|
|
62
|
+
set userData(value: unknown);
|
|
63
|
+
/**
|
|
64
|
+
* Apply a force at the center of mass
|
|
65
|
+
*/
|
|
66
|
+
applyForce(force: IVector3): void;
|
|
67
|
+
/**
|
|
68
|
+
* Apply a force at a world point
|
|
69
|
+
*/
|
|
70
|
+
applyForceAtPoint(force: IVector3, worldPoint: IVector3): void;
|
|
71
|
+
/**
|
|
72
|
+
* Apply an impulse at the center of mass
|
|
73
|
+
*/
|
|
74
|
+
applyImpulse(impulse: IVector3): void;
|
|
75
|
+
/**
|
|
76
|
+
* Apply an impulse at a world point
|
|
77
|
+
*/
|
|
78
|
+
applyImpulseAtPoint(impulse: IVector3, worldPoint: IVector3): void;
|
|
79
|
+
/**
|
|
80
|
+
* Apply a torque
|
|
81
|
+
*/
|
|
82
|
+
applyTorque(torque: IVector3): void;
|
|
83
|
+
/**
|
|
84
|
+
* Apply a torque impulse
|
|
85
|
+
*/
|
|
86
|
+
applyTorqueImpulse(impulse: IVector3): void;
|
|
87
|
+
/**
|
|
88
|
+
* Clear accumulated forces
|
|
89
|
+
*/
|
|
90
|
+
clearForces(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Integrate forces (semi-implicit Euler)
|
|
93
|
+
*/
|
|
94
|
+
integrateForces(dt: number, gravity: IVector3): void;
|
|
95
|
+
/**
|
|
96
|
+
* Integrate velocities (update position/rotation)
|
|
97
|
+
*/
|
|
98
|
+
integrateVelocities(dt: number): void;
|
|
99
|
+
/**
|
|
100
|
+
* Wake up the body
|
|
101
|
+
*/
|
|
102
|
+
wakeUp(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Try to put the body to sleep
|
|
105
|
+
*/
|
|
106
|
+
updateSleep(dt: number): void;
|
|
107
|
+
/**
|
|
108
|
+
* Get current state
|
|
109
|
+
*/
|
|
110
|
+
getState(): IRigidBodyState;
|
|
111
|
+
/**
|
|
112
|
+
* Get transform
|
|
113
|
+
*/
|
|
114
|
+
getTransform(): ITransform;
|
|
115
|
+
/**
|
|
116
|
+
* Set transform directly (for kinematic bodies)
|
|
117
|
+
*/
|
|
118
|
+
setTransform(transform: ITransform): void;
|
|
119
|
+
/**
|
|
120
|
+
* Get accumulated force
|
|
121
|
+
*/
|
|
122
|
+
getForce(): IVector3;
|
|
123
|
+
/**
|
|
124
|
+
* Get accumulated torque
|
|
125
|
+
*/
|
|
126
|
+
getTorque(): IVector3;
|
|
127
|
+
/**
|
|
128
|
+
* Calculate inertia tensor for the shape
|
|
129
|
+
*/
|
|
130
|
+
private calculateInertia;
|
|
131
|
+
/**
|
|
132
|
+
* Clamp velocity magnitude
|
|
133
|
+
*/
|
|
134
|
+
private clampVelocity;
|
|
135
|
+
/**
|
|
136
|
+
* Calculate vector length
|
|
137
|
+
*/
|
|
138
|
+
private vectorLength;
|
|
139
|
+
/**
|
|
140
|
+
* Normalize quaternion
|
|
141
|
+
*/
|
|
142
|
+
private normalizeQuaternion;
|
|
143
|
+
/**
|
|
144
|
+
* Test collision filter
|
|
145
|
+
*/
|
|
146
|
+
canCollideWith(other: RigidBody): boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* PhysicsWorldImpl.ts
|
|
151
|
+
*
|
|
152
|
+
* Physics world implementation with broadphase collision detection,
|
|
153
|
+
* constraint solving, and spatial queries.
|
|
154
|
+
*
|
|
155
|
+
* @module physics
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Physics world implementation
|
|
160
|
+
*/
|
|
161
|
+
declare class PhysicsWorldImpl implements IPhysicsWorld {
|
|
162
|
+
private config;
|
|
163
|
+
private bodies;
|
|
164
|
+
private constraints;
|
|
165
|
+
private collisionEvents;
|
|
166
|
+
private triggerEvents;
|
|
167
|
+
private islandDetector;
|
|
168
|
+
private accumulator;
|
|
169
|
+
private bodiesArray;
|
|
170
|
+
private collisionPairs;
|
|
171
|
+
private activeContacts;
|
|
172
|
+
constructor(config?: IPhysicsWorldConfig);
|
|
173
|
+
setGravity(gravity: IVector3): void;
|
|
174
|
+
getGravity(): IVector3;
|
|
175
|
+
createBody(config: IRigidBodyConfig): string;
|
|
176
|
+
removeBody(id: string): boolean;
|
|
177
|
+
getBody(id: string): IRigidBodyState | undefined;
|
|
178
|
+
getAllBodies(): IRigidBodyState[];
|
|
179
|
+
setPosition(id: string, position: IVector3): void;
|
|
180
|
+
setRotation(id: string, rotation: IQuaternion): void;
|
|
181
|
+
setTransform(id: string, transform: ITransform): void;
|
|
182
|
+
setLinearVelocity(id: string, velocity: IVector3): void;
|
|
183
|
+
setAngularVelocity(id: string, velocity: IVector3): void;
|
|
184
|
+
applyForce(id: string, force: IVector3, worldPoint?: IVector3): void;
|
|
185
|
+
applyImpulse(id: string, impulse: IVector3, worldPoint?: IVector3): void;
|
|
186
|
+
applyTorque(id: string, torque: IVector3): void;
|
|
187
|
+
applyTorqueImpulse(id: string, impulse: IVector3): void;
|
|
188
|
+
createConstraint(constraint: Constraint): string;
|
|
189
|
+
removeConstraint(id: string): boolean;
|
|
190
|
+
setConstraintEnabled(id: string, enabled: boolean): void;
|
|
191
|
+
step(deltaTime: number): void;
|
|
192
|
+
private fixedStep;
|
|
193
|
+
private broadphase;
|
|
194
|
+
private narrowphase;
|
|
195
|
+
private checkCollision;
|
|
196
|
+
/**
|
|
197
|
+
* Optimized sphere-sphere collision (analytic, O(1)).
|
|
198
|
+
*/
|
|
199
|
+
private checkSphereSphere;
|
|
200
|
+
/**
|
|
201
|
+
* GJK/EPA narrowphase collision for arbitrary convex shape pairs.
|
|
202
|
+
*
|
|
203
|
+
* 1. Run GJK to determine overlap (boolean).
|
|
204
|
+
* 2. If overlapping, run EPA to get contact normal + penetration depth.
|
|
205
|
+
* 3. Compute an approximate contact point on the surface between the two shapes.
|
|
206
|
+
*/
|
|
207
|
+
private checkGJKEPA;
|
|
208
|
+
private resolveCollision;
|
|
209
|
+
private solveConstraints;
|
|
210
|
+
private solveConstraint;
|
|
211
|
+
private detectIslands;
|
|
212
|
+
getContacts(): ICollisionEvent[];
|
|
213
|
+
getTriggers(): ITriggerEvent[];
|
|
214
|
+
raycast(ray: IRay, options?: IRaycastOptions): IRaycastHit[];
|
|
215
|
+
raycastClosest(ray: IRay, options?: IRaycastOptions): IRaycastHit | null;
|
|
216
|
+
private raycastBody;
|
|
217
|
+
private calculateAABBHitNormal;
|
|
218
|
+
sphereOverlap(center: IVector3, radius: number, filter?: ICollisionFilter): IOverlapResult[];
|
|
219
|
+
boxOverlap(center: IVector3, halfExtents: IVector3, _rotation?: IQuaternion, filter?: ICollisionFilter): IOverlapResult[];
|
|
220
|
+
private getBodyAABB;
|
|
221
|
+
private aabbOverlap;
|
|
222
|
+
private getContactKey;
|
|
223
|
+
private filterMatches;
|
|
224
|
+
dispose(): void;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Create a physics world
|
|
228
|
+
*/
|
|
229
|
+
declare function createPhysicsWorld(config?: IPhysicsWorldConfig): IPhysicsWorld;
|
|
230
|
+
|
|
231
|
+
declare class IslandDetector {
|
|
232
|
+
private bodies;
|
|
233
|
+
private connections;
|
|
234
|
+
/**
|
|
235
|
+
* Reset the detector state
|
|
236
|
+
*/
|
|
237
|
+
reset(): void;
|
|
238
|
+
/**
|
|
239
|
+
* Add a body to the graph
|
|
240
|
+
*/
|
|
241
|
+
addBody(id: string): void;
|
|
242
|
+
/**
|
|
243
|
+
* Add a connection (collision or constraint) between bodies
|
|
244
|
+
*/
|
|
245
|
+
addConnection(bodyA: string, bodyB: string): void;
|
|
246
|
+
/**
|
|
247
|
+
* Detect islands using a Disjoint Set Union (DSU) or BFS
|
|
248
|
+
*/
|
|
249
|
+
detectIslands(): string[][];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* PBDSolver.ts
|
|
254
|
+
*
|
|
255
|
+
* GPU Position-Based Dynamics solver using WebGPU compute shaders.
|
|
256
|
+
* Implements soft-body physics with distance, volume, bending, collision,
|
|
257
|
+
* and attachment constraints solved in parallel via graph coloring.
|
|
258
|
+
*
|
|
259
|
+
* Pipeline per frame:
|
|
260
|
+
* [1] Apply external forces (gravity, wind)
|
|
261
|
+
* [2] Predict new positions (Euler integration)
|
|
262
|
+
* [3] Solve constraints (parallel Gauss-Seidel, N iterations)
|
|
263
|
+
* ├─ Distance constraints (edges maintain rest length)
|
|
264
|
+
* ├─ Volume constraints (tetrahedra maintain rest volume)
|
|
265
|
+
* ├─ Bending constraints (adjacent triangles resist folding)
|
|
266
|
+
* ├─ Collision constraints (SDF-based penetration resolution)
|
|
267
|
+
* └─ Attachment constraints (pinned vertices stay fixed)
|
|
268
|
+
* [4] Update velocities from position delta
|
|
269
|
+
* [5] Apply damping
|
|
270
|
+
* [6] Recompute normals
|
|
271
|
+
*
|
|
272
|
+
* @module physics
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* WGSL: Apply external forces and predict positions via semi-implicit Euler
|
|
277
|
+
*/
|
|
278
|
+
declare const PBD_PREDICT_SHADER = "\nstruct SimParams {\n gravity: vec3f,\n dt: f32,\n wind: vec3f,\n damping: f32,\n numVertices: u32,\n padding: vec3u,\n}\n\n@group(0) @binding(0) var<storage, read_write> positions: array<f32>;\n@group(0) @binding(1) var<storage, read_write> velocities: array<f32>;\n@group(0) @binding(2) var<storage, read_write> predicted: array<f32>;\n@group(0) @binding(3) var<storage, read> masses: array<f32>;\n@group(0) @binding(4) var<uniform> params: SimParams;\n\n@compute @workgroup_size(256)\nfn cs_predict(@builtin(global_invocation_id) gid: vec3u) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n\n let mass = masses[idx];\n let i3 = idx * 3u;\n\n // Load current position and velocity\n var pos = vec3f(positions[i3], positions[i3 + 1u], positions[i3 + 2u]);\n var vel = vec3f(velocities[i3], velocities[i3 + 1u], velocities[i3 + 2u]);\n\n // Skip pinned vertices (mass == 0)\n if (mass > 0.0) {\n // Apply gravity\n vel += params.gravity * params.dt;\n\n // Apply wind (simple drag model)\n vel += params.wind * params.dt / mass;\n\n // Apply damping\n vel *= params.damping;\n\n // Predict position\n pos += vel * params.dt;\n }\n\n // Store predicted position\n predicted[i3] = pos.x;\n predicted[i3 + 1u] = pos.y;\n predicted[i3 + 2u] = pos.z;\n}\n";
|
|
279
|
+
/**
|
|
280
|
+
* WGSL: Solve distance constraints (one color group at a time)
|
|
281
|
+
*/
|
|
282
|
+
declare const PBD_DISTANCE_SHADER = "\nstruct DistanceConstraint {\n vertexA: u32,\n vertexB: u32,\n restLength: f32,\n compliance: f32,\n}\n\nstruct SolveParams {\n dt: f32,\n numConstraints: u32,\n iteration: u32,\n padding: u32,\n}\n\n@group(0) @binding(0) var<storage, read_write> predicted: array<f32>;\n@group(0) @binding(1) var<storage, read> masses: array<f32>;\n@group(0) @binding(2) var<storage, read> constraints: array<DistanceConstraint>;\n@group(0) @binding(3) var<uniform> params: SolveParams;\n\n@compute @workgroup_size(256)\nfn cs_solve_distance(@builtin(global_invocation_id) gid: vec3u) {\n let cIdx = gid.x;\n if (cIdx >= params.numConstraints) { return; }\n\n let c = constraints[cIdx];\n let iA = c.vertexA * 3u;\n let iB = c.vertexB * 3u;\n\n let pA = vec3f(predicted[iA], predicted[iA + 1u], predicted[iA + 2u]);\n let pB = vec3f(predicted[iB], predicted[iB + 1u], predicted[iB + 2u]);\n\n let diff = pB - pA;\n let dist = length(diff);\n\n if (dist < 1e-7) { return; }\n\n let wA = masses[c.vertexA];\n let wB = masses[c.vertexB];\n let invMassA = select(1.0 / wA, 0.0, wA <= 0.0);\n let invMassB = select(1.0 / wB, 0.0, wB <= 0.0);\n let wSum = invMassA + invMassB;\n\n if (wSum < 1e-7) { return; }\n\n // XPBD: compliance scaled by dt\u00B2\n let alpha = c.compliance / (params.dt * params.dt);\n let C = dist - c.restLength;\n let lambda = -C / (wSum + alpha);\n\n let correction = (diff / dist) * lambda;\n\n // Apply corrections\n if (invMassA > 0.0) {\n predicted[iA] -= correction.x * invMassA;\n predicted[iA + 1u] -= correction.y * invMassA;\n predicted[iA + 2u] -= correction.z * invMassA;\n }\n if (invMassB > 0.0) {\n predicted[iB] += correction.x * invMassB;\n predicted[iB + 1u] += correction.y * invMassB;\n predicted[iB + 2u] += correction.z * invMassB;\n }\n}\n";
|
|
283
|
+
/**
|
|
284
|
+
* WGSL: Solve volume constraints (one tetrahedron at a time)
|
|
285
|
+
*/
|
|
286
|
+
declare const PBD_VOLUME_SHADER = "\nstruct VolumeConstraint {\n v0: u32,\n v1: u32,\n v2: u32,\n v3: u32,\n restVolume: f32,\n compliance: f32,\n padding: vec2u,\n}\n\nstruct SolveParams {\n dt: f32,\n numConstraints: u32,\n iteration: u32,\n padding: u32,\n}\n\n@group(0) @binding(0) var<storage, read_write> predicted: array<f32>;\n@group(0) @binding(1) var<storage, read> masses: array<f32>;\n@group(0) @binding(2) var<storage, read> constraints: array<VolumeConstraint>;\n@group(0) @binding(3) var<uniform> params: SolveParams;\n\nfn loadPos(idx: u32) -> vec3f {\n let i = idx * 3u;\n return vec3f(predicted[i], predicted[i + 1u], predicted[i + 2u]);\n}\n\nfn storePos(idx: u32, p: vec3f) {\n let i = idx * 3u;\n predicted[i] = p.x;\n predicted[i + 1u] = p.y;\n predicted[i + 2u] = p.z;\n}\n\n@compute @workgroup_size(64)\nfn cs_solve_volume(@builtin(global_invocation_id) gid: vec3u) {\n let cIdx = gid.x;\n if (cIdx >= params.numConstraints) { return; }\n\n let c = constraints[cIdx];\n let p0 = loadPos(c.v0);\n let p1 = loadPos(c.v1);\n let p2 = loadPos(c.v2);\n let p3 = loadPos(c.v3);\n\n // Signed volume of tetrahedron = dot(p1-p0, cross(p2-p0, p3-p0)) / 6\n let d1 = p1 - p0;\n let d2 = p2 - p0;\n let d3 = p3 - p0;\n let volume = dot(d1, cross(d2, d3)) / 6.0;\n\n let C = volume - c.restVolume;\n if (abs(C) < 1e-7) { return; }\n\n // Gradients of volume w.r.t. each vertex\n let g1 = cross(d2, d3) / 6.0;\n let g2 = cross(d3, d1) / 6.0;\n let g3 = cross(d1, d2) / 6.0;\n let g0 = -(g1 + g2 + g3);\n\n let w0 = select(1.0 / masses[c.v0], 0.0, masses[c.v0] <= 0.0);\n let w1 = select(1.0 / masses[c.v1], 0.0, masses[c.v1] <= 0.0);\n let w2 = select(1.0 / masses[c.v2], 0.0, masses[c.v2] <= 0.0);\n let w3 = select(1.0 / masses[c.v3], 0.0, masses[c.v3] <= 0.0);\n\n let denom = w0 * dot(g0, g0) + w1 * dot(g1, g1) + w2 * dot(g2, g2) + w3 * dot(g3, g3);\n\n if (denom < 1e-7) { return; }\n\n let alpha = c.compliance / (params.dt * params.dt);\n let lambda = -C / (denom + alpha);\n\n if (w0 > 0.0) { storePos(c.v0, p0 + g0 * lambda * w0); }\n if (w1 > 0.0) { storePos(c.v1, p1 + g1 * lambda * w1); }\n if (w2 > 0.0) { storePos(c.v2, p2 + g2 * lambda * w2); }\n if (w3 > 0.0) { storePos(c.v3, p3 + g3 * lambda * w3); }\n}\n";
|
|
287
|
+
/**
|
|
288
|
+
* WGSL: SDF collision constraint solve
|
|
289
|
+
*/
|
|
290
|
+
declare const PBD_COLLISION_SHADER = "\nstruct SDFParams {\n boundsMin: vec3f,\n cellSize: f32,\n boundsMax: vec3f,\n friction: f32,\n gridSizeX: u32,\n gridSizeY: u32,\n gridSizeZ: u32,\n numVertices: u32,\n collisionMargin: f32,\n padding: vec3f,\n}\n\n@group(0) @binding(0) var<storage, read_write> predicted: array<f32>;\n@group(0) @binding(1) var<storage, read> masses: array<f32>;\n@group(0) @binding(2) var<storage, read> sdfData: array<f32>;\n@group(0) @binding(3) var<uniform> params: SDFParams;\n\nfn sampleSDF(pos: vec3f) -> f32 {\n let local = (pos - params.boundsMin) / params.cellSize;\n let gi = vec3u(clamp(vec3i(floor(local)), vec3i(0), vec3i(\n i32(params.gridSizeX) - 2,\n i32(params.gridSizeY) - 2,\n i32(params.gridSizeZ) - 2\n )));\n let f = fract(local);\n\n // Trilinear interpolation\n let idx000 = gi.x + gi.y * params.gridSizeX + gi.z * params.gridSizeX * params.gridSizeY;\n let idx100 = idx000 + 1u;\n let idx010 = idx000 + params.gridSizeX;\n let idx110 = idx010 + 1u;\n let idx001 = idx000 + params.gridSizeX * params.gridSizeY;\n let idx101 = idx001 + 1u;\n let idx011 = idx001 + params.gridSizeX;\n let idx111 = idx011 + 1u;\n\n let c00 = mix(sdfData[idx000], sdfData[idx100], f.x);\n let c10 = mix(sdfData[idx010], sdfData[idx110], f.x);\n let c01 = mix(sdfData[idx001], sdfData[idx101], f.x);\n let c11 = mix(sdfData[idx011], sdfData[idx111], f.x);\n let c0 = mix(c00, c10, f.y);\n let c1 = mix(c01, c11, f.y);\n return mix(c0, c1, f.z);\n}\n\nfn sdfGradient(pos: vec3f) -> vec3f {\n let eps = params.cellSize * 0.5;\n return normalize(vec3f(\n sampleSDF(pos + vec3f(eps, 0.0, 0.0)) - sampleSDF(pos - vec3f(eps, 0.0, 0.0)),\n sampleSDF(pos + vec3f(0.0, eps, 0.0)) - sampleSDF(pos - vec3f(0.0, eps, 0.0)),\n sampleSDF(pos + vec3f(0.0, 0.0, eps)) - sampleSDF(pos - vec3f(0.0, 0.0, eps))\n ));\n}\n\n@compute @workgroup_size(256)\nfn cs_solve_collision(@builtin(global_invocation_id) gid: vec3u) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n if (masses[idx] <= 0.0) { return; }\n\n let i3 = idx * 3u;\n let pos = vec3f(predicted[i3], predicted[i3 + 1u], predicted[i3 + 2u]);\n\n // Check if inside SDF bounds\n if (any(pos < params.boundsMin) || any(pos > params.boundsMax)) { return; }\n\n let dist = sampleSDF(pos);\n\n if (dist < params.collisionMargin) {\n let normal = sdfGradient(pos);\n let penetration = params.collisionMargin - dist;\n\n // Push vertex out along SDF gradient\n let correction = normal * penetration;\n predicted[i3] += correction.x;\n predicted[i3 + 1u] += correction.y;\n predicted[i3 + 2u] += correction.z;\n }\n}\n";
|
|
291
|
+
/**
|
|
292
|
+
* WGSL: Update velocities from position delta and apply damping
|
|
293
|
+
*/
|
|
294
|
+
declare const PBD_VELOCITY_SHADER = "\nstruct VelParams {\n dt: f32,\n damping: f32,\n numVertices: u32,\n padding: u32,\n}\n\n@group(0) @binding(0) var<storage, read> positions: array<f32>;\n@group(0) @binding(1) var<storage, read_write> velocities: array<f32>;\n@group(0) @binding(2) var<storage, read> predicted: array<f32>;\n@group(0) @binding(3) var<uniform> params: VelParams;\n\n@compute @workgroup_size(256)\nfn cs_update_velocity(@builtin(global_invocation_id) gid: vec3u) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n\n let i3 = idx * 3u;\n let invDt = 1.0 / params.dt;\n\n velocities[i3] = (predicted[i3] - positions[i3]) * invDt;\n velocities[i3 + 1u] = (predicted[i3 + 1u] - positions[i3 + 1u]) * invDt;\n velocities[i3 + 2u] = (predicted[i3 + 2u] - positions[i3 + 2u]) * invDt;\n}\n";
|
|
295
|
+
/**
|
|
296
|
+
* WGSL: Copy predicted back to positions (finalize step)
|
|
297
|
+
*/
|
|
298
|
+
declare const PBD_FINALIZE_SHADER = "\nstruct FinalizeParams {\n numVertices: u32,\n padding: vec3u,\n}\n\n@group(0) @binding(0) var<storage, read_write> positions: array<f32>;\n@group(0) @binding(1) var<storage, read> predicted: array<f32>;\n@group(0) @binding(2) var<uniform> params: FinalizeParams;\n\n@compute @workgroup_size(256)\nfn cs_finalize(@builtin(global_invocation_id) gid: vec3u) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n\n let i3 = idx * 3u;\n positions[i3] = predicted[i3];\n positions[i3 + 1u] = predicted[i3 + 1u];\n positions[i3 + 2u] = predicted[i3 + 2u];\n}\n";
|
|
299
|
+
/**
|
|
300
|
+
* WGSL: Recompute vertex normals from triangle indices
|
|
301
|
+
*/
|
|
302
|
+
declare const PBD_NORMALS_SHADER = "\nstruct NormalParams {\n numTriangles: u32,\n numVertices: u32,\n padding: vec2u,\n}\n\n@group(0) @binding(0) var<storage, read> positions: array<f32>;\n@group(0) @binding(1) var<storage, read_write> normals: array<atomic<i32>>;\n@group(0) @binding(2) var<storage, read> indices: array<u32>;\n@group(0) @binding(3) var<uniform> params: NormalParams;\n\nfn loadPos(idx: u32) -> vec3f {\n let i = idx * 3u;\n return vec3f(positions[i], positions[i + 1u], positions[i + 2u]);\n}\n\n// Atomic accumulate normal via fixed-point (multiply by 1e6, cast to i32)\nfn atomicAddNormal(vertIdx: u32, n: vec3f) {\n let i = vertIdx * 3u;\n let scale = 1000000.0;\n atomicAdd(&normals[i], i32(n.x * scale));\n atomicAdd(&normals[i + 1u], i32(n.y * scale));\n atomicAdd(&normals[i + 2u], i32(n.z * scale));\n}\n\n@compute @workgroup_size(256)\nfn cs_compute_normals(@builtin(global_invocation_id) gid: vec3u) {\n let triIdx = gid.x;\n if (triIdx >= params.numTriangles) { return; }\n\n let i0 = indices[triIdx * 3u];\n let i1 = indices[triIdx * 3u + 1u];\n let i2 = indices[triIdx * 3u + 2u];\n\n let p0 = loadPos(i0);\n let p1 = loadPos(i1);\n let p2 = loadPos(i2);\n\n let faceNormal = cross(p1 - p0, p2 - p0);\n\n atomicAddNormal(i0, faceNormal);\n atomicAddNormal(i1, faceNormal);\n atomicAddNormal(i2, faceNormal);\n}\n";
|
|
303
|
+
/**
|
|
304
|
+
* WGSL: Normalize accumulated vertex normals
|
|
305
|
+
*/
|
|
306
|
+
declare const PBD_NORMALIZE_SHADER = "\nstruct NormalizeParams {\n numVertices: u32,\n padding: vec3u,\n}\n\n@group(0) @binding(0) var<storage, read_write> normalsI32: array<i32>;\n@group(0) @binding(1) var<storage, read_write> normalsF32: array<f32>;\n@group(0) @binding(2) var<uniform> params: NormalizeParams;\n\n@compute @workgroup_size(256)\nfn cs_normalize_normals(@builtin(global_invocation_id) gid: vec3u) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n\n let i3 = idx * 3u;\n let scale = 1.0 / 1000000.0;\n var n = vec3f(\n f32(normalsI32[i3]) * scale,\n f32(normalsI32[i3 + 1u]) * scale,\n f32(normalsI32[i3 + 2u]) * scale\n );\n\n let len = length(n);\n if (len > 1e-7) {\n n /= len;\n } else {\n n = vec3f(0.0, 1.0, 0.0);\n }\n\n normalsF32[i3] = n.x;\n normalsF32[i3 + 1u] = n.y;\n normalsF32[i3 + 2u] = n.z;\n\n // Reset atomic accumulator for next frame\n normalsI32[i3] = 0;\n normalsI32[i3 + 1u] = 0;\n normalsI32[i3 + 2u] = 0;\n}\n";
|
|
307
|
+
/**
|
|
308
|
+
* WGSL compute shader for bending constraints.
|
|
309
|
+
* Maintains rest dihedral angles between adjacent triangle pairs.
|
|
310
|
+
* Uses XPBD formulation with compliance for stable soft constraints.
|
|
311
|
+
*
|
|
312
|
+
* Buffers:
|
|
313
|
+
* binding(1) positions — read_write predicted positions (flat xyz)
|
|
314
|
+
* binding(2) masses — read per-vertex masses (0 = pinned)
|
|
315
|
+
* binding(3) constraints — read 4 u32 per constraint [v0, v1, v2, v3]
|
|
316
|
+
* binding(4) restAngles — read rest dihedral angle per constraint
|
|
317
|
+
*/
|
|
318
|
+
declare const PBD_BENDING_SHADER = "\nstruct Params {\n dt: f32,\n numConstraints: u32,\n compliance: f32,\n _pad: f32,\n};\n\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read_write> positions: array<f32>;\n@group(0) @binding(2) var<storage, read> masses: array<f32>;\n@group(0) @binding(3) var<storage, read> constraints: array<u32>;\n@group(0) @binding(4) var<storage, read> restAngles: array<f32>;\n\nfn loadPos(i: u32) -> vec3<f32> {\n return vec3<f32>(positions[i * 3u], positions[i * 3u + 1u], positions[i * 3u + 2u]);\n}\n\nfn storePos(i: u32, p: vec3<f32>) {\n positions[i * 3u] = p.x;\n positions[i * 3u + 1u] = p.y;\n positions[i * 3u + 2u] = p.z;\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n if (idx >= params.numConstraints) { return; }\n\n // v0-v1 = shared edge, v2 = opposite on face 1, v3 = opposite on face 2\n let v0 = constraints[idx * 4u];\n let v1 = constraints[idx * 4u + 1u];\n let v2 = constraints[idx * 4u + 2u];\n let v3 = constraints[idx * 4u + 3u];\n\n let p0 = loadPos(v0);\n let p1 = loadPos(v1);\n let p2 = loadPos(v2);\n let p3 = loadPos(v3);\n\n // Shared edge\n let e = p1 - p0;\n let eLen = length(e);\n if (eLen < 1e-7) { return; }\n let eNorm = e / eLen;\n\n // Vectors from v0 to opposite vertices\n let d2 = p2 - p0;\n let d3 = p3 - p0;\n\n // Face normals (unnormalized, magnitude = 2 * triangle area)\n let n1 = cross(e, d2);\n let n2 = cross(e, d3);\n let n1Len = length(n1);\n let n2Len = length(n2);\n if (n1Len < 1e-7 || n2Len < 1e-7) { return; }\n\n let n1n = n1 / n1Len;\n let n2n = n2 / n2Len;\n\n // Dihedral angle via atan2 for full [-pi, pi] range\n let cosTheta = clamp(dot(n1n, n2n), -1.0, 1.0);\n let sinTheta = dot(cross(n1n, n2n), eNorm);\n let theta = atan2(sinTheta, cosTheta);\n\n // Constraint: C = theta - restAngle\n let restAngle = restAngles[idx];\n let C = theta - restAngle;\n if (abs(C) < 1e-6) { return; }\n\n // Perpendicular distances from opposite vertices to shared edge\n let h2 = n1Len / eLen;\n let h3 = n2Len / eLen;\n if (h2 < 1e-7 || h3 < 1e-7) { return; }\n\n // Gradients of theta w.r.t. vertex positions (Bridson formulation)\n let g2 = n1n / h2;\n let g3 = -n2n / h3;\n\n // Parametric projections along shared edge for gradient distribution\n let eDotE = eLen * eLen;\n let s2 = dot(d2, e) / eDotE;\n let s3 = dot(d3, e) / eDotE;\n\n // Edge vertex gradients (sum of all gradients = 0, translation invariance)\n let g0 = -(1.0 - s2) * g2 - (1.0 - s3) * g3;\n let g1 = -s2 * g2 - s3 * g3;\n\n // Inverse masses\n let w0 = select(0.0, 1.0 / masses[v0], masses[v0] > 0.0);\n let w1 = select(0.0, 1.0 / masses[v1], masses[v1] > 0.0);\n let w2 = select(0.0, 1.0 / masses[v2], masses[v2] > 0.0);\n let w3 = select(0.0, 1.0 / masses[v3], masses[v3] > 0.0);\n\n // XPBD: alpha = compliance / dt^2\n let alpha = params.compliance / (params.dt * params.dt);\n let denom = w0 * dot(g0, g0) + w1 * dot(g1, g1)\n + w2 * dot(g2, g2) + w3 * dot(g3, g3) + alpha;\n if (denom < 1e-10) { return; }\n\n let lambda = -C / denom;\n\n // Apply position corrections\n if (w0 > 0.0) { storePos(v0, p0 + g0 * lambda * w0); }\n if (w1 > 0.0) { storePos(v1, p1 + g1 * lambda * w1); }\n if (w2 > 0.0) { storePos(v2, p2 + g2 * lambda * w2); }\n if (w3 > 0.0) { storePos(v3, p3 + g3 * lambda * w3); }\n}\n";
|
|
319
|
+
/**
|
|
320
|
+
* WGSL compute shader for attachment constraints.
|
|
321
|
+
* Pins vertices to target positions with XPBD compliance.
|
|
322
|
+
* compliance=0 → hard pin, compliance>0 → soft spring.
|
|
323
|
+
*
|
|
324
|
+
* Buffers:
|
|
325
|
+
* binding(1) positions — read_write predicted positions (flat xyz)
|
|
326
|
+
* binding(2) masses — read per-vertex masses
|
|
327
|
+
* binding(3) vertexIndices — read vertex index per constraint
|
|
328
|
+
* binding(4) targets — read target positions (flat xyz, 3 per constraint)
|
|
329
|
+
* binding(5) compliances — read compliance per constraint
|
|
330
|
+
*/
|
|
331
|
+
declare const PBD_ATTACHMENT_SHADER = "\nstruct Params {\n dt: f32,\n numConstraints: u32,\n _pad0: f32,\n _pad1: f32,\n};\n\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read_write> positions: array<f32>;\n@group(0) @binding(2) var<storage, read> masses: array<f32>;\n@group(0) @binding(3) var<storage, read> vertexIndices: array<u32>;\n@group(0) @binding(4) var<storage, read> targets: array<f32>;\n@group(0) @binding(5) var<storage, read> compliances: array<f32>;\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n if (idx >= params.numConstraints) { return; }\n\n let vi = vertexIndices[idx];\n let mass = masses[vi];\n if (mass <= 0.0) { return; } // Pinned vertex, already at target\n\n let px = positions[vi * 3u];\n let py = positions[vi * 3u + 1u];\n let pz = positions[vi * 3u + 2u];\n\n let tx = targets[idx * 3u];\n let ty = targets[idx * 3u + 1u];\n let tz = targets[idx * 3u + 2u];\n\n let dx = tx - px;\n let dy = ty - py;\n let dz = tz - pz;\n\n let dist = sqrt(dx * dx + dy * dy + dz * dz);\n if (dist < 1e-7) { return; }\n\n let compliance = compliances[idx];\n let w = 1.0 / mass;\n let alpha = compliance / (params.dt * params.dt);\n\n // XPBD: C = dist, gradient = normalize(d), single vertex\n let lambda = dist / (w + alpha);\n\n let nx = dx / dist;\n let ny = dy / dist;\n let nz = dz / dist;\n\n positions[vi * 3u] = px + nx * lambda * w;\n positions[vi * 3u + 1u] = py + ny * lambda * w;\n positions[vi * 3u + 2u] = pz + nz * lambda * w;\n}\n";
|
|
332
|
+
/**
|
|
333
|
+
* WGSL compute shader: build spatial hash grid.
|
|
334
|
+
* Hashes each vertex position into a 3D grid cell and atomically appends
|
|
335
|
+
* the vertex index to that cell's list via a prefix-sum-style counter array.
|
|
336
|
+
*
|
|
337
|
+
* Two-pass approach:
|
|
338
|
+
* Pass 1 (this shader): count vertices per cell + write vertex→cell mapping
|
|
339
|
+
* CPU prefix sum: compute cell offsets from counts
|
|
340
|
+
* Pass 2 (resolve shader): iterate 27 neighbors, resolve penetrations
|
|
341
|
+
*/
|
|
342
|
+
declare const PBD_HASH_BUILD_SHADER = "\nstruct Params {\n numVertices: u32,\n cellSize: f32,\n gridDimX: u32,\n gridDimY: u32,\n gridDimZ: u32,\n originX: f32,\n originY: f32,\n originZ: f32,\n};\n\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read> positions: array<f32>;\n@group(0) @binding(2) var<storage, read_write> cellCounts: array<atomic<u32>>;\n@group(0) @binding(3) var<storage, read_write> vertexCells: array<u32>;\n\nfn hashCell(ix: u32, iy: u32, iz: u32) -> u32 {\n return ix + iy * params.gridDimX + iz * params.gridDimX * params.gridDimY;\n}\n\n@compute @workgroup_size(256)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n\n let px = positions[idx * 3u];\n let py = positions[idx * 3u + 1u];\n let pz = positions[idx * 3u + 2u];\n\n let ix = clamp(u32(floor((px - params.originX) / params.cellSize)), 0u, params.gridDimX - 1u);\n let iy = clamp(u32(floor((py - params.originY) / params.cellSize)), 0u, params.gridDimY - 1u);\n let iz = clamp(u32(floor((pz - params.originZ) / params.cellSize)), 0u, params.gridDimZ - 1u);\n\n let cell = hashCell(ix, iy, iz);\n vertexCells[idx] = cell;\n atomicAdd(&cellCounts[cell], 1u);\n}\n";
|
|
343
|
+
/**
|
|
344
|
+
* WGSL compute shader: resolve self-collisions.
|
|
345
|
+
* For each vertex, iterate all vertices in the 27 neighboring cells
|
|
346
|
+
* and push apart any that are closer than the collision radius.
|
|
347
|
+
*
|
|
348
|
+
* Buffers:
|
|
349
|
+
* binding(1) positions — read_write predicted positions
|
|
350
|
+
* binding(2) masses — read per-vertex masses
|
|
351
|
+
* binding(3) vertexCells — read cell index per vertex
|
|
352
|
+
* binding(4) cellOffsets — read prefix-sum offsets per cell (from CPU)
|
|
353
|
+
* binding(5) cellCounts — read vertex count per cell
|
|
354
|
+
* binding(6) sortedVerts — read vertex indices sorted by cell
|
|
355
|
+
*/
|
|
356
|
+
declare const PBD_SELF_COLLISION_SHADER = "\nstruct Params {\n numVertices: u32,\n collisionRadius: f32,\n gridDimX: u32,\n gridDimY: u32,\n gridDimZ: u32,\n originX: f32,\n originY: f32,\n originZ: f32,\n cellSize: f32,\n _pad: f32,\n _pad2: f32,\n _pad3: f32,\n};\n\n@group(0) @binding(0) var<uniform> params: Params;\n@group(0) @binding(1) var<storage, read_write> positions: array<f32>;\n@group(0) @binding(2) var<storage, read> masses: array<f32>;\n@group(0) @binding(3) var<storage, read> vertexCells: array<u32>;\n@group(0) @binding(4) var<storage, read> cellOffsets: array<u32>;\n@group(0) @binding(5) var<storage, read> cellCounts2: array<u32>;\n@group(0) @binding(6) var<storage, read> sortedVerts: array<u32>;\n\nfn hashCell(ix: u32, iy: u32, iz: u32) -> u32 {\n return ix + iy * params.gridDimX + iz * params.gridDimX * params.gridDimY;\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n if (idx >= params.numVertices) { return; }\n\n let mi = masses[idx];\n if (mi <= 0.0) { return; }\n let wi = 1.0 / mi;\n\n let px = positions[idx * 3u];\n let py = positions[idx * 3u + 1u];\n let pz = positions[idx * 3u + 2u];\n\n let ix = clamp(u32(floor((px - params.originX) / params.cellSize)), 0u, params.gridDimX - 1u);\n let iy = clamp(u32(floor((py - params.originY) / params.cellSize)), 0u, params.gridDimY - 1u);\n let iz = clamp(u32(floor((pz - params.originZ) / params.cellSize)), 0u, params.gridDimZ - 1u);\n\n let radius = params.collisionRadius;\n let radiusSq = radius * radius;\n\n var corrX = 0.0;\n var corrY = 0.0;\n var corrZ = 0.0;\n\n // Iterate 27 neighbor cells\n for (var dz: i32 = -1; dz <= 1; dz++) {\n for (var dy: i32 = -1; dy <= 1; dy++) {\n for (var dx: i32 = -1; dx <= 1; dx++) {\n let nx = i32(ix) + dx;\n let ny = i32(iy) + dy;\n let nz = i32(iz) + dz;\n\n if (nx < 0 || nx >= i32(params.gridDimX) ||\n ny < 0 || ny >= i32(params.gridDimY) ||\n nz < 0 || nz >= i32(params.gridDimZ)) { continue; }\n\n let cell = hashCell(u32(nx), u32(ny), u32(nz));\n let offset = cellOffsets[cell];\n let count = cellCounts2[cell];\n\n for (var k: u32 = 0u; k < count; k++) {\n let j = sortedVerts[offset + k];\n if (j == idx) { continue; }\n\n let mj = masses[j];\n if (mj <= 0.0) { continue; }\n\n let qx = positions[j * 3u] - px;\n let qy = positions[j * 3u + 1u] - py;\n let qz = positions[j * 3u + 2u] - pz;\n let distSq = qx * qx + qy * qy + qz * qz;\n\n if (distSq < radiusSq && distSq > 1e-10) {\n let dist = sqrt(distSq);\n let penetration = radius - dist;\n let wj = 1.0 / mj;\n let wSum = wi + wj;\n let scale = penetration / (wSum * dist);\n\n // Push this vertex away (negative direction)\n corrX -= qx * scale * wi;\n corrY -= qy * scale * wi;\n corrZ -= qz * scale * wi;\n }\n }\n }\n }\n }\n\n positions[idx * 3u] = px + corrX;\n positions[idx * 3u + 1u] = py + corrY;\n positions[idx * 3u + 2u] = pz + corrZ;\n}\n";
|
|
357
|
+
/**
|
|
358
|
+
* Greedy graph coloring for distance/bending constraints.
|
|
359
|
+
* Constraints sharing a vertex cannot be the same color — this allows
|
|
360
|
+
* same-color constraints to execute in parallel without data races.
|
|
361
|
+
*/
|
|
362
|
+
declare function colorConstraints(constraints: Array<{
|
|
363
|
+
vertexA: number;
|
|
364
|
+
vertexB: number;
|
|
365
|
+
}>, numVertices: number): IConstraintColoring;
|
|
366
|
+
/**
|
|
367
|
+
* Generate tetrahedral mesh from a surface triangle mesh.
|
|
368
|
+
* Uses simple fan tetrahedralization from centroid — suitable for convex
|
|
369
|
+
* and mildly concave meshes. For complex shapes, use Delaunay tetrahedralization.
|
|
370
|
+
*/
|
|
371
|
+
declare function generateTetrahedra(positions: Float32Array, indices: Uint32Array): {
|
|
372
|
+
tetIndices: Uint32Array;
|
|
373
|
+
restVolumes: Float32Array;
|
|
374
|
+
};
|
|
375
|
+
/**
|
|
376
|
+
* Extract unique edges from triangle indices for distance constraints.
|
|
377
|
+
*/
|
|
378
|
+
declare function extractEdges(indices: Uint32Array, _numVertices: number): {
|
|
379
|
+
edges: Uint32Array;
|
|
380
|
+
restLengths: Float32Array;
|
|
381
|
+
positions: Float32Array;
|
|
382
|
+
} | {
|
|
383
|
+
edges: Uint32Array;
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* Compute rest lengths for distance constraints.
|
|
387
|
+
*/
|
|
388
|
+
declare function computeRestLengths(positions: Float32Array, edges: Uint32Array): Float32Array;
|
|
389
|
+
/**
|
|
390
|
+
* Extract bending constraint pairs from a triangle mesh.
|
|
391
|
+
* Finds pairs of triangles sharing an edge and computes rest dihedral angles.
|
|
392
|
+
*
|
|
393
|
+
* @returns constraints — flat Uint32Array, 4 indices per constraint [v0, v1, v2, v3]
|
|
394
|
+
* where (v0,v1) is the shared edge and v2, v3 are the opposite vertices.
|
|
395
|
+
* @returns restAngles — Float32Array of rest dihedral angles (one per constraint).
|
|
396
|
+
*/
|
|
397
|
+
declare function extractBendingPairs(indices: Uint32Array, positions: Float32Array): {
|
|
398
|
+
constraints: Uint32Array;
|
|
399
|
+
restAngles: Float32Array;
|
|
400
|
+
};
|
|
401
|
+
/**
|
|
402
|
+
* Generate a signed distance field from a triangle mesh.
|
|
403
|
+
* Uses brute-force closest-triangle for each grid cell.
|
|
404
|
+
* For production, use a spatial acceleration structure.
|
|
405
|
+
*/
|
|
406
|
+
declare function generateSDF(vertices: Float32Array, indices: Uint32Array, gridSize: number, padding?: number): ISDFCollider;
|
|
407
|
+
/**
|
|
408
|
+
* CPU-side PBD solver. Mirrors the GPU pipeline for environments without WebGPU.
|
|
409
|
+
*/
|
|
410
|
+
declare class PBDSolverCPU {
|
|
411
|
+
private config;
|
|
412
|
+
private state;
|
|
413
|
+
private distanceConstraints;
|
|
414
|
+
private volumeConstraints;
|
|
415
|
+
private bendingConstraints;
|
|
416
|
+
private attachmentConstraints;
|
|
417
|
+
private densityParticles;
|
|
418
|
+
private densityNeighbors;
|
|
419
|
+
private densityRestDensity;
|
|
420
|
+
private densityKernelRadius;
|
|
421
|
+
private densityCompliance;
|
|
422
|
+
private coloring;
|
|
423
|
+
private sdfColliders;
|
|
424
|
+
constructor(config: ISoftBodyConfig);
|
|
425
|
+
private buildConstraints;
|
|
426
|
+
private computeTetVolume;
|
|
427
|
+
/**
|
|
428
|
+
* Add an SDF collider for collision detection
|
|
429
|
+
*/
|
|
430
|
+
addCollider(collider: ISDFCollider): void;
|
|
431
|
+
/**
|
|
432
|
+
* Pin a vertex to a world position.
|
|
433
|
+
* @param compliance 0 = hard pin, >0 = soft spring (XPBD compliant)
|
|
434
|
+
*/
|
|
435
|
+
pinVertex(vertexIndex: number, position: IVector3, compliance?: number): void;
|
|
436
|
+
/**
|
|
437
|
+
* Unpin a vertex
|
|
438
|
+
*/
|
|
439
|
+
unpinVertex(vertexIndex: number): void;
|
|
440
|
+
/**
|
|
441
|
+
* Apply an impulse at a position (for grab interaction)
|
|
442
|
+
*/
|
|
443
|
+
applyImpulse(position: IVector3, force: IVector3, radius: number): void;
|
|
444
|
+
/**
|
|
445
|
+
* Step the simulation forward by dt seconds
|
|
446
|
+
*/
|
|
447
|
+
step(dt: number): ISoftBodyState;
|
|
448
|
+
private solveDistanceConstraint;
|
|
449
|
+
private solveVolumeConstraint;
|
|
450
|
+
private solveBendingConstraint;
|
|
451
|
+
private solveAttachmentConstraint;
|
|
452
|
+
/**
|
|
453
|
+
* CPU density constraint solver (SPH-style for fluid-PBD coupling).
|
|
454
|
+
* Each fluid particle corrects toward rest density using neighbor kernel.
|
|
455
|
+
*/
|
|
456
|
+
private solveDensityConstraints;
|
|
457
|
+
/**
|
|
458
|
+
* Configure density constraints for fluid particles in the unified buffer.
|
|
459
|
+
* Call this to enable fluid-PBD coupling.
|
|
460
|
+
*/
|
|
461
|
+
setDensityParticles(particleIndices: number[], neighbors: number[][], restDensity?: number, kernelRadius?: number, compliance?: number): void;
|
|
462
|
+
private solveSelfCollision;
|
|
463
|
+
/**
|
|
464
|
+
* Update the target position of an existing attachment constraint.
|
|
465
|
+
* Used for dynamic targets like grab interaction or rigid body following.
|
|
466
|
+
*/
|
|
467
|
+
updateAttachmentTarget(vertexIndex: number, newTarget: IVector3): void;
|
|
468
|
+
private solveSdfCollision;
|
|
469
|
+
private recomputeNormals;
|
|
470
|
+
/** Get current state (positions, normals, etc.) */
|
|
471
|
+
getState(): ISoftBodyState;
|
|
472
|
+
/** Pause/resume */
|
|
473
|
+
setActive(active: boolean): void;
|
|
474
|
+
/** Reset to rest shape */
|
|
475
|
+
reset(): void;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* GPU-accelerated PBD solver.
|
|
479
|
+
* Uses WebGPU compute shaders for massively parallel constraint solving.
|
|
480
|
+
*/
|
|
481
|
+
declare class PBDSolverGPU {
|
|
482
|
+
private config;
|
|
483
|
+
private state;
|
|
484
|
+
private device;
|
|
485
|
+
private buffers;
|
|
486
|
+
private pipelines;
|
|
487
|
+
private bindGroups;
|
|
488
|
+
private coloring;
|
|
489
|
+
constructor(config: ISoftBodyConfig, device: GPUDevice);
|
|
490
|
+
/**
|
|
491
|
+
* Initialize GPU resources (buffers, pipelines, bind groups).
|
|
492
|
+
*/
|
|
493
|
+
initialize(): Promise<void>;
|
|
494
|
+
private createBuffer;
|
|
495
|
+
private createPipeline;
|
|
496
|
+
/**
|
|
497
|
+
* Step the simulation.
|
|
498
|
+
*/
|
|
499
|
+
step(dt: number): ISoftBodyState;
|
|
500
|
+
getState(): ISoftBodyState;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Create a soft-body solver with the given configuration.
|
|
504
|
+
* Applies preset parameters if a preset is specified.
|
|
505
|
+
*/
|
|
506
|
+
declare function createPBDSolver(config: ISoftBodyConfig): Promise<PBDSolverCPU | PBDSolverGPU>;
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* SoftBodyGrabController
|
|
510
|
+
*
|
|
511
|
+
* Bridges the @grabbable trait to PBD attachment constraints.
|
|
512
|
+
* When a hand grabs a soft body, finds the closest vertices within
|
|
513
|
+
* a grab radius, creates attachment constraints with distance-weighted
|
|
514
|
+
* compliance, and updates their targets each frame as the hand moves.
|
|
515
|
+
*/
|
|
516
|
+
|
|
517
|
+
interface GrabConfig {
|
|
518
|
+
/** Maximum number of vertices to grab */
|
|
519
|
+
maxVertices: number;
|
|
520
|
+
/** Grab radius around the hand position */
|
|
521
|
+
grabRadius: number;
|
|
522
|
+
/** Base compliance for attachment (0 = hard, higher = softer) */
|
|
523
|
+
baseCompliance: number;
|
|
524
|
+
/** Compliance scales with distance: compliance = base * (1 + dist/radius * falloff) */
|
|
525
|
+
complianceFalloff: number;
|
|
526
|
+
}
|
|
527
|
+
declare class SoftBodyGrabController {
|
|
528
|
+
private activeGrabs;
|
|
529
|
+
private config;
|
|
530
|
+
constructor(config?: Partial<GrabConfig>);
|
|
531
|
+
/**
|
|
532
|
+
* Start grabbing the soft body at the given hand position.
|
|
533
|
+
* Finds the closest vertices and creates attachment constraints.
|
|
534
|
+
*/
|
|
535
|
+
grabStart(handId: string, handPosition: IVector3, solver: PBDSolverCPU): void;
|
|
536
|
+
/**
|
|
537
|
+
* Update grab target positions as the hand moves.
|
|
538
|
+
* Each grabbed vertex follows the hand with its original local offset preserved.
|
|
539
|
+
*/
|
|
540
|
+
grabUpdate(handId: string, handPosition: IVector3): void;
|
|
541
|
+
/**
|
|
542
|
+
* Release the grab — remove all attachment constraints for this hand.
|
|
543
|
+
*/
|
|
544
|
+
grabEnd(handId: string): void;
|
|
545
|
+
/**
|
|
546
|
+
* Check if a hand is currently grabbing.
|
|
547
|
+
*/
|
|
548
|
+
isGrabbing(handId: string): boolean;
|
|
549
|
+
/**
|
|
550
|
+
* Get all active grab hand IDs.
|
|
551
|
+
*/
|
|
552
|
+
getActiveGrabs(): string[];
|
|
553
|
+
/**
|
|
554
|
+
* Release all grabs (e.g., when soft body is destroyed).
|
|
555
|
+
*/
|
|
556
|
+
releaseAll(): void;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* MLSMPMFluid — GPU-accelerated MLS-MPM fluid simulation.
|
|
561
|
+
*
|
|
562
|
+
* Uses WebGPU compute shaders for Moving Least Squares Material Point Method:
|
|
563
|
+
* Frame pipeline:
|
|
564
|
+
* [1] Grid Clear
|
|
565
|
+
* [2] Particle-to-Grid (P2G) — scatter mass/momentum via atomicAdd
|
|
566
|
+
* [3] Grid Update — gravity, boundaries, momentum → velocity
|
|
567
|
+
* [4] Grid-to-Particle (G2P) — gather velocity, update APIC C matrix + J
|
|
568
|
+
*
|
|
569
|
+
* Rendering pipeline (SSFR):
|
|
570
|
+
* [1] Depth pass — particle → depth buffer
|
|
571
|
+
* [2] Thickness pass — additive particle thickness
|
|
572
|
+
* [3] Bilateral filter — smooth depth, compute normals
|
|
573
|
+
* [4] Final shade — Fresnel + Beer-Lambert + refraction
|
|
574
|
+
*
|
|
575
|
+
* Performance targets:
|
|
576
|
+
* - 100K particles @ 60 FPS on iGPU
|
|
577
|
+
* - 300K particles @ 30 FPS on discrete GPU
|
|
578
|
+
*
|
|
579
|
+
* @module physics
|
|
580
|
+
*/
|
|
581
|
+
interface MLSMPMConfig {
|
|
582
|
+
/** Fluid behavior: liquid (incompressible) or gas (compressible) */
|
|
583
|
+
type: 'liquid' | 'gas';
|
|
584
|
+
/** Number of simulation particles */
|
|
585
|
+
particleCount: number;
|
|
586
|
+
/** Dynamic viscosity (default: 0.01 for water) */
|
|
587
|
+
viscosity: number;
|
|
588
|
+
/** Grid cells per axis (default: 128) */
|
|
589
|
+
gridResolution: number;
|
|
590
|
+
/** Domain size in world units (default: 10) */
|
|
591
|
+
domainSize: number;
|
|
592
|
+
/** SSFR render resolution scale (0.5 = half-res, default) */
|
|
593
|
+
resolutionScale: number;
|
|
594
|
+
/** Target rest density (default: 1000 for water) */
|
|
595
|
+
restDensity: number;
|
|
596
|
+
/** Compressibility stiffness (default: 50) */
|
|
597
|
+
bulkModulus: number;
|
|
598
|
+
/** Particle visual radius (default: 0.02) */
|
|
599
|
+
particleRadius: number;
|
|
600
|
+
/** Gravity Y component (default: -9.81) */
|
|
601
|
+
gravity: number;
|
|
602
|
+
/** SSFR absorption color RGB (default: [0.4, 0.04, 0.0] blue water) */
|
|
603
|
+
absorptionColor: [number, number, number];
|
|
604
|
+
/** SSFR absorption strength (default: 2.0) */
|
|
605
|
+
absorptionStrength: number;
|
|
606
|
+
}
|
|
607
|
+
interface MLSMPMStats {
|
|
608
|
+
particleCount: number;
|
|
609
|
+
gridResolution: number;
|
|
610
|
+
lastStepMs: number;
|
|
611
|
+
lastRenderMs: number;
|
|
612
|
+
gpuBufferSizeMB: number;
|
|
613
|
+
}
|
|
614
|
+
declare class MLSMPMFluid {
|
|
615
|
+
private config;
|
|
616
|
+
private device;
|
|
617
|
+
private disposed;
|
|
618
|
+
private particlePositions;
|
|
619
|
+
private particleVelocities;
|
|
620
|
+
private particleC;
|
|
621
|
+
private particleJ;
|
|
622
|
+
private gridMass;
|
|
623
|
+
private gridMomentumX;
|
|
624
|
+
private gridMomentumY;
|
|
625
|
+
private gridMomentumZ;
|
|
626
|
+
private gridVelocity;
|
|
627
|
+
private simParamsBuffer;
|
|
628
|
+
/** External force (wind) applied during grid update [x, y, z] in m/s² */
|
|
629
|
+
private externalForce;
|
|
630
|
+
private gridClearPipeline;
|
|
631
|
+
private p2gPipeline;
|
|
632
|
+
private gridUpdatePipeline;
|
|
633
|
+
private g2pPipeline;
|
|
634
|
+
private p2gBindGroup;
|
|
635
|
+
private gridClearBindGroup;
|
|
636
|
+
private gridUpdateBindGroup;
|
|
637
|
+
private g2pBindGroup;
|
|
638
|
+
private lastStepMs;
|
|
639
|
+
private lastRenderMs;
|
|
640
|
+
constructor(config?: Partial<MLSMPMConfig>);
|
|
641
|
+
/**
|
|
642
|
+
* Initialize GPU resources and compile shaders.
|
|
643
|
+
* Must be called before step().
|
|
644
|
+
*/
|
|
645
|
+
init(device: GPUDevice): Promise<void>;
|
|
646
|
+
/**
|
|
647
|
+
* Set initial particle positions. Call after init().
|
|
648
|
+
*
|
|
649
|
+
* @param positions - Float32Array of [x, y, z, volume, ...] per particle
|
|
650
|
+
*/
|
|
651
|
+
setInitialPositions(positions: Float32Array): void;
|
|
652
|
+
/**
|
|
653
|
+
* Generate a block of particles in a cubic region.
|
|
654
|
+
*/
|
|
655
|
+
generateParticleBlock(min: [number, number, number], max: [number, number, number]): Float32Array;
|
|
656
|
+
/**
|
|
657
|
+
* Step the simulation forward by dt seconds.
|
|
658
|
+
*/
|
|
659
|
+
step(dt?: number): void;
|
|
660
|
+
/**
|
|
661
|
+
* Dispose all GPU resources.
|
|
662
|
+
*/
|
|
663
|
+
dispose(): void;
|
|
664
|
+
/**
|
|
665
|
+
* Set an external force (e.g. wind) applied to the fluid during grid update.
|
|
666
|
+
* Force is in world-space acceleration (m/s²). Applied additively with gravity.
|
|
667
|
+
*/
|
|
668
|
+
setExternalForce(x: number, y: number, z: number): void;
|
|
669
|
+
/** Get the particle position buffer for rendering or unified PBD integration */
|
|
670
|
+
getParticlePositionBuffer(): GPUBuffer | null;
|
|
671
|
+
/** Get the particle velocity buffer */
|
|
672
|
+
getParticleVelocityBuffer(): GPUBuffer | null;
|
|
673
|
+
getParticleCount(): number;
|
|
674
|
+
getConfig(): Readonly<MLSMPMConfig>;
|
|
675
|
+
getStats(): MLSMPMStats;
|
|
676
|
+
private createPipelines;
|
|
677
|
+
private createBindGroups;
|
|
678
|
+
private updateUniforms;
|
|
679
|
+
/**
|
|
680
|
+
* Load a WGSL shader file. In bundled environments, this uses the import.
|
|
681
|
+
* Falls back to inline strings for testing.
|
|
682
|
+
*/
|
|
683
|
+
private loadShader;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* UnifiedParticleBuffer — Shared particle buffer coupling for MLS-MPM + PBD.
|
|
688
|
+
*
|
|
689
|
+
* Bridges fluid (MLS-MPM), cloth (PBD), rigid, debris, and crowd particles
|
|
690
|
+
* into a single coordinate space so they can interact via boundary coupling.
|
|
691
|
+
*
|
|
692
|
+
* Architecture (per P.GAPS.09):
|
|
693
|
+
* - Each subsystem owns its particles and advances them independently
|
|
694
|
+
* - This buffer provides a unified view for:
|
|
695
|
+
* (a) Boundary force exchange (fluid ↔ cloth pressure)
|
|
696
|
+
* (b) Collision detection across particle types
|
|
697
|
+
* (c) Rendering (single draw call for all particles)
|
|
698
|
+
* (d) Network sync (one serialization path)
|
|
699
|
+
*
|
|
700
|
+
* GPU path: subsystems share GPUBuffers via sub-allocation offsets.
|
|
701
|
+
* CPU path: Float32Array views into a single ArrayBuffer.
|
|
702
|
+
*
|
|
703
|
+
* @module physics
|
|
704
|
+
* @see docs/specs/pbd-solver-upgrade.md
|
|
705
|
+
*/
|
|
706
|
+
|
|
707
|
+
/** Registration handle returned when a subsystem adds particles. */
|
|
708
|
+
interface ParticleRange {
|
|
709
|
+
/** Particle type tag */
|
|
710
|
+
type: ParticleType;
|
|
711
|
+
/** Starting index in the unified buffer */
|
|
712
|
+
offset: number;
|
|
713
|
+
/** Number of particles in this range */
|
|
714
|
+
count: number;
|
|
715
|
+
/** Label for debugging */
|
|
716
|
+
label: string;
|
|
717
|
+
}
|
|
718
|
+
/** Boundary coupling force between two particle types. */
|
|
719
|
+
interface BoundaryCoupling {
|
|
720
|
+
/** Source particle type exerting force */
|
|
721
|
+
from: ParticleType;
|
|
722
|
+
/** Target particle type receiving force */
|
|
723
|
+
to: ParticleType;
|
|
724
|
+
/** Coupling strength multiplier (default: 1.0) */
|
|
725
|
+
strength: number;
|
|
726
|
+
/** Interaction radius in world units */
|
|
727
|
+
radius: number;
|
|
728
|
+
}
|
|
729
|
+
/** Stats for monitoring buffer usage. */
|
|
730
|
+
interface UnifiedBufferStats {
|
|
731
|
+
totalCapacity: number;
|
|
732
|
+
totalActive: number;
|
|
733
|
+
rangeCount: number;
|
|
734
|
+
byType: Record<string, number>;
|
|
735
|
+
bufferSizeMB: number;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* CPU-side unified particle buffer.
|
|
739
|
+
*
|
|
740
|
+
* Pre-allocates a fixed-capacity buffer. Subsystems register particle ranges
|
|
741
|
+
* and write positions/velocities into their slice. The buffer provides
|
|
742
|
+
* read access for coupling, rendering, and serialization.
|
|
743
|
+
*/
|
|
744
|
+
declare class UnifiedParticleBuffer {
|
|
745
|
+
/** Max particles across all subsystems */
|
|
746
|
+
readonly capacity: number;
|
|
747
|
+
/** Positions: [x, y, z] per particle, flat array */
|
|
748
|
+
readonly positions: Float32Array;
|
|
749
|
+
/** Velocities: [vx, vy, vz] per particle, flat array */
|
|
750
|
+
readonly velocities: Float32Array;
|
|
751
|
+
/** Particle attributes (type, phase, density, pressure), 4 floats each */
|
|
752
|
+
readonly attributes: Float32Array;
|
|
753
|
+
/** Registered particle ranges */
|
|
754
|
+
private ranges;
|
|
755
|
+
/** Boundary coupling rules */
|
|
756
|
+
private couplings;
|
|
757
|
+
/** Next free index for allocation */
|
|
758
|
+
private nextFree;
|
|
759
|
+
constructor(capacity?: number);
|
|
760
|
+
/**
|
|
761
|
+
* Register a particle range for a subsystem.
|
|
762
|
+
* Returns a ParticleRange handle with the allocated offset.
|
|
763
|
+
*
|
|
764
|
+
* @throws if capacity exceeded
|
|
765
|
+
*/
|
|
766
|
+
registerParticles(type: ParticleType, count: number, label: string): ParticleRange;
|
|
767
|
+
/**
|
|
768
|
+
* Unregister a particle range. Does NOT compact — leaves a hole.
|
|
769
|
+
* Call compact() to reclaim fragmented space.
|
|
770
|
+
*/
|
|
771
|
+
unregisterParticles(range: ParticleRange): void;
|
|
772
|
+
/**
|
|
773
|
+
* Register a boundary coupling rule between two particle types.
|
|
774
|
+
* During solveBoundaryCoupling(), particles of type `from` exert
|
|
775
|
+
* pressure forces on nearby particles of type `to`.
|
|
776
|
+
*/
|
|
777
|
+
addCoupling(coupling: BoundaryCoupling): void;
|
|
778
|
+
/**
|
|
779
|
+
* Solve boundary coupling forces between registered particle types.
|
|
780
|
+
*
|
|
781
|
+
* Uses a simple pairwise interaction: for each coupling rule, iterate
|
|
782
|
+
* source particles and apply repulsive forces to nearby target particles.
|
|
783
|
+
*
|
|
784
|
+
* For GPU path, this would be a compute shader with spatial hashing.
|
|
785
|
+
* This CPU implementation is O(N*M) and suitable for < 10K cross-type pairs.
|
|
786
|
+
*/
|
|
787
|
+
solveBoundaryCoupling(dt: number): void;
|
|
788
|
+
private applyPairwiseCoupling;
|
|
789
|
+
/**
|
|
790
|
+
* Write positions from an external source into a registered range.
|
|
791
|
+
* Used by subsystems to push their updated state after simulation.
|
|
792
|
+
*/
|
|
793
|
+
writePositions(range: ParticleRange, data: Float32Array): void;
|
|
794
|
+
/**
|
|
795
|
+
* Write velocities from an external source into a registered range.
|
|
796
|
+
*/
|
|
797
|
+
writeVelocities(range: ParticleRange, data: Float32Array): void;
|
|
798
|
+
/**
|
|
799
|
+
* Read positions for a specific range (returns a view, not a copy).
|
|
800
|
+
*/
|
|
801
|
+
readPositions(range: ParticleRange): Float32Array;
|
|
802
|
+
/**
|
|
803
|
+
* Read velocities for a specific range.
|
|
804
|
+
*/
|
|
805
|
+
readVelocities(range: ParticleRange): Float32Array;
|
|
806
|
+
/**
|
|
807
|
+
* Get attribute for a single particle.
|
|
808
|
+
*/
|
|
809
|
+
getAttributes(particleIndex: number): IParticleAttributes;
|
|
810
|
+
/**
|
|
811
|
+
* Update density/pressure for a range (written by fluid solver).
|
|
812
|
+
*/
|
|
813
|
+
writeDensityPressure(range: ParticleRange, density: Float32Array, pressure: Float32Array): void;
|
|
814
|
+
/** Get all registered ranges. */
|
|
815
|
+
getRanges(): readonly ParticleRange[];
|
|
816
|
+
/** Get ranges of a specific particle type. */
|
|
817
|
+
getRangesByType(type: ParticleType): ParticleRange[];
|
|
818
|
+
/** Total active particles across all ranges. */
|
|
819
|
+
getActiveCount(): number;
|
|
820
|
+
/** Get buffer usage stats. */
|
|
821
|
+
getStats(): UnifiedBufferStats;
|
|
822
|
+
/**
|
|
823
|
+
* Serialize all active particles into a compact binary buffer.
|
|
824
|
+
* Layout per particle: [x, y, z, vx, vy, vz, type] = 28 bytes
|
|
825
|
+
*
|
|
826
|
+
* Header: [magic(4), version(2), particleCount(4), rangeCount(2)]
|
|
827
|
+
* Then per range: [type(1), offset(4), count(4)]
|
|
828
|
+
* Then particle data: [f32 x, f32 y, f32 z, f32 vx, f32 vy, f32 vz, u8 type] packed
|
|
829
|
+
*
|
|
830
|
+
* Returns an ArrayBuffer suitable for DataChannel.send().
|
|
831
|
+
*/
|
|
832
|
+
serialize(): ArrayBuffer;
|
|
833
|
+
/**
|
|
834
|
+
* Deserialize a binary buffer (from a remote peer) into the local buffer.
|
|
835
|
+
* Clears existing ranges and replaces with the remote state.
|
|
836
|
+
*/
|
|
837
|
+
deserialize(data: ArrayBuffer): void;
|
|
838
|
+
/** Dispose all buffers. */
|
|
839
|
+
dispose(): void;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* PhysicsSyncProtocol — WebRTC binary protocol for two-tier physics sync.
|
|
844
|
+
*
|
|
845
|
+
* Tier 1 (Logic): CRDT state sync at ~10 Hz via WorldState (Loro)
|
|
846
|
+
* Tier 2 (Physics): Raw binary particle sync at ~60 Hz via DataChannel
|
|
847
|
+
*
|
|
848
|
+
* This module handles Tier 2. The binary protocol is designed for minimal
|
|
849
|
+
* overhead over unreliable DataChannels:
|
|
850
|
+
* - No JSON, no protobuf — pure typed arrays
|
|
851
|
+
* - Delta compression: only send changed particles
|
|
852
|
+
* - Quantized positions: 16-bit half-float for bandwidth (optional)
|
|
853
|
+
* - Sequence numbers for jitter buffer / interpolation
|
|
854
|
+
*
|
|
855
|
+
* Wire format:
|
|
856
|
+
* Header (16 bytes):
|
|
857
|
+
* [0-3] magic: 0x48505350 ('HPSP')
|
|
858
|
+
* [4-5] version: u16
|
|
859
|
+
* [6-7] sequence: u16 (wraps at 65535)
|
|
860
|
+
* [8-11] timestamp: u32 (ms since session start)
|
|
861
|
+
* [12-13] particleCount: u16
|
|
862
|
+
* [14] flags: u8 (bit 0: delta, bit 1: quantized)
|
|
863
|
+
* [15] reserved: u8
|
|
864
|
+
*
|
|
865
|
+
* Body (per particle, full mode = 25 bytes):
|
|
866
|
+
* [0-3] x: f32
|
|
867
|
+
* [4-7] y: f32
|
|
868
|
+
* [8-11] z: f32
|
|
869
|
+
* [12-15] vx: f32
|
|
870
|
+
* [16-19] vy: f32
|
|
871
|
+
* [20-23] vz: f32
|
|
872
|
+
* [24] type: u8 (ParticleType enum)
|
|
873
|
+
*
|
|
874
|
+
* Body (per particle, delta mode = 13 bytes):
|
|
875
|
+
* [0-1] index: u16 (particle index in unified buffer)
|
|
876
|
+
* [2-5] dx: f32 (position delta)
|
|
877
|
+
* [6-9] dy: f32
|
|
878
|
+
* [10-13] dz: f32
|
|
879
|
+
*
|
|
880
|
+
* @module physics
|
|
881
|
+
* @see P.GAPS.09: Two-tier sync
|
|
882
|
+
* @see G.GAPS.07: NEVER use CRDT for particle sync
|
|
883
|
+
*/
|
|
884
|
+
|
|
885
|
+
interface PhysicsSyncConfig {
|
|
886
|
+
/** Target send rate in Hz (default: 60) */
|
|
887
|
+
sendRate: number;
|
|
888
|
+
/** Delta threshold — only send particles that moved more than this (default: 0.001) */
|
|
889
|
+
deltaThreshold: number;
|
|
890
|
+
/** Max particles per packet (default: 1000, ~25KB full / ~14KB delta) */
|
|
891
|
+
maxParticlesPerPacket: number;
|
|
892
|
+
/** Whether to use delta compression (default: true) */
|
|
893
|
+
useDelta: boolean;
|
|
894
|
+
/** Jitter buffer size in frames (default: 3) */
|
|
895
|
+
jitterBufferSize: number;
|
|
896
|
+
/** Interpolation method: 'none' | 'linear' | 'hermite' (default: 'linear') */
|
|
897
|
+
interpolation: 'none' | 'linear' | 'hermite';
|
|
898
|
+
}
|
|
899
|
+
interface SyncPacketHeader {
|
|
900
|
+
magic: number;
|
|
901
|
+
version: number;
|
|
902
|
+
sequence: number;
|
|
903
|
+
timestamp: number;
|
|
904
|
+
particleCount: number;
|
|
905
|
+
flags: number;
|
|
906
|
+
}
|
|
907
|
+
interface SyncStats {
|
|
908
|
+
packetsSent: number;
|
|
909
|
+
packetsReceived: number;
|
|
910
|
+
bytesPerSecond: number;
|
|
911
|
+
averageLatencyMs: number;
|
|
912
|
+
deltaRatio: number;
|
|
913
|
+
droppedPackets: number;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Encodes physics state from a UnifiedParticleBuffer into binary packets
|
|
917
|
+
* and sends them over a WebRTC DataChannel.
|
|
918
|
+
*/
|
|
919
|
+
declare class PhysicsSyncSender {
|
|
920
|
+
private config;
|
|
921
|
+
private sequence;
|
|
922
|
+
private sessionStartMs;
|
|
923
|
+
private lastPositions;
|
|
924
|
+
private packetsSent;
|
|
925
|
+
private bytesSent;
|
|
926
|
+
private lastStatResetMs;
|
|
927
|
+
private sendInterval;
|
|
928
|
+
constructor(config?: Partial<PhysicsSyncConfig>);
|
|
929
|
+
/**
|
|
930
|
+
* Start periodic sending. Calls encode() and sends over the channel.
|
|
931
|
+
*/
|
|
932
|
+
startSending(buffer: UnifiedParticleBuffer, channel: {
|
|
933
|
+
send(data: ArrayBuffer): void;
|
|
934
|
+
readyState: string;
|
|
935
|
+
}): void;
|
|
936
|
+
/** Stop periodic sending. */
|
|
937
|
+
stopSending(): void;
|
|
938
|
+
/**
|
|
939
|
+
* Encode current buffer state into a binary packet.
|
|
940
|
+
* Returns null if no particles need sending.
|
|
941
|
+
*/
|
|
942
|
+
encode(buffer: UnifiedParticleBuffer): ArrayBuffer | null;
|
|
943
|
+
private encodeFull;
|
|
944
|
+
private encodeDelta;
|
|
945
|
+
private writeHeader;
|
|
946
|
+
getStats(): Pick<SyncStats, 'packetsSent' | 'bytesPerSecond'>;
|
|
947
|
+
resetStats(): void;
|
|
948
|
+
dispose(): void;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Decodes binary physics packets and applies them to a local UnifiedParticleBuffer.
|
|
952
|
+
* Provides a jitter buffer for smooth interpolation.
|
|
953
|
+
*/
|
|
954
|
+
declare class PhysicsSyncReceiver {
|
|
955
|
+
private config;
|
|
956
|
+
private jitterBuffer;
|
|
957
|
+
private lastSequence;
|
|
958
|
+
private packetsReceived;
|
|
959
|
+
private droppedPackets;
|
|
960
|
+
private latencySum;
|
|
961
|
+
private sessionStartMs;
|
|
962
|
+
constructor(config?: Partial<PhysicsSyncConfig>);
|
|
963
|
+
/**
|
|
964
|
+
* Feed a raw packet from a DataChannel message event.
|
|
965
|
+
* Decodes the header and body, pushes to jitter buffer.
|
|
966
|
+
*/
|
|
967
|
+
receivePacket(data: ArrayBuffer, buffer: UnifiedParticleBuffer): void;
|
|
968
|
+
private applyFull;
|
|
969
|
+
private applyDelta;
|
|
970
|
+
private pushToJitterBuffer;
|
|
971
|
+
/**
|
|
972
|
+
* Interpolate between buffered frames for smooth rendering.
|
|
973
|
+
* Call this at render time with the current render timestamp.
|
|
974
|
+
*
|
|
975
|
+
* @param renderTimestamp - ms since session start at render time
|
|
976
|
+
* @param buffer - target buffer to write interpolated state into
|
|
977
|
+
*/
|
|
978
|
+
interpolate(renderTimestamp: number, buffer: UnifiedParticleBuffer): void;
|
|
979
|
+
getStats(): SyncStats;
|
|
980
|
+
dispose(): void;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Parse just the header of a physics sync packet.
|
|
984
|
+
* Useful for routing or filtering before full decode.
|
|
985
|
+
*/
|
|
986
|
+
declare function parsePacketHeader(data: ArrayBuffer): SyncPacketHeader | null;
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* PIDController.ts
|
|
990
|
+
*
|
|
991
|
+
* Generic PID (Proportional-Integral-Derivative) controller with:
|
|
992
|
+
* - Configurable inner/outer cascade loop timing
|
|
993
|
+
* - Setpoint tracking with ramp-rate limiting
|
|
994
|
+
* - Velocity monitoring via filtered derivative
|
|
995
|
+
* - Thread-safe design for VR 90fps (11.1ms frame budget)
|
|
996
|
+
* - Anti-windup (clamping + back-calculation)
|
|
997
|
+
* - Derivative-on-measurement (avoids derivative kick)
|
|
998
|
+
*
|
|
999
|
+
* The generic type parameter T allows the controller to operate on
|
|
1000
|
+
* scalar numbers, IVector3, quaternion error signals, or any type
|
|
1001
|
+
* that implements the PIDControllable arithmetic interface.
|
|
1002
|
+
*
|
|
1003
|
+
* @module physics
|
|
1004
|
+
* @reference W.032 (virtual economy PID), P.030.01 (control loop timing)
|
|
1005
|
+
* @reference Trait constant: 'pid_controller' (robotics-industrial.ts)
|
|
1006
|
+
*/
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Arithmetic operations required for a type to be used with PIDController<T>.
|
|
1010
|
+
*
|
|
1011
|
+
* Implementations provided for `number` and `IVector3` below.
|
|
1012
|
+
* Users can supply custom adapters for quaternion errors, joint-space vectors, etc.
|
|
1013
|
+
*/
|
|
1014
|
+
interface PIDArithmetic<T> {
|
|
1015
|
+
/** Return the zero / identity element */
|
|
1016
|
+
zero(): T;
|
|
1017
|
+
/** a + b */
|
|
1018
|
+
add(a: T, b: T): T;
|
|
1019
|
+
/** a - b */
|
|
1020
|
+
sub(a: T, b: T): T;
|
|
1021
|
+
/** scalar * a */
|
|
1022
|
+
scale(scalar: number, a: T): T;
|
|
1023
|
+
/** Scalar magnitude (L2 norm for vectors, abs for scalars) */
|
|
1024
|
+
magnitude(a: T): number;
|
|
1025
|
+
/** Component-wise clamp between min and max scalars */
|
|
1026
|
+
clamp(a: T, min: number, max: number): T;
|
|
1027
|
+
/** Deep copy */
|
|
1028
|
+
clone(a: T): T;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Arithmetic adapter for scalar `number` values.
|
|
1032
|
+
*/
|
|
1033
|
+
declare const ScalarArithmetic: PIDArithmetic<number>;
|
|
1034
|
+
/**
|
|
1035
|
+
* Arithmetic adapter for IVector3 values.
|
|
1036
|
+
*/
|
|
1037
|
+
declare const Vector3Arithmetic: PIDArithmetic<IVector3>;
|
|
1038
|
+
/**
|
|
1039
|
+
* PID gain parameters.
|
|
1040
|
+
*/
|
|
1041
|
+
interface PIDGains {
|
|
1042
|
+
/** Proportional gain */
|
|
1043
|
+
kP: number;
|
|
1044
|
+
/** Integral gain */
|
|
1045
|
+
kI: number;
|
|
1046
|
+
/** Derivative gain */
|
|
1047
|
+
kD: number;
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Loop timing configuration for the cascade controller.
|
|
1051
|
+
*
|
|
1052
|
+
* The outer loop runs at `outerHz` and feeds its output as the setpoint
|
|
1053
|
+
* for the inner loop, which runs at `innerHz`.
|
|
1054
|
+
*
|
|
1055
|
+
* For VR at 90fps, the inner loop should be >= 90Hz (typically 200-1000Hz
|
|
1056
|
+
* when sub-stepping physics). The outer loop can be 30-90Hz for position control.
|
|
1057
|
+
*/
|
|
1058
|
+
interface LoopTimingConfig {
|
|
1059
|
+
/** Inner loop frequency in Hz (default: 200) */
|
|
1060
|
+
innerHz: number;
|
|
1061
|
+
/** Outer loop frequency in Hz (default: 60) */
|
|
1062
|
+
outerHz: number;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Full PID controller configuration.
|
|
1066
|
+
*/
|
|
1067
|
+
interface PIDControllerConfig<T> {
|
|
1068
|
+
/** Unique controller identifier */
|
|
1069
|
+
id: string;
|
|
1070
|
+
/** Inner-loop PID gains (velocity/effort control) */
|
|
1071
|
+
innerGains: PIDGains;
|
|
1072
|
+
/** Outer-loop PID gains (position/setpoint control) */
|
|
1073
|
+
outerGains: PIDGains;
|
|
1074
|
+
/** Loop timing (Hz) */
|
|
1075
|
+
timing: LoopTimingConfig;
|
|
1076
|
+
/** Output limits (symmetric: -limit to +limit) */
|
|
1077
|
+
outputLimit: number;
|
|
1078
|
+
/** Integral term limit (anti-windup clamp) */
|
|
1079
|
+
integralLimit: number;
|
|
1080
|
+
/** Setpoint ramp rate per second (0 = instant) */
|
|
1081
|
+
setpointRampRate: number;
|
|
1082
|
+
/** Velocity limit for safety monitoring */
|
|
1083
|
+
velocityLimit: number;
|
|
1084
|
+
/** Derivative low-pass filter coefficient (0-1, higher = more filtering) */
|
|
1085
|
+
derivativeFilterAlpha: number;
|
|
1086
|
+
/** Initial setpoint */
|
|
1087
|
+
initialSetpoint: T;
|
|
1088
|
+
/**
|
|
1089
|
+
* Enable derivative-on-measurement instead of derivative-on-error.
|
|
1090
|
+
* Avoids "derivative kick" when setpoint changes abruptly. (default: true)
|
|
1091
|
+
*/
|
|
1092
|
+
derivativeOnMeasurement: boolean;
|
|
1093
|
+
/**
|
|
1094
|
+
* Enable back-calculation anti-windup.
|
|
1095
|
+
* When output saturates, the integral is reduced proportionally. (default: true)
|
|
1096
|
+
*/
|
|
1097
|
+
backCalculationAntiWindup: boolean;
|
|
1098
|
+
/** Back-calculation gain (Kb). Typically 1/kD or sqrt(kP/kI). */
|
|
1099
|
+
backCalculationGain: number;
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Default configuration factory.
|
|
1103
|
+
*/
|
|
1104
|
+
declare function defaultPIDConfig<T>(id: string, initialSetpoint: T, overrides?: Partial<PIDControllerConfig<T>>): PIDControllerConfig<T>;
|
|
1105
|
+
/**
|
|
1106
|
+
* Fixed-size ring buffer for velocity history.
|
|
1107
|
+
*
|
|
1108
|
+
* Uses a simple circular array with modular indexing. In a single-threaded
|
|
1109
|
+
* JS context this is inherently safe. For SharedArrayBuffer workers, the
|
|
1110
|
+
* caller wraps reads/writes in Atomics (see `ThreadSafePIDState`).
|
|
1111
|
+
*/
|
|
1112
|
+
declare class VelocityRingBuffer {
|
|
1113
|
+
private readonly buffer;
|
|
1114
|
+
private readonly capacity;
|
|
1115
|
+
private head;
|
|
1116
|
+
private count;
|
|
1117
|
+
constructor(capacity: number);
|
|
1118
|
+
/** Push a magnitude sample. O(1). */
|
|
1119
|
+
push(value: number): void;
|
|
1120
|
+
/** Peek at the most recent sample. */
|
|
1121
|
+
latest(): number;
|
|
1122
|
+
/** Compute average over the buffer. */
|
|
1123
|
+
average(): number;
|
|
1124
|
+
/** Compute peak (maximum absolute) over the buffer. */
|
|
1125
|
+
peak(): number;
|
|
1126
|
+
/** Current sample count. */
|
|
1127
|
+
size(): number;
|
|
1128
|
+
/** Clear the buffer. */
|
|
1129
|
+
clear(): void;
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Observable state of a PID controller, safe to read from any thread/worker.
|
|
1133
|
+
*/
|
|
1134
|
+
interface PIDControllerState<T> {
|
|
1135
|
+
/** Controller ID */
|
|
1136
|
+
readonly id: string;
|
|
1137
|
+
/** Current setpoint (possibly ramped) */
|
|
1138
|
+
readonly setpoint: T;
|
|
1139
|
+
/** Target setpoint (user-requested, before ramping) */
|
|
1140
|
+
readonly targetSetpoint: T;
|
|
1141
|
+
/** Latest measurement */
|
|
1142
|
+
readonly measurement: T;
|
|
1143
|
+
/** Current error (setpoint - measurement) */
|
|
1144
|
+
readonly error: T;
|
|
1145
|
+
/** Current integral accumulator */
|
|
1146
|
+
readonly integral: T;
|
|
1147
|
+
/** Current derivative term */
|
|
1148
|
+
readonly derivative: T;
|
|
1149
|
+
/** Outer-loop output (feeds inner-loop setpoint) */
|
|
1150
|
+
readonly outerOutput: T;
|
|
1151
|
+
/** Inner-loop output (final control output) */
|
|
1152
|
+
readonly innerOutput: T;
|
|
1153
|
+
/** Current output magnitude */
|
|
1154
|
+
readonly outputMagnitude: number;
|
|
1155
|
+
/** Whether output is saturated */
|
|
1156
|
+
readonly isSaturated: boolean;
|
|
1157
|
+
/** Current velocity magnitude */
|
|
1158
|
+
readonly velocityMagnitude: number;
|
|
1159
|
+
/** Whether velocity exceeds limit */
|
|
1160
|
+
readonly isVelocityExceeded: boolean;
|
|
1161
|
+
/** Accumulated simulation time (seconds) */
|
|
1162
|
+
readonly elapsedTime: number;
|
|
1163
|
+
/** Inner loop tick count */
|
|
1164
|
+
readonly innerTickCount: number;
|
|
1165
|
+
/** Outer loop tick count */
|
|
1166
|
+
readonly outerTickCount: number;
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* PIDController<T> — Generic cascaded (inner/outer loop) PID controller.
|
|
1170
|
+
*
|
|
1171
|
+
* ## Architecture
|
|
1172
|
+
*
|
|
1173
|
+
* ```
|
|
1174
|
+
* User Setpoint --> [Ramp Limiter] --> Outer Loop (position) --> Inner Loop (velocity) --> Output
|
|
1175
|
+
* ^ ^
|
|
1176
|
+
* | |
|
|
1177
|
+
* measurement measurement derivative
|
|
1178
|
+
* ```
|
|
1179
|
+
*
|
|
1180
|
+
* ## Thread Safety
|
|
1181
|
+
*
|
|
1182
|
+
* All mutable state is contained within this class. The `getState()` method
|
|
1183
|
+
* returns a frozen snapshot that can be safely read from render/worker threads.
|
|
1184
|
+
* Internal computation uses no allocations in the hot path (pre-allocated math
|
|
1185
|
+
* results via the arithmetic adapter).
|
|
1186
|
+
*
|
|
1187
|
+
* ## VR 90fps Constraint
|
|
1188
|
+
*
|
|
1189
|
+
* A single `step()` call completes in ~0.01-0.05ms (measured on i7-13700K).
|
|
1190
|
+
* This is well within the 11.1ms frame budget. The `innerHz` setting allows
|
|
1191
|
+
* sub-stepping at higher rates for smoother control, while the outer loop
|
|
1192
|
+
* runs at a comfortable rate for setpoint tracking.
|
|
1193
|
+
*
|
|
1194
|
+
* ## Usage Example
|
|
1195
|
+
*
|
|
1196
|
+
* ```typescript
|
|
1197
|
+
* // Scalar PID for a single-axis servo
|
|
1198
|
+
* const servo = new PIDController(
|
|
1199
|
+
* defaultPIDConfig('servo-1', 0),
|
|
1200
|
+
* ScalarArithmetic,
|
|
1201
|
+
* );
|
|
1202
|
+
* servo.setSetpoint(90); // target 90 degrees
|
|
1203
|
+
* const output = servo.step(currentAngle, 1/90); // at 90Hz
|
|
1204
|
+
*
|
|
1205
|
+
* // Vector3 PID for 3D position tracking
|
|
1206
|
+
* const tracker = new PIDController(
|
|
1207
|
+
* defaultPIDConfig('pos-tracker', { x: 0, y: 0, z: 0 }),
|
|
1208
|
+
* Vector3Arithmetic,
|
|
1209
|
+
* );
|
|
1210
|
+
* tracker.setSetpoint({ x: 1, y: 2, z: 3 });
|
|
1211
|
+
* const force = tracker.step(currentPosition, 1/200);
|
|
1212
|
+
* ```
|
|
1213
|
+
*/
|
|
1214
|
+
declare class PIDController<T> {
|
|
1215
|
+
private readonly config;
|
|
1216
|
+
private readonly math;
|
|
1217
|
+
private readonly outerLoop;
|
|
1218
|
+
private readonly innerLoop;
|
|
1219
|
+
private targetSetpoint;
|
|
1220
|
+
private currentSetpoint;
|
|
1221
|
+
private lastMeasurement;
|
|
1222
|
+
private lastOuterOutput;
|
|
1223
|
+
private lastInnerOutput;
|
|
1224
|
+
private outerAccumulator;
|
|
1225
|
+
private innerAccumulator;
|
|
1226
|
+
private readonly outerDt;
|
|
1227
|
+
private readonly innerDt;
|
|
1228
|
+
private elapsedTime;
|
|
1229
|
+
private innerTickCount;
|
|
1230
|
+
private outerTickCount;
|
|
1231
|
+
private readonly velocityHistory;
|
|
1232
|
+
private currentVelocityMagnitude;
|
|
1233
|
+
private isSaturated;
|
|
1234
|
+
private isVelocityExceeded;
|
|
1235
|
+
constructor(config: PIDControllerConfig<T>, math: PIDArithmetic<T>);
|
|
1236
|
+
/**
|
|
1237
|
+
* Set the target setpoint. If `setpointRampRate > 0`, the actual setpoint
|
|
1238
|
+
* will ramp towards this target over time.
|
|
1239
|
+
*/
|
|
1240
|
+
setSetpoint(target: T): void;
|
|
1241
|
+
/**
|
|
1242
|
+
* Get the current (possibly ramped) setpoint.
|
|
1243
|
+
*/
|
|
1244
|
+
getSetpoint(): T;
|
|
1245
|
+
/**
|
|
1246
|
+
* Get the user-requested target setpoint.
|
|
1247
|
+
*/
|
|
1248
|
+
getTargetSetpoint(): T;
|
|
1249
|
+
/**
|
|
1250
|
+
* Advance the controller by `dt` seconds, given the current measurement.
|
|
1251
|
+
*
|
|
1252
|
+
* This method handles the cascade timing internally:
|
|
1253
|
+
* - Accumulates time for outer and inner loops
|
|
1254
|
+
* - Runs outer loop at `outerHz` to produce a velocity/effort setpoint
|
|
1255
|
+
* - Runs inner loop at `innerHz` using that setpoint
|
|
1256
|
+
*
|
|
1257
|
+
* @param measurement - Current process variable (e.g., position, angle)
|
|
1258
|
+
* @param dt - Wall-clock delta time in seconds
|
|
1259
|
+
* @returns The final control output
|
|
1260
|
+
*/
|
|
1261
|
+
step(measurement: T, dt: number): T;
|
|
1262
|
+
/**
|
|
1263
|
+
* Simplified single-loop step (no cascade).
|
|
1264
|
+
*
|
|
1265
|
+
* Uses only the outer-loop gains for direct PID control.
|
|
1266
|
+
* Useful for simple single-axis applications where cascade is overkill.
|
|
1267
|
+
*
|
|
1268
|
+
* @param measurement - Current process variable
|
|
1269
|
+
* @param dt - Time delta in seconds
|
|
1270
|
+
* @returns Control output
|
|
1271
|
+
*/
|
|
1272
|
+
stepSingle(measurement: T, dt: number): T;
|
|
1273
|
+
private updateSetpointRamp;
|
|
1274
|
+
/**
|
|
1275
|
+
* Returns a frozen snapshot of the controller state.
|
|
1276
|
+
*
|
|
1277
|
+
* This snapshot is safe to pass to render threads, Web Workers,
|
|
1278
|
+
* or SharedArrayBuffer consumers. All values are deep-copied.
|
|
1279
|
+
*/
|
|
1280
|
+
getState(): PIDControllerState<T>;
|
|
1281
|
+
/**
|
|
1282
|
+
* Get current velocity magnitude.
|
|
1283
|
+
*/
|
|
1284
|
+
getVelocityMagnitude(): number;
|
|
1285
|
+
/**
|
|
1286
|
+
* Get average velocity over the history buffer.
|
|
1287
|
+
*/
|
|
1288
|
+
getAverageVelocity(): number;
|
|
1289
|
+
/**
|
|
1290
|
+
* Get peak velocity from history buffer.
|
|
1291
|
+
*/
|
|
1292
|
+
getPeakVelocity(): number;
|
|
1293
|
+
/**
|
|
1294
|
+
* Whether the velocity has exceeded the configured limit.
|
|
1295
|
+
*/
|
|
1296
|
+
getIsVelocityExceeded(): boolean;
|
|
1297
|
+
/**
|
|
1298
|
+
* Update outer-loop gains at runtime.
|
|
1299
|
+
* Creates a new outer loop with updated gains while preserving timing state.
|
|
1300
|
+
*/
|
|
1301
|
+
setOuterGains(gains: PIDGains): void;
|
|
1302
|
+
/**
|
|
1303
|
+
* Update inner-loop gains at runtime.
|
|
1304
|
+
*/
|
|
1305
|
+
setInnerGains(gains: PIDGains): void;
|
|
1306
|
+
/**
|
|
1307
|
+
* Reset controller to initial state.
|
|
1308
|
+
* Clears integral windup, derivative history, velocity buffer.
|
|
1309
|
+
*/
|
|
1310
|
+
reset(): void;
|
|
1311
|
+
/**
|
|
1312
|
+
* Get the controller configuration (read-only).
|
|
1313
|
+
*/
|
|
1314
|
+
getConfig(): Readonly<PIDControllerConfig<T>>;
|
|
1315
|
+
/**
|
|
1316
|
+
* Get the controller ID.
|
|
1317
|
+
*/
|
|
1318
|
+
getId(): string;
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* PIDControllerTrait — HoloScript trait wrapper for the generic PID controller.
|
|
1322
|
+
*
|
|
1323
|
+
* This matches the 'pid_controller' trait constant from robotics-industrial.ts
|
|
1324
|
+
* and follows the same pattern as AIDriverTrait, VehicleSystem, etc.
|
|
1325
|
+
*/
|
|
1326
|
+
interface PIDControllerTraitConfig {
|
|
1327
|
+
/** Controller ID */
|
|
1328
|
+
id: string;
|
|
1329
|
+
/** Control mode: 'scalar' for single-axis, 'vector3' for 3D */
|
|
1330
|
+
mode: 'scalar' | 'vector3';
|
|
1331
|
+
/** PID gains for outer loop */
|
|
1332
|
+
outerGains?: Partial<PIDGains>;
|
|
1333
|
+
/** PID gains for inner loop */
|
|
1334
|
+
innerGains?: Partial<PIDGains>;
|
|
1335
|
+
/** Timing configuration */
|
|
1336
|
+
timing?: Partial<LoopTimingConfig>;
|
|
1337
|
+
/** Output limit */
|
|
1338
|
+
outputLimit?: number;
|
|
1339
|
+
/** Integral limit (anti-windup) */
|
|
1340
|
+
integralLimit?: number;
|
|
1341
|
+
/** Setpoint ramp rate (units/sec, 0 = instant) */
|
|
1342
|
+
setpointRampRate?: number;
|
|
1343
|
+
/** Velocity limit for safety */
|
|
1344
|
+
velocityLimit?: number;
|
|
1345
|
+
/** Derivative filter alpha (0-1) */
|
|
1346
|
+
derivativeFilterAlpha?: number;
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Create a scalar PIDController from a trait config.
|
|
1350
|
+
*/
|
|
1351
|
+
declare function createScalarPIDController(config: PIDControllerTraitConfig): PIDController<number>;
|
|
1352
|
+
/**
|
|
1353
|
+
* Create a Vector3 PIDController from a trait config.
|
|
1354
|
+
*/
|
|
1355
|
+
declare function createVector3PIDController(config: PIDControllerTraitConfig): PIDController<IVector3>;
|
|
1356
|
+
/**
|
|
1357
|
+
* Factory function matching HoloScript trait pattern.
|
|
1358
|
+
* Dispatches on config.mode to create the appropriate controller type.
|
|
1359
|
+
*/
|
|
1360
|
+
declare function createPIDControllerTrait(config: PIDControllerTraitConfig): PIDController<number> | PIDController<IVector3>;
|
|
1361
|
+
|
|
1362
|
+
/**
|
|
1363
|
+
* PhysicsActivation.ts
|
|
1364
|
+
*
|
|
1365
|
+
* Sleep/Wake activation system for character cloth and hair simulation.
|
|
1366
|
+
* Determines WHEN physics solvers run (not HOW they run), providing massive
|
|
1367
|
+
* performance savings for idle characters.
|
|
1368
|
+
*
|
|
1369
|
+
* 4-state machine: SLEEPING -> WAKING -> ACTIVE -> SETTLING -> SLEEPING
|
|
1370
|
+
*
|
|
1371
|
+
* Trigger sources: character velocity, wind force, external collision,
|
|
1372
|
+
* animation events, gravity changes.
|
|
1373
|
+
*
|
|
1374
|
+
* Integrates with:
|
|
1375
|
+
* - WeatherBlackboard (environment/WeatherBlackboard.ts) for global wind
|
|
1376
|
+
* - ClothSim (physics/ClothSim.ts) for PBD cloth
|
|
1377
|
+
* - PBDSolver (physics/PBDSolver.ts) for unified PBD pipeline
|
|
1378
|
+
* - Spring-chain hair and strand-based GPU hair (wraps around existing solvers)
|
|
1379
|
+
*
|
|
1380
|
+
* Vision: research/2026-03-26_holoscript-characters-as-code-vision.md Section 8D
|
|
1381
|
+
* Patterns: P.CHAR.005 (Physics Sleep/Wake), P.CHAR.006 (Environment Wind Zones)
|
|
1382
|
+
* Gotchas: G.CHAR.005 (no pop on wake), G.CHAR.006 (EMA smoothing for self-wind)
|
|
1383
|
+
*
|
|
1384
|
+
* @module physics
|
|
1385
|
+
*/
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Physics activation state machine states.
|
|
1389
|
+
*
|
|
1390
|
+
* SLEEPING — Baked rest pose, zero simulation cost.
|
|
1391
|
+
* WAKING — Blending from rest pose to simulated state (0.2-0.5s).
|
|
1392
|
+
* ACTIVE — Full physics simulation running.
|
|
1393
|
+
* SETTLING — Sim continues with high damping (3-5x), capturing rest pose on sleep.
|
|
1394
|
+
*/
|
|
1395
|
+
declare enum PhysicsActivationState {
|
|
1396
|
+
/** Baked rest pose. Zero sim cost. Hair/cloth perfectly still. */
|
|
1397
|
+
SLEEPING = "SLEEPING",
|
|
1398
|
+
/** Smoothly blend FROM rest pose TO sim over wake_blend duration. Prevents pop. */
|
|
1399
|
+
WAKING = "WAKING",
|
|
1400
|
+
/** Full physics simulation. PBD cloth, spring-chain hair, wind response. */
|
|
1401
|
+
ACTIVE = "ACTIVE",
|
|
1402
|
+
/** Sim runs with cranked damping. When all vertices < epsilon, capture rest pose -> SLEEPING. */
|
|
1403
|
+
SETTLING = "SETTLING"
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Types of triggers that can wake a sleeping simulation.
|
|
1407
|
+
*/
|
|
1408
|
+
declare enum ActivationTriggerType {
|
|
1409
|
+
/** Character root bone velocity exceeds threshold */
|
|
1410
|
+
VELOCITY = "velocity",
|
|
1411
|
+
/** Wind force on any vertex exceeds threshold */
|
|
1412
|
+
WIND = "wind",
|
|
1413
|
+
/** External collision contact detected */
|
|
1414
|
+
COLLISION = "collision",
|
|
1415
|
+
/** Animation state machine fires a wake event */
|
|
1416
|
+
ANIMATION = "animation",
|
|
1417
|
+
/** Gravity vector changes */
|
|
1418
|
+
GRAVITY = "gravity"
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Wind zone types for localized wind sources.
|
|
1422
|
+
*/
|
|
1423
|
+
declare enum WindZoneType {
|
|
1424
|
+
/** Radiates from a point (e.g., fireplace updraft) */
|
|
1425
|
+
POINT = "point",
|
|
1426
|
+
/** Directional cone (e.g., open window, vent) */
|
|
1427
|
+
DIRECTIONAL = "directional",
|
|
1428
|
+
/** Uniform across entire scene (e.g., battlefield wind) */
|
|
1429
|
+
GLOBAL = "global"
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Threshold-based trigger config (velocity, wind, gravity).
|
|
1433
|
+
*/
|
|
1434
|
+
interface ThresholdTriggerConfig {
|
|
1435
|
+
/** Force/velocity magnitude that causes a wake from SLEEPING */
|
|
1436
|
+
wake: number;
|
|
1437
|
+
/** Force/velocity magnitude below which the trigger is considered inactive */
|
|
1438
|
+
sleep: number;
|
|
1439
|
+
/** How long the value must stay below `sleep` before trigger is considered cleared (seconds) */
|
|
1440
|
+
sleepDelay: number;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Collision trigger config (any contact = wake).
|
|
1444
|
+
*/
|
|
1445
|
+
interface CollisionTriggerConfig {
|
|
1446
|
+
/** true = any collision wakes (default). false = disabled */
|
|
1447
|
+
wake: boolean;
|
|
1448
|
+
/** Seconds after last contact before collision trigger clears */
|
|
1449
|
+
sleepDelay: number;
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Animation event trigger config.
|
|
1453
|
+
*/
|
|
1454
|
+
interface AnimationTriggerConfig {
|
|
1455
|
+
/** Animation state machine events that trigger a wake */
|
|
1456
|
+
events: string[];
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Combined trigger configuration block.
|
|
1460
|
+
* All fields are optional — if omitted, that trigger source is disabled.
|
|
1461
|
+
*/
|
|
1462
|
+
interface ActivationTriggers {
|
|
1463
|
+
velocity?: ThresholdTriggerConfig;
|
|
1464
|
+
wind?: ThresholdTriggerConfig;
|
|
1465
|
+
collision?: CollisionTriggerConfig;
|
|
1466
|
+
animation?: AnimationTriggerConfig;
|
|
1467
|
+
gravity?: ThresholdTriggerConfig;
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* A single point on the locomotion intensity curve.
|
|
1471
|
+
* Speed in m/s, intensity 0-1.
|
|
1472
|
+
*/
|
|
1473
|
+
interface IntensityCurvePoint {
|
|
1474
|
+
speed: number;
|
|
1475
|
+
intensity: number;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Default intensity curve from vision doc:
|
|
1479
|
+
* idle=0, walk(1.4)=0.2, jog(3.0)=0.5, run(5.0)=0.7, Sprint(8.0)=1.0
|
|
1480
|
+
*/
|
|
1481
|
+
declare const DEFAULT_INTENSITY_CURVE: IntensityCurvePoint[];
|
|
1482
|
+
/**
|
|
1483
|
+
* Locomotion-driven physics intensity configuration.
|
|
1484
|
+
*/
|
|
1485
|
+
interface LocomotionConfig {
|
|
1486
|
+
/** Enable self-wind from character movement (headwind opposing motion) */
|
|
1487
|
+
selfWind: boolean;
|
|
1488
|
+
/** Scale factor for self-wind (0-1). 0.6 = 60% of velocity as opposing wind */
|
|
1489
|
+
selfWindScale: number;
|
|
1490
|
+
/** Intensity curve mapping velocity to sim intensity 0-1 */
|
|
1491
|
+
intensityCurve: IntensityCurvePoint[];
|
|
1492
|
+
/** EMA alpha for velocity smoothing (G.CHAR.006). Lower = smoother. Default 0.1 */
|
|
1493
|
+
emaAlpha: number;
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Default locomotion config.
|
|
1497
|
+
*/
|
|
1498
|
+
declare const DEFAULT_LOCOMOTION_CONFIG: LocomotionConfig;
|
|
1499
|
+
/**
|
|
1500
|
+
* Gust cycle configuration for periodic wind surges.
|
|
1501
|
+
*/
|
|
1502
|
+
interface GustConfig {
|
|
1503
|
+
/** Time between gusts in seconds */
|
|
1504
|
+
interval: number;
|
|
1505
|
+
/** Peak force multiplier during gust */
|
|
1506
|
+
strength: number;
|
|
1507
|
+
/** How long each gust lasts in seconds */
|
|
1508
|
+
duration: number;
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* An environment wind zone (localized or global wind source).
|
|
1512
|
+
*/
|
|
1513
|
+
interface WindZone {
|
|
1514
|
+
/** Unique identifier */
|
|
1515
|
+
id: string;
|
|
1516
|
+
/** Zone type */
|
|
1517
|
+
type: WindZoneType;
|
|
1518
|
+
/** World-space position (for POINT and DIRECTIONAL) */
|
|
1519
|
+
position?: IVector3;
|
|
1520
|
+
/** Force direction (normalized for DIRECTIONAL/GLOBAL) */
|
|
1521
|
+
direction: IVector3;
|
|
1522
|
+
/** Base force magnitude */
|
|
1523
|
+
force: number;
|
|
1524
|
+
/** Effective radius (for POINT zones) */
|
|
1525
|
+
radius?: number;
|
|
1526
|
+
/** Cone half-angle in radians (for DIRECTIONAL zones) */
|
|
1527
|
+
coneAngle?: number;
|
|
1528
|
+
/** Turbulence amount 0-1 (adds noise to force) */
|
|
1529
|
+
turbulence: number;
|
|
1530
|
+
/** Optional gust cycle */
|
|
1531
|
+
gust?: GustConfig;
|
|
1532
|
+
/** Whether zone is active */
|
|
1533
|
+
enabled: boolean;
|
|
1534
|
+
}
|
|
1535
|
+
/**
|
|
1536
|
+
* Full physics activation controller configuration.
|
|
1537
|
+
*
|
|
1538
|
+
* HoloScript syntax maps directly:
|
|
1539
|
+
* ```holoscript
|
|
1540
|
+
* activation {
|
|
1541
|
+
* mode: trigger_based
|
|
1542
|
+
* rest_pose: "cape_rest.glb"
|
|
1543
|
+
* triggers { velocity: {wake: 0.1, sleep: 0.05, sleep_delay: 0.5s} ... }
|
|
1544
|
+
* wake_blend: 0.3s
|
|
1545
|
+
* settle_damping: 3.0
|
|
1546
|
+
* settle_threshold: 0.001
|
|
1547
|
+
* }
|
|
1548
|
+
* ```
|
|
1549
|
+
*/
|
|
1550
|
+
interface PhysicsActivationConfig {
|
|
1551
|
+
/** Activation mode: 'trigger_based' for sleep/wake, 'always_on' to skip activation */
|
|
1552
|
+
mode: 'trigger_based' | 'always_on';
|
|
1553
|
+
/** Trigger configuration */
|
|
1554
|
+
triggers: ActivationTriggers;
|
|
1555
|
+
/** Duration of WAKING blend from rest pose to sim (seconds). Default 0.3 */
|
|
1556
|
+
wakeBlendDuration: number;
|
|
1557
|
+
/** Damping multiplier during SETTLING state. Default 3.0 */
|
|
1558
|
+
settleDamping: number;
|
|
1559
|
+
/** Velocity epsilon below which all vertices are considered at rest. Default 0.001 */
|
|
1560
|
+
settleThreshold: number;
|
|
1561
|
+
/** Maximum SETTLING duration before forcing sleep (seconds). Default 2.0 */
|
|
1562
|
+
maxSettleDuration: number;
|
|
1563
|
+
/** Locomotion-driven intensity config (optional) */
|
|
1564
|
+
locomotion?: LocomotionConfig;
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* Default activation config.
|
|
1568
|
+
*/
|
|
1569
|
+
declare const DEFAULT_ACTIVATION_CONFIG: PhysicsActivationConfig;
|
|
1570
|
+
/**
|
|
1571
|
+
* Manages environment wind zones and computes aggregate wind force at a point.
|
|
1572
|
+
* Connects to WeatherBlackboard for global/ambient wind.
|
|
1573
|
+
*/
|
|
1574
|
+
declare class WindZoneManager {
|
|
1575
|
+
private zones;
|
|
1576
|
+
private time;
|
|
1577
|
+
/**
|
|
1578
|
+
* Add or update a wind zone.
|
|
1579
|
+
*/
|
|
1580
|
+
addZone(zone: WindZone): void;
|
|
1581
|
+
/**
|
|
1582
|
+
* Remove a wind zone by ID.
|
|
1583
|
+
*/
|
|
1584
|
+
removeZone(id: string): boolean;
|
|
1585
|
+
/**
|
|
1586
|
+
* Get a wind zone by ID.
|
|
1587
|
+
*/
|
|
1588
|
+
getZone(id: string): WindZone | undefined;
|
|
1589
|
+
/**
|
|
1590
|
+
* Get all registered wind zones.
|
|
1591
|
+
*/
|
|
1592
|
+
getAllZones(): WindZone[];
|
|
1593
|
+
/**
|
|
1594
|
+
* Advance internal time (for gust cycles).
|
|
1595
|
+
*/
|
|
1596
|
+
advanceTime(dt: number): void;
|
|
1597
|
+
/**
|
|
1598
|
+
* Get the current internal time.
|
|
1599
|
+
*/
|
|
1600
|
+
getTime(): number;
|
|
1601
|
+
/**
|
|
1602
|
+
* Compute the aggregate wind force at a world-space position,
|
|
1603
|
+
* combining all active wind zones + optional WeatherBlackboard ambient wind.
|
|
1604
|
+
*
|
|
1605
|
+
* @param worldPos - Sample point in world space
|
|
1606
|
+
* @param weather - Optional WeatherBlackboard state for ambient wind
|
|
1607
|
+
* @returns Aggregate wind force vector
|
|
1608
|
+
*/
|
|
1609
|
+
computeWindAt(worldPos: IVector3, weather?: WeatherBlackboardState): IVector3;
|
|
1610
|
+
/**
|
|
1611
|
+
* Compute a single zone's contribution at a point.
|
|
1612
|
+
*/
|
|
1613
|
+
private computeZoneContribution;
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Smooths a 3D velocity vector using Exponential Moving Average.
|
|
1617
|
+
* Prevents hair/cloth whip on instant direction changes (G.CHAR.006).
|
|
1618
|
+
*
|
|
1619
|
+
* EMA formula: smoothed = alpha * current + (1 - alpha) * previous
|
|
1620
|
+
* Lower alpha = smoother (more lag), higher alpha = more responsive.
|
|
1621
|
+
*/
|
|
1622
|
+
declare class VelocitySmoother {
|
|
1623
|
+
private smoothedX;
|
|
1624
|
+
private smoothedY;
|
|
1625
|
+
private smoothedZ;
|
|
1626
|
+
private initialized;
|
|
1627
|
+
private readonly alpha;
|
|
1628
|
+
constructor(alpha?: number);
|
|
1629
|
+
/**
|
|
1630
|
+
* Update with a new raw velocity sample and return smoothed result.
|
|
1631
|
+
*/
|
|
1632
|
+
update(raw: IVector3): IVector3;
|
|
1633
|
+
/**
|
|
1634
|
+
* Get current smoothed velocity without updating.
|
|
1635
|
+
*/
|
|
1636
|
+
getCurrent(): IVector3;
|
|
1637
|
+
/**
|
|
1638
|
+
* Get the magnitude of the current smoothed velocity.
|
|
1639
|
+
*/
|
|
1640
|
+
getSpeed(): number;
|
|
1641
|
+
/**
|
|
1642
|
+
* Reset to uninitialized state.
|
|
1643
|
+
*/
|
|
1644
|
+
reset(): void;
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Evaluates the physics intensity (0-1) from a speed value using
|
|
1648
|
+
* the configured intensity curve (piecewise linear interpolation).
|
|
1649
|
+
*/
|
|
1650
|
+
declare function evaluateIntensityCurve(speed: number, curve: IntensityCurvePoint[]): number;
|
|
1651
|
+
/**
|
|
1652
|
+
* Compute the self-wind vector from character velocity.
|
|
1653
|
+
* Self-wind opposes movement direction (headwind effect).
|
|
1654
|
+
*
|
|
1655
|
+
* @param smoothedVelocity - EMA-smoothed character velocity
|
|
1656
|
+
* @param scale - Self-wind scale factor (0-1)
|
|
1657
|
+
* @returns Opposing wind force vector
|
|
1658
|
+
*/
|
|
1659
|
+
declare function computeSelfWind(smoothedVelocity: IVector3, scale: number): IVector3;
|
|
1660
|
+
/**
|
|
1661
|
+
* Per-frame input to the activation controller.
|
|
1662
|
+
*/
|
|
1663
|
+
interface ActivationUpdateInput {
|
|
1664
|
+
/** Character root bone velocity (raw, will be EMA-smoothed internally) */
|
|
1665
|
+
characterVelocity?: IVector3;
|
|
1666
|
+
/** External wind force at simulation position */
|
|
1667
|
+
windForce?: IVector3;
|
|
1668
|
+
/** Current gravity vector (for gravity change detection) */
|
|
1669
|
+
gravity?: IVector3;
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Per-simulation activation controller.
|
|
1673
|
+
*
|
|
1674
|
+
* One controller per cloth/hair simulation instance. Manages the 4-state
|
|
1675
|
+
* sleep/wake machine, evaluates triggers, computes locomotion intensity,
|
|
1676
|
+
* and provides blending parameters for the owning solver.
|
|
1677
|
+
*
|
|
1678
|
+
* The controller does NOT run physics itself. It tells the solver:
|
|
1679
|
+
* - Whether to simulate this frame (isSimulating())
|
|
1680
|
+
* - What damping to use (getEffectiveDamping())
|
|
1681
|
+
* - What wind force to apply (getEffectiveWind())
|
|
1682
|
+
* - The current blend weight for WAKING transitions (getBlendWeight())
|
|
1683
|
+
* - The current physics intensity from locomotion (getIntensity())
|
|
1684
|
+
*
|
|
1685
|
+
* Usage:
|
|
1686
|
+
* ```typescript
|
|
1687
|
+
* const ctrl = new PhysicsActivationController(config);
|
|
1688
|
+
* // Each frame:
|
|
1689
|
+
* ctrl.update(dt, { characterVelocity, windForce, ... });
|
|
1690
|
+
* if (ctrl.isSimulating()) {
|
|
1691
|
+
* solver.setDamping(ctrl.getEffectiveDamping(baseDamping));
|
|
1692
|
+
* solver.setWind(ctrl.getEffectiveWind());
|
|
1693
|
+
* solver.step(dt);
|
|
1694
|
+
* }
|
|
1695
|
+
* ```
|
|
1696
|
+
*/
|
|
1697
|
+
declare class PhysicsActivationController {
|
|
1698
|
+
private state;
|
|
1699
|
+
private config;
|
|
1700
|
+
private stateTime;
|
|
1701
|
+
private triggerStates;
|
|
1702
|
+
private velocitySmoother;
|
|
1703
|
+
private currentIntensity;
|
|
1704
|
+
private selfWindVector;
|
|
1705
|
+
private currentWindForce;
|
|
1706
|
+
private maxVertexVelocity;
|
|
1707
|
+
private previousGravity;
|
|
1708
|
+
private activeAnimationEvents;
|
|
1709
|
+
constructor(config?: Partial<PhysicsActivationConfig>);
|
|
1710
|
+
/**
|
|
1711
|
+
* Get the current activation state.
|
|
1712
|
+
*/
|
|
1713
|
+
getState(): PhysicsActivationState;
|
|
1714
|
+
/**
|
|
1715
|
+
* Whether the physics solver should run this frame.
|
|
1716
|
+
* SLEEPING = false, all others = true.
|
|
1717
|
+
* If mode is 'always_on', always returns true.
|
|
1718
|
+
*/
|
|
1719
|
+
isSimulating(): boolean;
|
|
1720
|
+
/**
|
|
1721
|
+
* Get the current blend weight for WAKING transitions.
|
|
1722
|
+
* 0.0 = fully rest pose, 1.0 = fully simulated.
|
|
1723
|
+
* Returns 1.0 for ACTIVE and SETTLING states.
|
|
1724
|
+
*/
|
|
1725
|
+
getBlendWeight(): number;
|
|
1726
|
+
/**
|
|
1727
|
+
* Get the effective damping multiplier.
|
|
1728
|
+
* During SETTLING, damping is multiplied by settleDamping (3-5x).
|
|
1729
|
+
* Otherwise returns 1.0 (no modification to base damping).
|
|
1730
|
+
*/
|
|
1731
|
+
getEffectiveDampingMultiplier(): number;
|
|
1732
|
+
/**
|
|
1733
|
+
* Apply the activation damping multiplier to a base damping value.
|
|
1734
|
+
* Clamps result to [0, 1].
|
|
1735
|
+
*/
|
|
1736
|
+
getEffectiveDamping(baseDamping: number): number;
|
|
1737
|
+
/**
|
|
1738
|
+
* Get current physics intensity from locomotion (0-1).
|
|
1739
|
+
* Controls stiffness reduction, wind multiplier, inertia response.
|
|
1740
|
+
*/
|
|
1741
|
+
getIntensity(): number;
|
|
1742
|
+
/**
|
|
1743
|
+
* Get the current self-wind vector from character locomotion.
|
|
1744
|
+
* Opposes movement direction (headwind effect).
|
|
1745
|
+
*/
|
|
1746
|
+
getSelfWind(): IVector3;
|
|
1747
|
+
/**
|
|
1748
|
+
* Get the last computed external wind force at the simulation's position.
|
|
1749
|
+
*/
|
|
1750
|
+
getWindForce(): IVector3;
|
|
1751
|
+
/**
|
|
1752
|
+
* Get the total effective wind = external wind + self-wind.
|
|
1753
|
+
*/
|
|
1754
|
+
getEffectiveWind(): IVector3;
|
|
1755
|
+
/**
|
|
1756
|
+
* Get how long the controller has been in the current state (seconds).
|
|
1757
|
+
*/
|
|
1758
|
+
getStateTime(): number;
|
|
1759
|
+
/**
|
|
1760
|
+
* Check if any trigger is currently active.
|
|
1761
|
+
*/
|
|
1762
|
+
hasActiveTrigger(): boolean;
|
|
1763
|
+
/**
|
|
1764
|
+
* Check if a specific trigger type is currently active.
|
|
1765
|
+
*/
|
|
1766
|
+
isTriggerActive(type: ActivationTriggerType): boolean;
|
|
1767
|
+
/**
|
|
1768
|
+
* Get the configuration.
|
|
1769
|
+
*/
|
|
1770
|
+
getConfig(): Readonly<PhysicsActivationConfig>;
|
|
1771
|
+
/**
|
|
1772
|
+
* Notify the controller of an animation event (e.g., "jump", "attack").
|
|
1773
|
+
* If the event matches a configured trigger, it activates.
|
|
1774
|
+
*/
|
|
1775
|
+
notifyAnimationEvent(eventName: string): void;
|
|
1776
|
+
/**
|
|
1777
|
+
* Notify the controller of a collision event.
|
|
1778
|
+
*/
|
|
1779
|
+
notifyCollision(): void;
|
|
1780
|
+
/**
|
|
1781
|
+
* Provide the maximum vertex velocity for SETTLING convergence check.
|
|
1782
|
+
* The solver should call this each frame with the max velocity across all particles.
|
|
1783
|
+
*/
|
|
1784
|
+
reportMaxVertexVelocity(velocity: number): void;
|
|
1785
|
+
/**
|
|
1786
|
+
* Force an immediate transition to a specific state.
|
|
1787
|
+
* Use with caution — typically the state machine manages transitions.
|
|
1788
|
+
*/
|
|
1789
|
+
forceState(state: PhysicsActivationState): void;
|
|
1790
|
+
/**
|
|
1791
|
+
* Main update. Call once per frame before running the physics solver.
|
|
1792
|
+
*
|
|
1793
|
+
* @param dt - Delta time in seconds
|
|
1794
|
+
* @param input - Frame input (velocity, wind, gravity)
|
|
1795
|
+
*/
|
|
1796
|
+
update(dt: number, input?: ActivationUpdateInput): void;
|
|
1797
|
+
private updateVelocityTrigger;
|
|
1798
|
+
private updateWindTrigger;
|
|
1799
|
+
private updateAnimationTrigger;
|
|
1800
|
+
private updateGravityTrigger;
|
|
1801
|
+
private updateCollisionTriggerDecay;
|
|
1802
|
+
private decayTriggerDelays;
|
|
1803
|
+
private updateLocomotion;
|
|
1804
|
+
private updateStateMachine;
|
|
1805
|
+
private transitionTo;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
/**
|
|
1809
|
+
* SoftBodyAdapter
|
|
1810
|
+
*
|
|
1811
|
+
* Bridges the HoloScript Entity/Node system with the SoftBodySolver (PBD).
|
|
1812
|
+
* Handles the conversion of Mesh vertices to Particles and syncs them back.
|
|
1813
|
+
*
|
|
1814
|
+
* @version 1.0.0
|
|
1815
|
+
*/
|
|
1816
|
+
declare class SoftBodyAdapter {
|
|
1817
|
+
private solver;
|
|
1818
|
+
private node;
|
|
1819
|
+
private vertexMapping;
|
|
1820
|
+
constructor(node: any, config: any);
|
|
1821
|
+
update(dt: number): void;
|
|
1822
|
+
private createSoftBodyFromMesh;
|
|
1823
|
+
private syncBackToMesh;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
interface Particle {
|
|
1827
|
+
position: [number, number, number];
|
|
1828
|
+
previousPosition: [number, number, number];
|
|
1829
|
+
velocity: [number, number, number];
|
|
1830
|
+
invMass: number;
|
|
1831
|
+
}
|
|
1832
|
+
interface DistanceConstraint {
|
|
1833
|
+
p1: number;
|
|
1834
|
+
p2: number;
|
|
1835
|
+
restLength: number;
|
|
1836
|
+
stiffness: number;
|
|
1837
|
+
}
|
|
1838
|
+
declare class SoftBodySolver {
|
|
1839
|
+
private particles;
|
|
1840
|
+
private constraints;
|
|
1841
|
+
private gravity;
|
|
1842
|
+
private substeps;
|
|
1843
|
+
constructor(particles: Particle[], constraints: DistanceConstraint[]);
|
|
1844
|
+
/**
|
|
1845
|
+
* Step the simulation using PBD.
|
|
1846
|
+
*/
|
|
1847
|
+
step(dt: number): void;
|
|
1848
|
+
private predictPositions;
|
|
1849
|
+
private solveConstraints;
|
|
1850
|
+
private updateVelocities;
|
|
1851
|
+
getParticles(): Particle[];
|
|
1852
|
+
getConstraints(): DistanceConstraint[];
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/**
|
|
1856
|
+
* VRPhysicsBridge.ts
|
|
1857
|
+
*
|
|
1858
|
+
* Bridges the gap between WebXR input (Hands/Headset) and the Physics Engine.
|
|
1859
|
+
* Responsibilities:
|
|
1860
|
+
* 1. Create/Update Kinematic Bodies for hands/fingers.
|
|
1861
|
+
* 2. Sync velocity for throwing mechanics.
|
|
1862
|
+
* 3. Manage collision layers for hands (to avoid self-collision if needed).
|
|
1863
|
+
*/
|
|
1864
|
+
|
|
1865
|
+
declare class VRPhysicsBridge {
|
|
1866
|
+
private world;
|
|
1867
|
+
private handBodies;
|
|
1868
|
+
private lastPositions;
|
|
1869
|
+
private lastRotations;
|
|
1870
|
+
private onHaptic;
|
|
1871
|
+
constructor(world: IPhysicsWorld, onHaptic?: (hand: 'left' | 'right', intensity: number, duration: number) => void);
|
|
1872
|
+
update(vrContext: {
|
|
1873
|
+
hands: {
|
|
1874
|
+
left: VRHand | null;
|
|
1875
|
+
right: VRHand | null;
|
|
1876
|
+
};
|
|
1877
|
+
}, delta: number): void;
|
|
1878
|
+
private checkCollisions;
|
|
1879
|
+
updateHand(hand: VRHand | null, side: 'left' | 'right', delta: number): void;
|
|
1880
|
+
getHandBodyId(side: 'left' | 'right'): string | null;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
/**
|
|
1884
|
+
* ClothSim.ts
|
|
1885
|
+
*
|
|
1886
|
+
* Mass-spring cloth simulation: particle grid, distance constraints,
|
|
1887
|
+
* pin points, wind, gravity, and self-collision.
|
|
1888
|
+
*
|
|
1889
|
+
* @module physics
|
|
1890
|
+
*/
|
|
1891
|
+
interface ClothParticle {
|
|
1892
|
+
x: number;
|
|
1893
|
+
y: number;
|
|
1894
|
+
z: number;
|
|
1895
|
+
prevX: number;
|
|
1896
|
+
prevY: number;
|
|
1897
|
+
prevZ: number;
|
|
1898
|
+
mass: number;
|
|
1899
|
+
pinned: boolean;
|
|
1900
|
+
}
|
|
1901
|
+
interface ClothConstraint {
|
|
1902
|
+
particleA: number;
|
|
1903
|
+
particleB: number;
|
|
1904
|
+
restLength: number;
|
|
1905
|
+
stiffness: number;
|
|
1906
|
+
}
|
|
1907
|
+
interface ClothConfig {
|
|
1908
|
+
gravity: number;
|
|
1909
|
+
damping: number;
|
|
1910
|
+
iterations: number;
|
|
1911
|
+
wind: {
|
|
1912
|
+
x: number;
|
|
1913
|
+
y: number;
|
|
1914
|
+
z: number;
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
declare class ClothSim {
|
|
1918
|
+
private particles;
|
|
1919
|
+
private constraints;
|
|
1920
|
+
private config;
|
|
1921
|
+
private width;
|
|
1922
|
+
private height;
|
|
1923
|
+
constructor(config?: Partial<ClothConfig>);
|
|
1924
|
+
createGrid(width: number, height: number, spacing: number): void;
|
|
1925
|
+
private addConstraint;
|
|
1926
|
+
pin(index: number): void;
|
|
1927
|
+
unpin(index: number): void;
|
|
1928
|
+
pinTopRow(): void;
|
|
1929
|
+
update(dt: number): void;
|
|
1930
|
+
setWind(x: number, y: number, z: number): void;
|
|
1931
|
+
getParticle(index: number): ClothParticle | undefined;
|
|
1932
|
+
getParticleCount(): number;
|
|
1933
|
+
getConstraintCount(): number;
|
|
1934
|
+
getGridSize(): {
|
|
1935
|
+
width: number;
|
|
1936
|
+
height: number;
|
|
1937
|
+
};
|
|
1938
|
+
getAABB(): {
|
|
1939
|
+
min: {
|
|
1940
|
+
x: number;
|
|
1941
|
+
y: number;
|
|
1942
|
+
z: number;
|
|
1943
|
+
};
|
|
1944
|
+
max: {
|
|
1945
|
+
x: number;
|
|
1946
|
+
y: number;
|
|
1947
|
+
z: number;
|
|
1948
|
+
};
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
/**
|
|
1953
|
+
* ConstraintSolver.ts
|
|
1954
|
+
*
|
|
1955
|
+
* Sequential Impulse constraint solver for the HoloScript physics engine.
|
|
1956
|
+
* Supports all 8 constraint types defined in PhysicsTypes.ts.
|
|
1957
|
+
*
|
|
1958
|
+
* Features:
|
|
1959
|
+
* - Warm starting for convergence acceleration
|
|
1960
|
+
* - Baumgarte stabilization for drift correction
|
|
1961
|
+
* - Motor and limit support for hinge/slider joints
|
|
1962
|
+
*
|
|
1963
|
+
* @module physics
|
|
1964
|
+
*/
|
|
1965
|
+
|
|
1966
|
+
interface ConstraintSolverConfig {
|
|
1967
|
+
iterations: number;
|
|
1968
|
+
baumgarte: number;
|
|
1969
|
+
warmStarting: boolean;
|
|
1970
|
+
slop: number;
|
|
1971
|
+
}
|
|
1972
|
+
declare class ConstraintSolver {
|
|
1973
|
+
private config;
|
|
1974
|
+
private solved;
|
|
1975
|
+
constructor(config?: Partial<ConstraintSolverConfig>);
|
|
1976
|
+
/**
|
|
1977
|
+
* Add a constraint to be solved.
|
|
1978
|
+
*/
|
|
1979
|
+
addConstraint(constraint: Constraint, bodyA: IRigidBodyState, bodyB?: IRigidBodyState | null): void;
|
|
1980
|
+
/**
|
|
1981
|
+
* Remove a constraint by ID.
|
|
1982
|
+
*/
|
|
1983
|
+
removeConstraint(constraintId: string): boolean;
|
|
1984
|
+
/**
|
|
1985
|
+
* Get all active constraints.
|
|
1986
|
+
*/
|
|
1987
|
+
getConstraints(): Constraint[];
|
|
1988
|
+
/**
|
|
1989
|
+
* Solve all constraints for one timestep.
|
|
1990
|
+
* Returns velocity corrections to apply to rigid bodies.
|
|
1991
|
+
*/
|
|
1992
|
+
solve(dt: number): Map<string, {
|
|
1993
|
+
linearVelocity: IVector3;
|
|
1994
|
+
angularVelocity: IVector3;
|
|
1995
|
+
}>;
|
|
1996
|
+
/**
|
|
1997
|
+
* Get broken constraint IDs.
|
|
1998
|
+
*/
|
|
1999
|
+
getBrokenConstraints(): string[];
|
|
2000
|
+
/**
|
|
2001
|
+
* Clear all constraints.
|
|
2002
|
+
*/
|
|
2003
|
+
clear(): void;
|
|
2004
|
+
private solveConstraint;
|
|
2005
|
+
private solveFixed;
|
|
2006
|
+
private solveDistance;
|
|
2007
|
+
private solveSpring;
|
|
2008
|
+
private solveHinge;
|
|
2009
|
+
private solveBall;
|
|
2010
|
+
private solveSlider;
|
|
2011
|
+
private solveCone;
|
|
2012
|
+
private solveGeneric6DOF;
|
|
2013
|
+
private applyWarmStart;
|
|
2014
|
+
private accumulateCorrection;
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/**
|
|
2018
|
+
* DeformableMesh.ts
|
|
2019
|
+
*
|
|
2020
|
+
* Deformable mesh: vertex displacement, spring-damper networks,
|
|
2021
|
+
* shape matching for volume preservation, and impact deformation.
|
|
2022
|
+
*
|
|
2023
|
+
* @module physics
|
|
2024
|
+
*/
|
|
2025
|
+
interface DeformVertex {
|
|
2026
|
+
rest: {
|
|
2027
|
+
x: number;
|
|
2028
|
+
y: number;
|
|
2029
|
+
z: number;
|
|
2030
|
+
};
|
|
2031
|
+
current: {
|
|
2032
|
+
x: number;
|
|
2033
|
+
y: number;
|
|
2034
|
+
z: number;
|
|
2035
|
+
};
|
|
2036
|
+
velocity: {
|
|
2037
|
+
x: number;
|
|
2038
|
+
y: number;
|
|
2039
|
+
z: number;
|
|
2040
|
+
};
|
|
2041
|
+
mass: number;
|
|
2042
|
+
locked: boolean;
|
|
2043
|
+
}
|
|
2044
|
+
interface DeformSpring {
|
|
2045
|
+
a: number;
|
|
2046
|
+
b: number;
|
|
2047
|
+
restLength: number;
|
|
2048
|
+
stiffness: number;
|
|
2049
|
+
damping: number;
|
|
2050
|
+
}
|
|
2051
|
+
interface DeformConfig {
|
|
2052
|
+
stiffness: number;
|
|
2053
|
+
damping: number;
|
|
2054
|
+
shapeMatchingStrength: number;
|
|
2055
|
+
maxDisplacement: number;
|
|
2056
|
+
plasticity: number;
|
|
2057
|
+
}
|
|
2058
|
+
declare class DeformableMesh {
|
|
2059
|
+
private vertices;
|
|
2060
|
+
private springs;
|
|
2061
|
+
private config;
|
|
2062
|
+
private restCentroid;
|
|
2063
|
+
constructor(config?: Partial<DeformConfig>);
|
|
2064
|
+
setVertices(positions: Array<{
|
|
2065
|
+
x: number;
|
|
2066
|
+
y: number;
|
|
2067
|
+
z: number;
|
|
2068
|
+
}>): void;
|
|
2069
|
+
addSpring(a: number, b: number, stiffness?: number, damping?: number): void;
|
|
2070
|
+
autoConnectRadius(radius: number): void;
|
|
2071
|
+
private computeRestCentroid;
|
|
2072
|
+
applyImpact(center: {
|
|
2073
|
+
x: number;
|
|
2074
|
+
y: number;
|
|
2075
|
+
z: number;
|
|
2076
|
+
}, radius: number, force: number): void;
|
|
2077
|
+
update(dt: number): void;
|
|
2078
|
+
getVertices(): DeformVertex[];
|
|
2079
|
+
getVertex(index: number): DeformVertex | undefined;
|
|
2080
|
+
getVertexCount(): number;
|
|
2081
|
+
getSpringCount(): number;
|
|
2082
|
+
getDisplacement(index: number): number;
|
|
2083
|
+
getMaxDisplacement(): number;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* FluidSim.ts
|
|
2088
|
+
*
|
|
2089
|
+
* SPH fluid: particle-based fluid simulation, viscosity,
|
|
2090
|
+
* surface tension, boundary handling, and density queries.
|
|
2091
|
+
*
|
|
2092
|
+
* @module physics
|
|
2093
|
+
*/
|
|
2094
|
+
interface FluidParticle {
|
|
2095
|
+
position: [number, number, number];
|
|
2096
|
+
velocity: {
|
|
2097
|
+
x: number;
|
|
2098
|
+
y: number;
|
|
2099
|
+
z: number;
|
|
2100
|
+
};
|
|
2101
|
+
density: number;
|
|
2102
|
+
pressure: number;
|
|
2103
|
+
mass: number;
|
|
2104
|
+
}
|
|
2105
|
+
interface FluidConfig {
|
|
2106
|
+
restDensity: number;
|
|
2107
|
+
gasConstant: number;
|
|
2108
|
+
viscosity: number;
|
|
2109
|
+
surfaceTension: number;
|
|
2110
|
+
gravity: {
|
|
2111
|
+
x: number;
|
|
2112
|
+
y: number;
|
|
2113
|
+
z: number;
|
|
2114
|
+
};
|
|
2115
|
+
smoothingRadius: number;
|
|
2116
|
+
timeStep: number;
|
|
2117
|
+
boundaryMin: {
|
|
2118
|
+
x: number;
|
|
2119
|
+
y: number;
|
|
2120
|
+
z: number;
|
|
2121
|
+
};
|
|
2122
|
+
boundaryMax: {
|
|
2123
|
+
x: number;
|
|
2124
|
+
y: number;
|
|
2125
|
+
z: number;
|
|
2126
|
+
};
|
|
2127
|
+
boundaryDamping: number;
|
|
2128
|
+
}
|
|
2129
|
+
declare class FluidSim {
|
|
2130
|
+
private particles;
|
|
2131
|
+
private config;
|
|
2132
|
+
constructor(config?: Partial<FluidConfig>);
|
|
2133
|
+
addParticle(position: [number, number, number], velocity?: {
|
|
2134
|
+
x: number;
|
|
2135
|
+
y: number;
|
|
2136
|
+
z: number;
|
|
2137
|
+
}): void;
|
|
2138
|
+
addBlock(min: {
|
|
2139
|
+
x: number;
|
|
2140
|
+
y: number;
|
|
2141
|
+
z: number;
|
|
2142
|
+
}, max: {
|
|
2143
|
+
x: number;
|
|
2144
|
+
y: number;
|
|
2145
|
+
z: number;
|
|
2146
|
+
}, spacing: number): number;
|
|
2147
|
+
private poly6;
|
|
2148
|
+
private spikyGrad;
|
|
2149
|
+
private viscosityLaplacian;
|
|
2150
|
+
update(): void;
|
|
2151
|
+
private enforceBoundaries;
|
|
2152
|
+
getParticles(): FluidParticle[];
|
|
2153
|
+
getParticleCount(): number;
|
|
2154
|
+
getAverageDensity(): number;
|
|
2155
|
+
getKineticEnergy(): number;
|
|
2156
|
+
clear(): void;
|
|
2157
|
+
setConfig(config: Partial<FluidConfig>): void;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
/**
|
|
2161
|
+
* JointSystem.ts
|
|
2162
|
+
*
|
|
2163
|
+
* Physics joint types: hinge, ball, slider, spring, distance, fixed.
|
|
2164
|
+
* Constraint solving, breakable joints, and motor forces.
|
|
2165
|
+
*
|
|
2166
|
+
* @module physics
|
|
2167
|
+
*/
|
|
2168
|
+
type JointType = 'hinge' | 'ball' | 'slider' | 'spring' | 'distance' | 'fixed';
|
|
2169
|
+
interface JointDef {
|
|
2170
|
+
id: string;
|
|
2171
|
+
type: JointType;
|
|
2172
|
+
bodyA: string;
|
|
2173
|
+
bodyB: string;
|
|
2174
|
+
anchorA: {
|
|
2175
|
+
x: number;
|
|
2176
|
+
y: number;
|
|
2177
|
+
z: number;
|
|
2178
|
+
};
|
|
2179
|
+
anchorB: {
|
|
2180
|
+
x: number;
|
|
2181
|
+
y: number;
|
|
2182
|
+
z: number;
|
|
2183
|
+
};
|
|
2184
|
+
axis?: {
|
|
2185
|
+
x: number;
|
|
2186
|
+
y: number;
|
|
2187
|
+
z: number;
|
|
2188
|
+
};
|
|
2189
|
+
limits?: {
|
|
2190
|
+
min: number;
|
|
2191
|
+
max: number;
|
|
2192
|
+
};
|
|
2193
|
+
breakForce: number;
|
|
2194
|
+
stiffness: number;
|
|
2195
|
+
damping: number;
|
|
2196
|
+
motorSpeed: number;
|
|
2197
|
+
motorForce: number;
|
|
2198
|
+
broken: boolean;
|
|
2199
|
+
enabled: boolean;
|
|
2200
|
+
}
|
|
2201
|
+
interface JointState {
|
|
2202
|
+
currentForce: number;
|
|
2203
|
+
currentAngle: number;
|
|
2204
|
+
currentDistance: number;
|
|
2205
|
+
}
|
|
2206
|
+
declare class JointSystem {
|
|
2207
|
+
private joints;
|
|
2208
|
+
private states;
|
|
2209
|
+
private bodyJoints;
|
|
2210
|
+
createJoint(type: JointType, bodyA: string, bodyB: string, config?: Partial<JointDef>): JointDef;
|
|
2211
|
+
removeJoint(id: string): boolean;
|
|
2212
|
+
solve(dt: number): void;
|
|
2213
|
+
setMotor(id: string, speed: number, force: number): void;
|
|
2214
|
+
setEnabled(id: string, enabled: boolean): void;
|
|
2215
|
+
setAngle(id: string, angle: number): void;
|
|
2216
|
+
setDistance(id: string, dist: number): void;
|
|
2217
|
+
getJoint(id: string): JointDef | undefined;
|
|
2218
|
+
getState(id: string): JointState | undefined;
|
|
2219
|
+
getJointCount(): number;
|
|
2220
|
+
getBrokenJoints(): JointDef[];
|
|
2221
|
+
getJointsForBody(bodyId: string): JointDef[];
|
|
2222
|
+
private distance3D;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
/**
|
|
2226
|
+
* RagdollController.ts
|
|
2227
|
+
*
|
|
2228
|
+
* Ragdoll physics: bone chain definition, joint limits,
|
|
2229
|
+
* active/ragdoll blending, and impulse application.
|
|
2230
|
+
*
|
|
2231
|
+
* @module physics
|
|
2232
|
+
*/
|
|
2233
|
+
interface RagdollBone {
|
|
2234
|
+
id: string;
|
|
2235
|
+
name: string;
|
|
2236
|
+
parentId: string | null;
|
|
2237
|
+
position: [number, number, number];
|
|
2238
|
+
rotation: {
|
|
2239
|
+
x: number;
|
|
2240
|
+
y: number;
|
|
2241
|
+
z: number;
|
|
2242
|
+
};
|
|
2243
|
+
velocity: {
|
|
2244
|
+
x: number;
|
|
2245
|
+
y: number;
|
|
2246
|
+
z: number;
|
|
2247
|
+
};
|
|
2248
|
+
angularVelocity: {
|
|
2249
|
+
x: number;
|
|
2250
|
+
y: number;
|
|
2251
|
+
z: number;
|
|
2252
|
+
};
|
|
2253
|
+
mass: number;
|
|
2254
|
+
length: number;
|
|
2255
|
+
jointLimits: {
|
|
2256
|
+
min: {
|
|
2257
|
+
x: number;
|
|
2258
|
+
y: number;
|
|
2259
|
+
z: number;
|
|
2260
|
+
};
|
|
2261
|
+
max: {
|
|
2262
|
+
x: number;
|
|
2263
|
+
y: number;
|
|
2264
|
+
z: number;
|
|
2265
|
+
};
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
interface RagdollConfig {
|
|
2269
|
+
gravity: number;
|
|
2270
|
+
damping: number;
|
|
2271
|
+
iterations: number;
|
|
2272
|
+
}
|
|
2273
|
+
type RagdollState = 'active' | 'ragdoll' | 'blending';
|
|
2274
|
+
declare class RagdollController {
|
|
2275
|
+
private bones;
|
|
2276
|
+
private rootBone;
|
|
2277
|
+
private state;
|
|
2278
|
+
private blendFactor;
|
|
2279
|
+
private blendSpeed;
|
|
2280
|
+
private config;
|
|
2281
|
+
constructor(config?: Partial<RagdollConfig>);
|
|
2282
|
+
addBone(name: string, parentId: string | null, mass: number, length: number, limits?: {
|
|
2283
|
+
min: {
|
|
2284
|
+
x: number;
|
|
2285
|
+
y: number;
|
|
2286
|
+
z: number;
|
|
2287
|
+
};
|
|
2288
|
+
max: {
|
|
2289
|
+
x: number;
|
|
2290
|
+
y: number;
|
|
2291
|
+
z: number;
|
|
2292
|
+
};
|
|
2293
|
+
}): RagdollBone;
|
|
2294
|
+
removeBone(name: string): boolean;
|
|
2295
|
+
activate(): void;
|
|
2296
|
+
goRagdoll(): void;
|
|
2297
|
+
startBlend(toRagdoll?: boolean): void;
|
|
2298
|
+
getState(): RagdollState;
|
|
2299
|
+
getBlendFactor(): number;
|
|
2300
|
+
update(dt: number): void;
|
|
2301
|
+
applyImpulse(boneId: string, impulse: {
|
|
2302
|
+
x: number;
|
|
2303
|
+
y: number;
|
|
2304
|
+
z: number;
|
|
2305
|
+
}): void;
|
|
2306
|
+
getBone(id: string): RagdollBone | undefined;
|
|
2307
|
+
getBoneCount(): number;
|
|
2308
|
+
getRootBone(): RagdollBone | undefined;
|
|
2309
|
+
getChildren(boneId: string): RagdollBone[];
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
/**
|
|
2313
|
+
* RagdollSystem.ts
|
|
2314
|
+
*
|
|
2315
|
+
* Ragdoll physics system for articulated character bodies.
|
|
2316
|
+
* Creates rigid body chains with cone/hinge constraints for humanoid and quadruped skeletons.
|
|
2317
|
+
*
|
|
2318
|
+
* @module physics
|
|
2319
|
+
*/
|
|
2320
|
+
|
|
2321
|
+
interface BoneDefinition {
|
|
2322
|
+
id: string;
|
|
2323
|
+
parentBone?: string;
|
|
2324
|
+
length: number;
|
|
2325
|
+
radius: number;
|
|
2326
|
+
mass: number;
|
|
2327
|
+
localOffset: IVector3;
|
|
2328
|
+
jointType: 'cone' | 'hinge';
|
|
2329
|
+
jointLimits?: {
|
|
2330
|
+
swingSpan1?: number;
|
|
2331
|
+
swingSpan2?: number;
|
|
2332
|
+
twistSpan?: number;
|
|
2333
|
+
low?: number;
|
|
2334
|
+
high?: number;
|
|
2335
|
+
};
|
|
2336
|
+
}
|
|
2337
|
+
interface RagdollDefinition {
|
|
2338
|
+
id: string;
|
|
2339
|
+
bones: BoneDefinition[];
|
|
2340
|
+
}
|
|
2341
|
+
interface RagdollInstance {
|
|
2342
|
+
id: string;
|
|
2343
|
+
definition: RagdollDefinition;
|
|
2344
|
+
bodies: IRigidBodyConfig[];
|
|
2345
|
+
constraints: Constraint[];
|
|
2346
|
+
rootPosition: IVector3;
|
|
2347
|
+
}
|
|
2348
|
+
declare const HUMANOID_PRESET: BoneDefinition[];
|
|
2349
|
+
declare const QUADRUPED_PRESET: BoneDefinition[];
|
|
2350
|
+
declare class RagdollSystem {
|
|
2351
|
+
private ragdolls;
|
|
2352
|
+
/**
|
|
2353
|
+
* Create a ragdoll from a definition at a given world position.
|
|
2354
|
+
*/
|
|
2355
|
+
createRagdoll(definition: RagdollDefinition, rootPosition: IVector3): RagdollInstance;
|
|
2356
|
+
/**
|
|
2357
|
+
* Create humanoid ragdoll from preset.
|
|
2358
|
+
*/
|
|
2359
|
+
createHumanoid(id: string, rootPosition: IVector3): RagdollInstance;
|
|
2360
|
+
/**
|
|
2361
|
+
* Create quadruped ragdoll from preset.
|
|
2362
|
+
*/
|
|
2363
|
+
createQuadruped(id: string, rootPosition: IVector3): RagdollInstance;
|
|
2364
|
+
/**
|
|
2365
|
+
* Get a ragdoll instance by ID.
|
|
2366
|
+
*/
|
|
2367
|
+
getRagdoll(id: string): RagdollInstance | undefined;
|
|
2368
|
+
/**
|
|
2369
|
+
* Remove a ragdoll.
|
|
2370
|
+
*/
|
|
2371
|
+
removeRagdoll(id: string): boolean;
|
|
2372
|
+
/**
|
|
2373
|
+
* Get total mass of a ragdoll.
|
|
2374
|
+
*/
|
|
2375
|
+
getTotalMass(id: string): number;
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
/**
|
|
2379
|
+
* RaycastSystem.ts
|
|
2380
|
+
*
|
|
2381
|
+
* Raycasting: ray-AABB, ray-sphere, ray-plane intersection tests,
|
|
2382
|
+
* distance sorting, layer masks, and batch queries.
|
|
2383
|
+
*
|
|
2384
|
+
* @module physics
|
|
2385
|
+
*/
|
|
2386
|
+
interface Ray {
|
|
2387
|
+
origin: {
|
|
2388
|
+
x: number;
|
|
2389
|
+
y: number;
|
|
2390
|
+
z: number;
|
|
2391
|
+
};
|
|
2392
|
+
direction: {
|
|
2393
|
+
x: number;
|
|
2394
|
+
y: number;
|
|
2395
|
+
z: number;
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2398
|
+
interface AABB {
|
|
2399
|
+
min: {
|
|
2400
|
+
x: number;
|
|
2401
|
+
y: number;
|
|
2402
|
+
z: number;
|
|
2403
|
+
};
|
|
2404
|
+
max: {
|
|
2405
|
+
x: number;
|
|
2406
|
+
y: number;
|
|
2407
|
+
z: number;
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
interface Sphere {
|
|
2411
|
+
center: {
|
|
2412
|
+
x: number;
|
|
2413
|
+
y: number;
|
|
2414
|
+
z: number;
|
|
2415
|
+
};
|
|
2416
|
+
radius: number;
|
|
2417
|
+
}
|
|
2418
|
+
interface Plane {
|
|
2419
|
+
normal: {
|
|
2420
|
+
x: number;
|
|
2421
|
+
y: number;
|
|
2422
|
+
z: number;
|
|
2423
|
+
};
|
|
2424
|
+
distance: number;
|
|
2425
|
+
}
|
|
2426
|
+
interface RayHit {
|
|
2427
|
+
entityId: string;
|
|
2428
|
+
distance: number;
|
|
2429
|
+
point: {
|
|
2430
|
+
x: number;
|
|
2431
|
+
y: number;
|
|
2432
|
+
z: number;
|
|
2433
|
+
};
|
|
2434
|
+
normal: {
|
|
2435
|
+
x: number;
|
|
2436
|
+
y: number;
|
|
2437
|
+
z: number;
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
interface Collider {
|
|
2441
|
+
entityId: string;
|
|
2442
|
+
type: 'aabb' | 'sphere' | 'plane';
|
|
2443
|
+
shape: AABB | Sphere | Plane;
|
|
2444
|
+
layer: number;
|
|
2445
|
+
}
|
|
2446
|
+
declare class RaycastSystem {
|
|
2447
|
+
private colliders;
|
|
2448
|
+
addCollider(collider: Collider): void;
|
|
2449
|
+
removeCollider(entityId: string): void;
|
|
2450
|
+
getColliderCount(): number;
|
|
2451
|
+
raycast(ray: Ray, maxDistance?: number, layerMask?: number): RayHit | null;
|
|
2452
|
+
raycastAll(ray: Ray, maxDistance?: number, layerMask?: number): RayHit[];
|
|
2453
|
+
private rayAABB;
|
|
2454
|
+
private raySphere;
|
|
2455
|
+
private rayPlane;
|
|
2456
|
+
private normalize;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
/**
|
|
2460
|
+
* RopeSystem.ts
|
|
2461
|
+
*
|
|
2462
|
+
* Verlet rope/chain: segment links, tension, pin/attach points,
|
|
2463
|
+
* gravity, damping, and length constraints.
|
|
2464
|
+
*
|
|
2465
|
+
* @module physics
|
|
2466
|
+
*/
|
|
2467
|
+
interface RopeNode {
|
|
2468
|
+
position: [number, number, number];
|
|
2469
|
+
previous: {
|
|
2470
|
+
x: number;
|
|
2471
|
+
y: number;
|
|
2472
|
+
z: number;
|
|
2473
|
+
};
|
|
2474
|
+
mass: number;
|
|
2475
|
+
pinned: boolean;
|
|
2476
|
+
}
|
|
2477
|
+
interface RopeConfig {
|
|
2478
|
+
segmentCount: number;
|
|
2479
|
+
segmentLength: number;
|
|
2480
|
+
gravity: {
|
|
2481
|
+
x: number;
|
|
2482
|
+
y: number;
|
|
2483
|
+
z: number;
|
|
2484
|
+
};
|
|
2485
|
+
damping: number;
|
|
2486
|
+
iterations: number;
|
|
2487
|
+
elasticity: number;
|
|
2488
|
+
}
|
|
2489
|
+
interface RopeAttachment {
|
|
2490
|
+
nodeIndex: number;
|
|
2491
|
+
entityId: string;
|
|
2492
|
+
offset: {
|
|
2493
|
+
x: number;
|
|
2494
|
+
y: number;
|
|
2495
|
+
z: number;
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
declare class RopeSystem {
|
|
2499
|
+
private ropes;
|
|
2500
|
+
createRope(id: string, start: {
|
|
2501
|
+
x: number;
|
|
2502
|
+
y: number;
|
|
2503
|
+
z: number;
|
|
2504
|
+
}, end: {
|
|
2505
|
+
x: number;
|
|
2506
|
+
y: number;
|
|
2507
|
+
z: number;
|
|
2508
|
+
}, config?: Partial<RopeConfig>): void;
|
|
2509
|
+
pinNode(ropeId: string, nodeIndex: number): void;
|
|
2510
|
+
unpinNode(ropeId: string, nodeIndex: number): void;
|
|
2511
|
+
attach(ropeId: string, attachment: RopeAttachment): void;
|
|
2512
|
+
update(dt: number): void;
|
|
2513
|
+
getRopeNodes(ropeId: string): RopeNode[];
|
|
2514
|
+
getRopeLength(ropeId: string): number;
|
|
2515
|
+
getTension(ropeId: string, nodeIndex: number): number;
|
|
2516
|
+
getRopeCount(): number;
|
|
2517
|
+
removeRope(id: string): void;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
/**
|
|
2521
|
+
* TriggerZone.ts
|
|
2522
|
+
*
|
|
2523
|
+
* Trigger zones: enter/stay/exit callbacks, shape overlap tests,
|
|
2524
|
+
* zone stacking, and entity tracking.
|
|
2525
|
+
*
|
|
2526
|
+
* @module physics
|
|
2527
|
+
*/
|
|
2528
|
+
type TriggerEvent = 'enter' | 'stay' | 'exit';
|
|
2529
|
+
type TriggerCallback = (entityId: string, zoneId: string, event: TriggerEvent) => void;
|
|
2530
|
+
interface TriggerShape {
|
|
2531
|
+
type: 'box' | 'sphere';
|
|
2532
|
+
position: [number, number, number];
|
|
2533
|
+
halfExtents?: {
|
|
2534
|
+
x: number;
|
|
2535
|
+
y: number;
|
|
2536
|
+
z: number;
|
|
2537
|
+
};
|
|
2538
|
+
radius?: number;
|
|
2539
|
+
}
|
|
2540
|
+
interface TriggerZoneConfig {
|
|
2541
|
+
id: string;
|
|
2542
|
+
shape: TriggerShape;
|
|
2543
|
+
enabled: boolean;
|
|
2544
|
+
tags: string[];
|
|
2545
|
+
}
|
|
2546
|
+
declare class TriggerZoneSystem {
|
|
2547
|
+
private zones;
|
|
2548
|
+
private callbacks;
|
|
2549
|
+
private occupants;
|
|
2550
|
+
addZone(config: TriggerZoneConfig): void;
|
|
2551
|
+
removeZone(id: string): void;
|
|
2552
|
+
enableZone(id: string, enabled: boolean): void;
|
|
2553
|
+
onTrigger(zoneId: string, callback: TriggerCallback): void;
|
|
2554
|
+
private fire;
|
|
2555
|
+
update(entities: Array<{
|
|
2556
|
+
id: string;
|
|
2557
|
+
position: [number, number, number];
|
|
2558
|
+
radius?: number;
|
|
2559
|
+
}>): void;
|
|
2560
|
+
private overlaps;
|
|
2561
|
+
isInside(entityId: string, zoneId: string): boolean;
|
|
2562
|
+
getOccupants(zoneId: string): string[];
|
|
2563
|
+
getZonesForEntity(entityId: string): string[];
|
|
2564
|
+
getZoneCount(): number;
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
/**
|
|
2568
|
+
* VehicleSystem.ts
|
|
2569
|
+
*
|
|
2570
|
+
* Raycast vehicle physics system.
|
|
2571
|
+
* Implements suspension springs, wheel friction, steering, and drivetrain simulation.
|
|
2572
|
+
*
|
|
2573
|
+
* @module physics
|
|
2574
|
+
*/
|
|
2575
|
+
|
|
2576
|
+
interface WheelConfig {
|
|
2577
|
+
id: string;
|
|
2578
|
+
connectionPoint: IVector3;
|
|
2579
|
+
direction: IVector3;
|
|
2580
|
+
axle: IVector3;
|
|
2581
|
+
suspensionRestLength: number;
|
|
2582
|
+
suspensionStiffness: number;
|
|
2583
|
+
suspensionDamping: number;
|
|
2584
|
+
maxSuspensionTravel: number;
|
|
2585
|
+
wheelRadius: number;
|
|
2586
|
+
frictionSlip: number;
|
|
2587
|
+
isSteering: boolean;
|
|
2588
|
+
isDriving: boolean;
|
|
2589
|
+
rollInfluence: number;
|
|
2590
|
+
}
|
|
2591
|
+
interface VehicleDefinition {
|
|
2592
|
+
id: string;
|
|
2593
|
+
chassisMass: number;
|
|
2594
|
+
chassisSize: IVector3;
|
|
2595
|
+
wheels: WheelConfig[];
|
|
2596
|
+
maxSteerAngle: number;
|
|
2597
|
+
maxEngineForce: number;
|
|
2598
|
+
maxBrakeForce: number;
|
|
2599
|
+
}
|
|
2600
|
+
interface WheelState {
|
|
2601
|
+
config: WheelConfig;
|
|
2602
|
+
suspensionLength: number;
|
|
2603
|
+
suspensionForce: number;
|
|
2604
|
+
contactPoint: IVector3 | null;
|
|
2605
|
+
isGrounded: boolean;
|
|
2606
|
+
rotation: number;
|
|
2607
|
+
steerAngle: number;
|
|
2608
|
+
skidFactor: number;
|
|
2609
|
+
}
|
|
2610
|
+
interface VehicleState {
|
|
2611
|
+
id: string;
|
|
2612
|
+
definition: VehicleDefinition;
|
|
2613
|
+
position: IVector3;
|
|
2614
|
+
rotation: {
|
|
2615
|
+
x: number;
|
|
2616
|
+
y: number;
|
|
2617
|
+
z: number;
|
|
2618
|
+
w: number;
|
|
2619
|
+
};
|
|
2620
|
+
linearVelocity: IVector3;
|
|
2621
|
+
angularVelocity: IVector3;
|
|
2622
|
+
wheels: WheelState[];
|
|
2623
|
+
speed: number;
|
|
2624
|
+
engineForce: number;
|
|
2625
|
+
brakeForce: number;
|
|
2626
|
+
steerAngle: number;
|
|
2627
|
+
}
|
|
2628
|
+
declare function createDefaultCar(id: string): VehicleDefinition;
|
|
2629
|
+
declare function createTruck(id: string): VehicleDefinition;
|
|
2630
|
+
declare class VehicleSystem {
|
|
2631
|
+
private vehicles;
|
|
2632
|
+
/**
|
|
2633
|
+
* Create a vehicle from a definition at a given position.
|
|
2634
|
+
*/
|
|
2635
|
+
createVehicle(definition: VehicleDefinition, position: IVector3): VehicleState;
|
|
2636
|
+
/**
|
|
2637
|
+
* Update vehicle physics for one timestep.
|
|
2638
|
+
*/
|
|
2639
|
+
update(vehicleId: string, dt: number): VehicleState | null;
|
|
2640
|
+
setThrottle(vehicleId: string, throttle: number): void;
|
|
2641
|
+
setBrake(vehicleId: string, brake: number): void;
|
|
2642
|
+
setSteering(vehicleId: string, steering: number): void;
|
|
2643
|
+
getVehicle(vehicleId: string): VehicleState | undefined;
|
|
2644
|
+
removeVehicle(vehicleId: string): boolean;
|
|
2645
|
+
private getForwardVector;
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
/**
|
|
2649
|
+
* SpatialHash.ts
|
|
2650
|
+
*
|
|
2651
|
+
* Grid-based spatial hash for broad-phase collision detection:
|
|
2652
|
+
* insert/remove/query, cell management, and neighbor iteration.
|
|
2653
|
+
*
|
|
2654
|
+
* @module physics
|
|
2655
|
+
*/
|
|
2656
|
+
interface SpatialEntry {
|
|
2657
|
+
id: string;
|
|
2658
|
+
x: number;
|
|
2659
|
+
y: number;
|
|
2660
|
+
z: number;
|
|
2661
|
+
radius: number;
|
|
2662
|
+
}
|
|
2663
|
+
declare class SpatialHash {
|
|
2664
|
+
private cellSize;
|
|
2665
|
+
private cells;
|
|
2666
|
+
private entries;
|
|
2667
|
+
constructor(cellSize: number);
|
|
2668
|
+
insert(entry: SpatialEntry): void;
|
|
2669
|
+
remove(id: string): void;
|
|
2670
|
+
update(id: string, x: number, y: number, z: number): void;
|
|
2671
|
+
queryPoint(x: number, y: number, z: number): string[];
|
|
2672
|
+
queryRadius(x: number, y: number, z: number, radius: number): string[];
|
|
2673
|
+
getNearbyPairs(): Array<[string, string]>;
|
|
2674
|
+
private getCellsForEntry;
|
|
2675
|
+
private cellKey;
|
|
2676
|
+
getEntryCount(): number;
|
|
2677
|
+
getCellCount(): number;
|
|
2678
|
+
clear(): void;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
/**
|
|
2682
|
+
* Physics module
|
|
2683
|
+
*
|
|
2684
|
+
* Provides rigid body dynamics, collision detection, constraint solving,
|
|
2685
|
+
* and spatial queries for the HoloScript engine.
|
|
2686
|
+
*
|
|
2687
|
+
* @module physics
|
|
2688
|
+
*/
|
|
2689
|
+
|
|
2690
|
+
type index_AABB = AABB;
|
|
2691
|
+
type index_ActivationTriggerType = ActivationTriggerType;
|
|
2692
|
+
declare const index_ActivationTriggerType: typeof ActivationTriggerType;
|
|
2693
|
+
type index_ActivationTriggers = ActivationTriggers;
|
|
2694
|
+
type index_ActivationUpdateInput = ActivationUpdateInput;
|
|
2695
|
+
type index_AnimationTriggerConfig = AnimationTriggerConfig;
|
|
2696
|
+
declare const index_BodyType: typeof BodyType;
|
|
2697
|
+
type index_BoneDefinition = BoneDefinition;
|
|
2698
|
+
type index_BoundaryCoupling = BoundaryCoupling;
|
|
2699
|
+
declare const index_COLLISION_GROUPS: typeof COLLISION_GROUPS;
|
|
2700
|
+
type index_ClothConfig = ClothConfig;
|
|
2701
|
+
type index_ClothConstraint = ClothConstraint;
|
|
2702
|
+
type index_ClothParticle = ClothParticle;
|
|
2703
|
+
type index_ClothSim = ClothSim;
|
|
2704
|
+
declare const index_ClothSim: typeof ClothSim;
|
|
2705
|
+
type index_Collider = Collider;
|
|
2706
|
+
declare const index_CollisionShape: typeof CollisionShape;
|
|
2707
|
+
type index_CollisionTriggerConfig = CollisionTriggerConfig;
|
|
2708
|
+
declare const index_Constraint: typeof Constraint;
|
|
2709
|
+
type index_ConstraintSolver = ConstraintSolver;
|
|
2710
|
+
declare const index_ConstraintSolver: typeof ConstraintSolver;
|
|
2711
|
+
type index_ConstraintSolverConfig = ConstraintSolverConfig;
|
|
2712
|
+
declare const index_DEFAULT_ACTIVATION_CONFIG: typeof DEFAULT_ACTIVATION_CONFIG;
|
|
2713
|
+
declare const index_DEFAULT_INTENSITY_CURVE: typeof DEFAULT_INTENSITY_CURVE;
|
|
2714
|
+
declare const index_DEFAULT_LOCOMOTION_CONFIG: typeof DEFAULT_LOCOMOTION_CONFIG;
|
|
2715
|
+
type index_DeformConfig = DeformConfig;
|
|
2716
|
+
type index_DeformSpring = DeformSpring;
|
|
2717
|
+
type index_DeformVertex = DeformVertex;
|
|
2718
|
+
type index_DeformableMesh = DeformableMesh;
|
|
2719
|
+
declare const index_DeformableMesh: typeof DeformableMesh;
|
|
2720
|
+
type index_DistanceConstraint = DistanceConstraint;
|
|
2721
|
+
type index_FluidConfig = FluidConfig;
|
|
2722
|
+
type index_FluidParticle = FluidParticle;
|
|
2723
|
+
type index_FluidSim = FluidSim;
|
|
2724
|
+
declare const index_FluidSim: typeof FluidSim;
|
|
2725
|
+
type index_GrabConfig = GrabConfig;
|
|
2726
|
+
type index_GustConfig = GustConfig;
|
|
2727
|
+
declare const index_HUMANOID_PRESET: typeof HUMANOID_PRESET;
|
|
2728
|
+
declare const index_IBallConstraint: typeof IBallConstraint;
|
|
2729
|
+
declare const index_IBoxShape: typeof IBoxShape;
|
|
2730
|
+
declare const index_ICapsuleShape: typeof ICapsuleShape;
|
|
2731
|
+
declare const index_ICollisionEvent: typeof ICollisionEvent;
|
|
2732
|
+
declare const index_ICollisionFilter: typeof ICollisionFilter;
|
|
2733
|
+
declare const index_ICompoundShape: typeof ICompoundShape;
|
|
2734
|
+
declare const index_IConeConstraint: typeof IConeConstraint;
|
|
2735
|
+
declare const index_IConeShape: typeof IConeShape;
|
|
2736
|
+
declare const index_IConstraintColoring: typeof IConstraintColoring;
|
|
2737
|
+
declare const index_IConvexShape: typeof IConvexShape;
|
|
2738
|
+
declare const index_ICylinderShape: typeof ICylinderShape;
|
|
2739
|
+
declare const index_IDistanceConstraint: typeof IDistanceConstraint;
|
|
2740
|
+
declare const index_IFixedConstraint: typeof IFixedConstraint;
|
|
2741
|
+
declare const index_IGeneric6DOFConstraint: typeof IGeneric6DOFConstraint;
|
|
2742
|
+
declare const index_IHeightfieldShape: typeof IHeightfieldShape;
|
|
2743
|
+
declare const index_IHingeConstraint: typeof IHingeConstraint;
|
|
2744
|
+
declare const index_IMeshShape: typeof IMeshShape;
|
|
2745
|
+
declare const index_IOverlapResult: typeof IOverlapResult;
|
|
2746
|
+
declare const index_IPBDAttachmentConstraint: typeof IPBDAttachmentConstraint;
|
|
2747
|
+
declare const index_IPBDBendingConstraint: typeof IPBDBendingConstraint;
|
|
2748
|
+
declare const index_IPBDCollisionConstraint: typeof IPBDCollisionConstraint;
|
|
2749
|
+
declare const index_IPBDDistanceConstraint: typeof IPBDDistanceConstraint;
|
|
2750
|
+
declare const index_IPBDVolumeConstraint: typeof IPBDVolumeConstraint;
|
|
2751
|
+
declare const index_IParticleAttributes: typeof IParticleAttributes;
|
|
2752
|
+
declare const index_IPhysicsMaterial: typeof IPhysicsMaterial;
|
|
2753
|
+
declare const index_IPhysicsWorld: typeof IPhysicsWorld;
|
|
2754
|
+
declare const index_IPhysicsWorldConfig: typeof IPhysicsWorldConfig;
|
|
2755
|
+
declare const index_IQuaternion: typeof IQuaternion;
|
|
2756
|
+
declare const index_IRay: typeof IRay;
|
|
2757
|
+
declare const index_IRaycastHit: typeof IRaycastHit;
|
|
2758
|
+
declare const index_IRaycastOptions: typeof IRaycastOptions;
|
|
2759
|
+
declare const index_IRigidBodyConfig: typeof IRigidBodyConfig;
|
|
2760
|
+
declare const index_IRigidBodyState: typeof IRigidBodyState;
|
|
2761
|
+
declare const index_ISDFCollider: typeof ISDFCollider;
|
|
2762
|
+
declare const index_ISliderConstraint: typeof ISliderConstraint;
|
|
2763
|
+
declare const index_ISoftBodyConfig: typeof ISoftBodyConfig;
|
|
2764
|
+
declare const index_ISoftBodyState: typeof ISoftBodyState;
|
|
2765
|
+
declare const index_ISpatialHashGrid: typeof ISpatialHashGrid;
|
|
2766
|
+
declare const index_ISphereShape: typeof ISphereShape;
|
|
2767
|
+
declare const index_ISpringConstraint: typeof ISpringConstraint;
|
|
2768
|
+
declare const index_ITransform: typeof ITransform;
|
|
2769
|
+
declare const index_ITriggerEvent: typeof ITriggerEvent;
|
|
2770
|
+
declare const index_IVector3: typeof IVector3;
|
|
2771
|
+
type index_IntensityCurvePoint = IntensityCurvePoint;
|
|
2772
|
+
type index_IslandDetector = IslandDetector;
|
|
2773
|
+
declare const index_IslandDetector: typeof IslandDetector;
|
|
2774
|
+
type index_JointDef = JointDef;
|
|
2775
|
+
type index_JointState = JointState;
|
|
2776
|
+
type index_JointSystem = JointSystem;
|
|
2777
|
+
declare const index_JointSystem: typeof JointSystem;
|
|
2778
|
+
type index_JointType = JointType;
|
|
2779
|
+
type index_LocomotionConfig = LocomotionConfig;
|
|
2780
|
+
type index_LoopTimingConfig = LoopTimingConfig;
|
|
2781
|
+
type index_MLSMPMConfig = MLSMPMConfig;
|
|
2782
|
+
type index_MLSMPMFluid = MLSMPMFluid;
|
|
2783
|
+
declare const index_MLSMPMFluid: typeof MLSMPMFluid;
|
|
2784
|
+
type index_MLSMPMStats = MLSMPMStats;
|
|
2785
|
+
declare const index_PBDConstraint: typeof PBDConstraint;
|
|
2786
|
+
declare const index_PBDConstraintType: typeof PBDConstraintType;
|
|
2787
|
+
type index_PBDSolverCPU = PBDSolverCPU;
|
|
2788
|
+
declare const index_PBDSolverCPU: typeof PBDSolverCPU;
|
|
2789
|
+
declare const index_PBD_ATTACHMENT_SHADER: typeof PBD_ATTACHMENT_SHADER;
|
|
2790
|
+
declare const index_PBD_BENDING_SHADER: typeof PBD_BENDING_SHADER;
|
|
2791
|
+
declare const index_PBD_COLLISION_SHADER: typeof PBD_COLLISION_SHADER;
|
|
2792
|
+
declare const index_PBD_DISTANCE_SHADER: typeof PBD_DISTANCE_SHADER;
|
|
2793
|
+
declare const index_PBD_FINALIZE_SHADER: typeof PBD_FINALIZE_SHADER;
|
|
2794
|
+
declare const index_PBD_HASH_BUILD_SHADER: typeof PBD_HASH_BUILD_SHADER;
|
|
2795
|
+
declare const index_PBD_NORMALIZE_SHADER: typeof PBD_NORMALIZE_SHADER;
|
|
2796
|
+
declare const index_PBD_NORMALS_SHADER: typeof PBD_NORMALS_SHADER;
|
|
2797
|
+
declare const index_PBD_PREDICT_SHADER: typeof PBD_PREDICT_SHADER;
|
|
2798
|
+
declare const index_PBD_SELF_COLLISION_SHADER: typeof PBD_SELF_COLLISION_SHADER;
|
|
2799
|
+
declare const index_PBD_VELOCITY_SHADER: typeof PBD_VELOCITY_SHADER;
|
|
2800
|
+
declare const index_PBD_VOLUME_SHADER: typeof PBD_VOLUME_SHADER;
|
|
2801
|
+
declare const index_PHYSICS_DEFAULTS: typeof PHYSICS_DEFAULTS;
|
|
2802
|
+
type index_PIDArithmetic<T> = PIDArithmetic<T>;
|
|
2803
|
+
type index_PIDController<T> = PIDController<T>;
|
|
2804
|
+
declare const index_PIDController: typeof PIDController;
|
|
2805
|
+
type index_PIDControllerConfig<T> = PIDControllerConfig<T>;
|
|
2806
|
+
type index_PIDControllerState<T> = PIDControllerState<T>;
|
|
2807
|
+
type index_PIDControllerTraitConfig = PIDControllerTraitConfig;
|
|
2808
|
+
type index_PIDGains = PIDGains;
|
|
2809
|
+
type index_Particle = Particle;
|
|
2810
|
+
type index_ParticleRange = ParticleRange;
|
|
2811
|
+
declare const index_ParticleType: typeof ParticleType;
|
|
2812
|
+
type index_PhysicsActivationConfig = PhysicsActivationConfig;
|
|
2813
|
+
type index_PhysicsActivationController = PhysicsActivationController;
|
|
2814
|
+
declare const index_PhysicsActivationController: typeof PhysicsActivationController;
|
|
2815
|
+
type index_PhysicsActivationState = PhysicsActivationState;
|
|
2816
|
+
declare const index_PhysicsActivationState: typeof PhysicsActivationState;
|
|
2817
|
+
type index_PhysicsSyncConfig = PhysicsSyncConfig;
|
|
2818
|
+
type index_PhysicsSyncReceiver = PhysicsSyncReceiver;
|
|
2819
|
+
declare const index_PhysicsSyncReceiver: typeof PhysicsSyncReceiver;
|
|
2820
|
+
type index_PhysicsSyncSender = PhysicsSyncSender;
|
|
2821
|
+
declare const index_PhysicsSyncSender: typeof PhysicsSyncSender;
|
|
2822
|
+
type index_PhysicsWorldImpl = PhysicsWorldImpl;
|
|
2823
|
+
declare const index_PhysicsWorldImpl: typeof PhysicsWorldImpl;
|
|
2824
|
+
type index_Plane = Plane;
|
|
2825
|
+
declare const index_QUADRUPED_PRESET: typeof QUADRUPED_PRESET;
|
|
2826
|
+
type index_RagdollBone = RagdollBone;
|
|
2827
|
+
type index_RagdollConfig = RagdollConfig;
|
|
2828
|
+
type index_RagdollController = RagdollController;
|
|
2829
|
+
declare const index_RagdollController: typeof RagdollController;
|
|
2830
|
+
type index_RagdollDefinition = RagdollDefinition;
|
|
2831
|
+
type index_RagdollInstance = RagdollInstance;
|
|
2832
|
+
type index_RagdollState = RagdollState;
|
|
2833
|
+
type index_RagdollSystem = RagdollSystem;
|
|
2834
|
+
declare const index_RagdollSystem: typeof RagdollSystem;
|
|
2835
|
+
type index_Ray = Ray;
|
|
2836
|
+
type index_RayHit = RayHit;
|
|
2837
|
+
type index_RaycastSystem = RaycastSystem;
|
|
2838
|
+
declare const index_RaycastSystem: typeof RaycastSystem;
|
|
2839
|
+
type index_RigidBody = RigidBody;
|
|
2840
|
+
declare const index_RigidBody: typeof RigidBody;
|
|
2841
|
+
type index_RopeAttachment = RopeAttachment;
|
|
2842
|
+
type index_RopeConfig = RopeConfig;
|
|
2843
|
+
type index_RopeNode = RopeNode;
|
|
2844
|
+
type index_RopeSystem = RopeSystem;
|
|
2845
|
+
declare const index_RopeSystem: typeof RopeSystem;
|
|
2846
|
+
declare const index_SOFT_BODY_PRESETS: typeof SOFT_BODY_PRESETS;
|
|
2847
|
+
declare const index_ScalarArithmetic: typeof ScalarArithmetic;
|
|
2848
|
+
type index_SoftBodyAdapter = SoftBodyAdapter;
|
|
2849
|
+
declare const index_SoftBodyAdapter: typeof SoftBodyAdapter;
|
|
2850
|
+
type index_SoftBodyGrabController = SoftBodyGrabController;
|
|
2851
|
+
declare const index_SoftBodyGrabController: typeof SoftBodyGrabController;
|
|
2852
|
+
declare const index_SoftBodyPreset: typeof SoftBodyPreset;
|
|
2853
|
+
type index_SoftBodySolver = SoftBodySolver;
|
|
2854
|
+
declare const index_SoftBodySolver: typeof SoftBodySolver;
|
|
2855
|
+
type index_SpatialEntry = SpatialEntry;
|
|
2856
|
+
type index_SpatialHash = SpatialHash;
|
|
2857
|
+
declare const index_SpatialHash: typeof SpatialHash;
|
|
2858
|
+
type index_Sphere = Sphere;
|
|
2859
|
+
type index_SyncPacketHeader = SyncPacketHeader;
|
|
2860
|
+
type index_SyncStats = SyncStats;
|
|
2861
|
+
type index_ThresholdTriggerConfig = ThresholdTriggerConfig;
|
|
2862
|
+
type index_TriggerCallback = TriggerCallback;
|
|
2863
|
+
type index_TriggerEvent = TriggerEvent;
|
|
2864
|
+
type index_TriggerShape = TriggerShape;
|
|
2865
|
+
type index_TriggerZoneConfig = TriggerZoneConfig;
|
|
2866
|
+
type index_TriggerZoneSystem = TriggerZoneSystem;
|
|
2867
|
+
declare const index_TriggerZoneSystem: typeof TriggerZoneSystem;
|
|
2868
|
+
type index_UnifiedBufferStats = UnifiedBufferStats;
|
|
2869
|
+
type index_UnifiedParticleBuffer = UnifiedParticleBuffer;
|
|
2870
|
+
declare const index_UnifiedParticleBuffer: typeof UnifiedParticleBuffer;
|
|
2871
|
+
type index_VRPhysicsBridge = VRPhysicsBridge;
|
|
2872
|
+
declare const index_VRPhysicsBridge: typeof VRPhysicsBridge;
|
|
2873
|
+
declare const index_Vector3Arithmetic: typeof Vector3Arithmetic;
|
|
2874
|
+
type index_VehicleDefinition = VehicleDefinition;
|
|
2875
|
+
type index_VehicleState = VehicleState;
|
|
2876
|
+
type index_VehicleSystem = VehicleSystem;
|
|
2877
|
+
declare const index_VehicleSystem: typeof VehicleSystem;
|
|
2878
|
+
type index_VelocityRingBuffer = VelocityRingBuffer;
|
|
2879
|
+
declare const index_VelocityRingBuffer: typeof VelocityRingBuffer;
|
|
2880
|
+
type index_VelocitySmoother = VelocitySmoother;
|
|
2881
|
+
declare const index_VelocitySmoother: typeof VelocitySmoother;
|
|
2882
|
+
type index_WheelConfig = WheelConfig;
|
|
2883
|
+
type index_WheelState = WheelState;
|
|
2884
|
+
type index_WindZone = WindZone;
|
|
2885
|
+
type index_WindZoneManager = WindZoneManager;
|
|
2886
|
+
declare const index_WindZoneManager: typeof WindZoneManager;
|
|
2887
|
+
type index_WindZoneType = WindZoneType;
|
|
2888
|
+
declare const index_WindZoneType: typeof WindZoneType;
|
|
2889
|
+
declare const index_boxShape: typeof boxShape;
|
|
2890
|
+
declare const index_capsuleShape: typeof capsuleShape;
|
|
2891
|
+
declare const index_colorConstraints: typeof colorConstraints;
|
|
2892
|
+
declare const index_computeRestLengths: typeof computeRestLengths;
|
|
2893
|
+
declare const index_computeSelfWind: typeof computeSelfWind;
|
|
2894
|
+
declare const index_createDefaultCar: typeof createDefaultCar;
|
|
2895
|
+
declare const index_createPBDSolver: typeof createPBDSolver;
|
|
2896
|
+
declare const index_createPIDControllerTrait: typeof createPIDControllerTrait;
|
|
2897
|
+
declare const index_createPhysicsWorld: typeof createPhysicsWorld;
|
|
2898
|
+
declare const index_createScalarPIDController: typeof createScalarPIDController;
|
|
2899
|
+
declare const index_createTruck: typeof createTruck;
|
|
2900
|
+
declare const index_createVector3PIDController: typeof createVector3PIDController;
|
|
2901
|
+
declare const index_defaultMaterial: typeof defaultMaterial;
|
|
2902
|
+
declare const index_defaultPIDConfig: typeof defaultPIDConfig;
|
|
2903
|
+
declare const index_defaultTransform: typeof defaultTransform;
|
|
2904
|
+
declare const index_dynamicBody: typeof dynamicBody;
|
|
2905
|
+
declare const index_evaluateIntensityCurve: typeof evaluateIntensityCurve;
|
|
2906
|
+
declare const index_extractBendingPairs: typeof extractBendingPairs;
|
|
2907
|
+
declare const index_extractEdges: typeof extractEdges;
|
|
2908
|
+
declare const index_generateSDF: typeof generateSDF;
|
|
2909
|
+
declare const index_generateTetrahedra: typeof generateTetrahedra;
|
|
2910
|
+
declare const index_identityQuaternion: typeof identityQuaternion;
|
|
2911
|
+
declare const index_kinematicBody: typeof kinematicBody;
|
|
2912
|
+
declare const index_parsePacketHeader: typeof parsePacketHeader;
|
|
2913
|
+
declare const index_sphereShape: typeof sphereShape;
|
|
2914
|
+
declare const index_staticBody: typeof staticBody;
|
|
2915
|
+
declare const index_validateBodyConfig: typeof validateBodyConfig;
|
|
2916
|
+
declare const index_zeroVector: typeof zeroVector;
|
|
2917
|
+
declare namespace index {
|
|
2918
|
+
export { type index_AABB as AABB, index_ActivationTriggerType as ActivationTriggerType, type index_ActivationTriggers as ActivationTriggers, type index_ActivationUpdateInput as ActivationUpdateInput, type index_AnimationTriggerConfig as AnimationTriggerConfig, index_BodyType as BodyType, type index_BoneDefinition as BoneDefinition, type index_BoundaryCoupling as BoundaryCoupling, index_COLLISION_GROUPS as COLLISION_GROUPS, type index_ClothConfig as ClothConfig, type index_ClothConstraint as ClothConstraint, type index_ClothParticle as ClothParticle, index_ClothSim as ClothSim, type index_Collider as Collider, index_CollisionShape as CollisionShape, type index_CollisionTriggerConfig as CollisionTriggerConfig, index_Constraint as Constraint, index_ConstraintSolver as ConstraintSolver, type index_ConstraintSolverConfig as ConstraintSolverConfig, index_DEFAULT_ACTIVATION_CONFIG as DEFAULT_ACTIVATION_CONFIG, index_DEFAULT_INTENSITY_CURVE as DEFAULT_INTENSITY_CURVE, index_DEFAULT_LOCOMOTION_CONFIG as DEFAULT_LOCOMOTION_CONFIG, type index_DeformConfig as DeformConfig, type index_DeformSpring as DeformSpring, type index_DeformVertex as DeformVertex, index_DeformableMesh as DeformableMesh, type index_DistanceConstraint as DistanceConstraint, type index_FluidConfig as FluidConfig, type index_FluidParticle as FluidParticle, index_FluidSim as FluidSim, type index_GrabConfig as GrabConfig, type index_GustConfig as GustConfig, index_HUMANOID_PRESET as HUMANOID_PRESET, index_IBallConstraint as IBallConstraint, index_IBoxShape as IBoxShape, index_ICapsuleShape as ICapsuleShape, index_ICollisionEvent as ICollisionEvent, index_ICollisionFilter as ICollisionFilter, index_ICompoundShape as ICompoundShape, index_IConeConstraint as IConeConstraint, index_IConeShape as IConeShape, index_IConstraintColoring as IConstraintColoring, index_IConvexShape as IConvexShape, index_ICylinderShape as ICylinderShape, index_IDistanceConstraint as IDistanceConstraint, index_IFixedConstraint as IFixedConstraint, index_IGeneric6DOFConstraint as IGeneric6DOFConstraint, index_IHeightfieldShape as IHeightfieldShape, index_IHingeConstraint as IHingeConstraint, index_IMeshShape as IMeshShape, index_IOverlapResult as IOverlapResult, index_IPBDAttachmentConstraint as IPBDAttachmentConstraint, index_IPBDBendingConstraint as IPBDBendingConstraint, index_IPBDCollisionConstraint as IPBDCollisionConstraint, index_IPBDDistanceConstraint as IPBDDistanceConstraint, index_IPBDVolumeConstraint as IPBDVolumeConstraint, index_IParticleAttributes as IParticleAttributes, index_IPhysicsMaterial as IPhysicsMaterial, index_IPhysicsWorld as IPhysicsWorld, index_IPhysicsWorldConfig as IPhysicsWorldConfig, index_IQuaternion as IQuaternion, index_IRay as IRay, index_IRaycastHit as IRaycastHit, index_IRaycastOptions as IRaycastOptions, index_IRigidBodyConfig as IRigidBodyConfig, index_IRigidBodyState as IRigidBodyState, index_ISDFCollider as ISDFCollider, index_ISliderConstraint as ISliderConstraint, index_ISoftBodyConfig as ISoftBodyConfig, index_ISoftBodyState as ISoftBodyState, index_ISpatialHashGrid as ISpatialHashGrid, index_ISphereShape as ISphereShape, index_ISpringConstraint as ISpringConstraint, index_ITransform as ITransform, index_ITriggerEvent as ITriggerEvent, index_IVector3 as IVector3, type index_IntensityCurvePoint as IntensityCurvePoint, index_IslandDetector as IslandDetector, type index_JointDef as JointDef, type index_JointState as JointState, index_JointSystem as JointSystem, type index_JointType as JointType, type index_LocomotionConfig as LocomotionConfig, type index_LoopTimingConfig as LoopTimingConfig, type index_MLSMPMConfig as MLSMPMConfig, index_MLSMPMFluid as MLSMPMFluid, type index_MLSMPMStats as MLSMPMStats, index_PBDConstraint as PBDConstraint, index_PBDConstraintType as PBDConstraintType, index_PBDSolverCPU as PBDSolverCPU, index_PBD_ATTACHMENT_SHADER as PBD_ATTACHMENT_SHADER, index_PBD_BENDING_SHADER as PBD_BENDING_SHADER, index_PBD_COLLISION_SHADER as PBD_COLLISION_SHADER, index_PBD_DISTANCE_SHADER as PBD_DISTANCE_SHADER, index_PBD_FINALIZE_SHADER as PBD_FINALIZE_SHADER, index_PBD_HASH_BUILD_SHADER as PBD_HASH_BUILD_SHADER, index_PBD_NORMALIZE_SHADER as PBD_NORMALIZE_SHADER, index_PBD_NORMALS_SHADER as PBD_NORMALS_SHADER, index_PBD_PREDICT_SHADER as PBD_PREDICT_SHADER, index_PBD_SELF_COLLISION_SHADER as PBD_SELF_COLLISION_SHADER, index_PBD_VELOCITY_SHADER as PBD_VELOCITY_SHADER, index_PBD_VOLUME_SHADER as PBD_VOLUME_SHADER, index_PHYSICS_DEFAULTS as PHYSICS_DEFAULTS, type index_PIDArithmetic as PIDArithmetic, index_PIDController as PIDController, type index_PIDControllerConfig as PIDControllerConfig, type index_PIDControllerState as PIDControllerState, type index_PIDControllerTraitConfig as PIDControllerTraitConfig, type index_PIDGains as PIDGains, type index_Particle as Particle, type index_ParticleRange as ParticleRange, index_ParticleType as ParticleType, type index_PhysicsActivationConfig as PhysicsActivationConfig, index_PhysicsActivationController as PhysicsActivationController, index_PhysicsActivationState as PhysicsActivationState, type index_PhysicsSyncConfig as PhysicsSyncConfig, index_PhysicsSyncReceiver as PhysicsSyncReceiver, index_PhysicsSyncSender as PhysicsSyncSender, index_PhysicsWorldImpl as PhysicsWorldImpl, type index_Plane as Plane, index_QUADRUPED_PRESET as QUADRUPED_PRESET, type index_RagdollBone as RagdollBone, type index_RagdollConfig as RagdollConfig, index_RagdollController as RagdollController, type index_RagdollDefinition as RagdollDefinition, type index_RagdollInstance as RagdollInstance, type index_RagdollState as RagdollState, index_RagdollSystem as RagdollSystem, type index_Ray as Ray, type index_RayHit as RayHit, index_RaycastSystem as RaycastSystem, index_RigidBody as RigidBody, type index_RopeAttachment as RopeAttachment, type index_RopeConfig as RopeConfig, type index_RopeNode as RopeNode, index_RopeSystem as RopeSystem, index_SOFT_BODY_PRESETS as SOFT_BODY_PRESETS, index_ScalarArithmetic as ScalarArithmetic, index_SoftBodyAdapter as SoftBodyAdapter, index_SoftBodyGrabController as SoftBodyGrabController, index_SoftBodyPreset as SoftBodyPreset, index_SoftBodySolver as SoftBodySolver, type index_SpatialEntry as SpatialEntry, index_SpatialHash as SpatialHash, type index_Sphere as Sphere, type index_SyncPacketHeader as SyncPacketHeader, type index_SyncStats as SyncStats, type index_ThresholdTriggerConfig as ThresholdTriggerConfig, type index_TriggerCallback as TriggerCallback, type index_TriggerEvent as TriggerEvent, type index_TriggerShape as TriggerShape, type index_TriggerZoneConfig as TriggerZoneConfig, index_TriggerZoneSystem as TriggerZoneSystem, type index_UnifiedBufferStats as UnifiedBufferStats, index_UnifiedParticleBuffer as UnifiedParticleBuffer, index_VRPhysicsBridge as VRPhysicsBridge, index_Vector3Arithmetic as Vector3Arithmetic, type index_VehicleDefinition as VehicleDefinition, type index_VehicleState as VehicleState, index_VehicleSystem as VehicleSystem, index_VelocityRingBuffer as VelocityRingBuffer, index_VelocitySmoother as VelocitySmoother, type index_WheelConfig as WheelConfig, type index_WheelState as WheelState, type index_WindZone as WindZone, index_WindZoneManager as WindZoneManager, index_WindZoneType as WindZoneType, index_boxShape as boxShape, index_capsuleShape as capsuleShape, index_colorConstraints as colorConstraints, index_computeRestLengths as computeRestLengths, index_computeSelfWind as computeSelfWind, index_createDefaultCar as createDefaultCar, index_createPBDSolver as createPBDSolver, index_createPIDControllerTrait as createPIDControllerTrait, index_createPhysicsWorld as createPhysicsWorld, index_createScalarPIDController as createScalarPIDController, index_createTruck as createTruck, index_createVector3PIDController as createVector3PIDController, index_defaultMaterial as defaultMaterial, index_defaultPIDConfig as defaultPIDConfig, index_defaultTransform as defaultTransform, index_dynamicBody as dynamicBody, index_evaluateIntensityCurve as evaluateIntensityCurve, index_extractBendingPairs as extractBendingPairs, index_extractEdges as extractEdges, index_generateSDF as generateSDF, index_generateTetrahedra as generateTetrahedra, index_identityQuaternion as identityQuaternion, index_kinematicBody as kinematicBody, index_parsePacketHeader as parsePacketHeader, index_sphereShape as sphereShape, index_staticBody as staticBody, index_validateBodyConfig as validateBodyConfig, index_zeroVector as zeroVector };
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
export { PBD_VOLUME_SHADER as $, type AABB as A, type BoneDefinition as B, type ClothConfig as C, DEFAULT_ACTIVATION_CONFIG as D, type JointType as E, type FluidConfig as F, type GrabConfig as G, HUMANOID_PRESET as H, type IntensityCurvePoint as I, type JointDef as J, type LoopTimingConfig as K, type LocomotionConfig as L, type MLSMPMConfig as M, MLSMPMFluid as N, type MLSMPMStats as O, PBDSolverCPU as P, PBD_ATTACHMENT_SHADER as Q, PBD_BENDING_SHADER as R, PBD_COLLISION_SHADER as S, PBD_DISTANCE_SHADER as T, PBD_FINALIZE_SHADER as U, PBD_HASH_BUILD_SHADER as V, PBD_NORMALIZE_SHADER as W, PBD_NORMALS_SHADER as X, PBD_PREDICT_SHADER as Y, PBD_SELF_COLLISION_SHADER as Z, PBD_VELOCITY_SHADER as _, ActivationTriggerType as a, computeSelfWind as a$, type PIDArithmetic as a0, PIDController as a1, type PIDControllerConfig as a2, type PIDControllerState as a3, type PIDControllerTraitConfig as a4, type PIDGains as a5, type Particle as a6, type ParticleRange as a7, type PhysicsActivationConfig as a8, PhysicsActivationController as a9, type SpatialEntry as aA, SpatialHash as aB, type Sphere as aC, type SyncPacketHeader as aD, type SyncStats as aE, type ThresholdTriggerConfig as aF, type TriggerCallback as aG, type TriggerEvent as aH, type TriggerShape as aI, type TriggerZoneConfig as aJ, TriggerZoneSystem as aK, type UnifiedBufferStats as aL, UnifiedParticleBuffer as aM, VRPhysicsBridge as aN, Vector3Arithmetic as aO, type VehicleDefinition as aP, type VehicleState as aQ, VehicleSystem as aR, VelocityRingBuffer as aS, VelocitySmoother as aT, type WheelConfig as aU, type WheelState as aV, type WindZone as aW, WindZoneManager as aX, WindZoneType as aY, colorConstraints as aZ, computeRestLengths as a_, PhysicsActivationState as aa, type PhysicsSyncConfig as ab, PhysicsSyncReceiver as ac, PhysicsSyncSender as ad, PhysicsWorldImpl as ae, type Plane as af, QUADRUPED_PRESET as ag, type RagdollBone as ah, type RagdollConfig as ai, RagdollController as aj, type RagdollDefinition as ak, type RagdollInstance as al, type RagdollState as am, RagdollSystem as an, type Ray as ao, type RayHit as ap, RaycastSystem as aq, RigidBody as ar, type RopeAttachment as as, type RopeConfig as at, type RopeNode as au, RopeSystem as av, ScalarArithmetic as aw, SoftBodyAdapter as ax, SoftBodyGrabController as ay, SoftBodySolver as az, type ActivationTriggers as b, createDefaultCar as b0, createPBDSolver as b1, createPIDControllerTrait as b2, createPhysicsWorld as b3, createScalarPIDController as b4, createTruck as b5, createVector3PIDController as b6, defaultPIDConfig as b7, evaluateIntensityCurve as b8, extractBendingPairs as b9, extractEdges as ba, generateSDF as bb, generateTetrahedra as bc, parsePacketHeader as bd, type ActivationUpdateInput as c, type AnimationTriggerConfig as d, type BoundaryCoupling as e, type ClothConstraint as f, type ClothParticle as g, ClothSim as h, index as i, type Collider as j, type CollisionTriggerConfig as k, ConstraintSolver as l, type ConstraintSolverConfig as m, DEFAULT_INTENSITY_CURVE as n, DEFAULT_LOCOMOTION_CONFIG as o, type DeformConfig as p, type DeformSpring as q, type DeformVertex as r, DeformableMesh as s, type DistanceConstraint as t, type FluidParticle as u, FluidSim as v, type GustConfig as w, IslandDetector as x, type JointState as y, JointSystem as z };
|