@woosh/meep-engine 2.140.0 → 2.142.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/geom/3d/quaternion/quat3_multiply.d.ts +21 -0
- package/src/core/geom/3d/quaternion/quat3_multiply.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_multiply.js +25 -0
- package/src/engine/control/first-person/prototype_first_person_controller.js +5 -0
- package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.d.ts.map +1 -1
- package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +67 -42
- package/src/engine/graphics/render/buffer/simple-fx/ao/SAOShader.d.ts +12 -22
- package/src/engine/graphics/render/buffer/simple-fx/ao/SAOShader.d.ts.map +1 -1
- package/src/engine/graphics/render/buffer/simple-fx/ao/SAOShader.js +340 -186
- package/src/engine/graphics/render/buffer/simple-fx/ao/SAOUpscaleShader.d.ts +44 -0
- package/src/engine/graphics/render/buffer/simple-fx/ao/SAOUpscaleShader.d.ts.map +1 -0
- package/src/engine/graphics/render/buffer/simple-fx/ao/SAOUpscaleShader.js +151 -0
- package/src/engine/graphics/render/buffer/simple-fx/ao/generateHilbertNoiseTexture.d.ts +14 -0
- package/src/engine/graphics/render/buffer/simple-fx/ao/generateHilbertNoiseTexture.d.ts.map +1 -0
- package/src/engine/graphics/render/buffer/simple-fx/ao/generateHilbertNoiseTexture.js +78 -0
- package/src/engine/physics/PLAN.md +705 -461
- package/src/engine/physics/REVIEW_002.md +151 -0
- package/src/engine/physics/REVIEW_003.md +166 -0
- package/src/engine/physics/constraint/DofMode.d.ts +28 -0
- package/src/engine/physics/constraint/DofMode.d.ts.map +1 -0
- package/src/engine/physics/constraint/DofMode.js +35 -0
- package/src/engine/physics/constraint/solve_constraints.d.ts +38 -0
- package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -0
- package/src/engine/physics/constraint/solve_constraints.js +673 -0
- package/src/engine/physics/ecs/Joint.d.ts +294 -0
- package/src/engine/physics/ecs/Joint.d.ts.map +1 -0
- package/src/engine/physics/ecs/Joint.js +402 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +52 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +126 -4
- package/src/engine/physics/fluid/FluidField.d.ts +14 -10
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +14 -10
- package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidSimulator.js +0 -1
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +17 -10
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +18 -11
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +13 -10
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +18 -13
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +4 -3
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +15 -11
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +24 -22
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +26 -22
- package/src/engine/physics/island/IslandBuilder.d.ts +4 -1
- package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
- package/src/engine/physics/island/IslandBuilder.js +33 -16
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_box_manifold.js +27 -1
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts +33 -0
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +75 -0
- package/src/engine/physics/narrowphase/ray_shapes.d.ts +66 -0
- package/src/engine/physics/narrowphase/ray_shapes.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/ray_shapes.js +187 -0
- package/src/engine/physics/narrowphase/refine_ray_concave.d.ts +16 -0
- package/src/engine/physics/narrowphase/refine_ray_concave.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/refine_ray_concave.js +145 -0
- package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +39 -0
- package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/refine_ray_hit.js +78 -0
- package/src/engine/physics/queries/raycast.d.ts +11 -9
- package/src/engine/physics/queries/raycast.d.ts.map +1 -1
- package/src/engine/physics/queries/raycast.js +108 -159
- package/src/engine/physics/solver/solve_contacts.d.ts +28 -0
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +169 -1
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts +114 -0
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -0
- package/src/engine/physics/vehicle/RaycastVehicle.js +333 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel for {@link Joint#_jointId} before the joint is linked into a
|
|
3
|
+
* {@link PhysicsSystem}.
|
|
4
|
+
* @type {number}
|
|
5
|
+
*/
|
|
6
|
+
export const JOINT_UNALLOCATED: number;
|
|
7
|
+
/**
|
|
8
|
+
* `entityB` value meaning "the world" — body A is constrained to a fixed
|
|
9
|
+
* world anchor rather than to a second body.
|
|
10
|
+
* @type {number}
|
|
11
|
+
*/
|
|
12
|
+
export const JOINT_WORLD: number;
|
|
13
|
+
/**
|
|
14
|
+
* A configurable 6-DOF constraint between two bodies (or a body and the
|
|
15
|
+
* world). Connects body A's anchor frame to body B's; each of the 6 relative
|
|
16
|
+
* degrees of freedom (3 linear, 3 angular) is independently
|
|
17
|
+
* locked / free / limited / springy / motorised ({@link DofMode}). One
|
|
18
|
+
* constraint type expresses the whole joint taxonomy — see DofMode.
|
|
19
|
+
*
|
|
20
|
+
* The default configuration is a **ball-socket** (point-to-point): the three
|
|
21
|
+
* linear DOFs LOCKED (the two anchor points are held coincident), the three
|
|
22
|
+
* angular DOFs FREE. That alone gives chains, ropes, and pendulums.
|
|
23
|
+
*
|
|
24
|
+
* Anchors live in body-local frames. When `entityB === JOINT_WORLD`,
|
|
25
|
+
* `localAnchorB` is interpreted as a fixed **world** point instead of a
|
|
26
|
+
* local anchor on a second body.
|
|
27
|
+
*
|
|
28
|
+
* Solver state ({@link dofImpulse}, the `_*` fields) is owned by the
|
|
29
|
+
* PhysicsSystem; user code must not write it.
|
|
30
|
+
*
|
|
31
|
+
* @author Alex Goldring
|
|
32
|
+
* @copyright Company Named Limited (c) 2026
|
|
33
|
+
*/
|
|
34
|
+
export class Joint {
|
|
35
|
+
/**
|
|
36
|
+
* Entity owning body A (the constraint's first body — always a real body).
|
|
37
|
+
* @type {number}
|
|
38
|
+
*/
|
|
39
|
+
entityA: number;
|
|
40
|
+
/**
|
|
41
|
+
* Entity owning body B, or {@link JOINT_WORLD} to anchor A to the world.
|
|
42
|
+
* @type {number}
|
|
43
|
+
*/
|
|
44
|
+
entityB: number;
|
|
45
|
+
/**
|
|
46
|
+
* Anchor point on body A, in A's local frame.
|
|
47
|
+
* @readonly
|
|
48
|
+
* @type {Vector3}
|
|
49
|
+
*/
|
|
50
|
+
readonly localAnchorA: Vector3;
|
|
51
|
+
/**
|
|
52
|
+
* Anchor point on body B in B's local frame — or, when
|
|
53
|
+
* `entityB === JOINT_WORLD`, a fixed world-space anchor point.
|
|
54
|
+
* @readonly
|
|
55
|
+
* @type {Vector3}
|
|
56
|
+
*/
|
|
57
|
+
readonly localAnchorB: Vector3;
|
|
58
|
+
/**
|
|
59
|
+
* Orientation of the joint's reference frame on body A, in A's local
|
|
60
|
+
* space (a unit quaternion; identity = the joint frame is the body
|
|
61
|
+
* frame). The 3 linear and 3 angular DOFs are expressed in this frame:
|
|
62
|
+
* locked/limited/etc. axes are the frame's axes, not world axes. For a
|
|
63
|
+
* hinge, the free angular axis is one of these frame axes — orient the
|
|
64
|
+
* frame so that axis is the hinge axis.
|
|
65
|
+
* @readonly
|
|
66
|
+
* @type {Quaternion}
|
|
67
|
+
*/
|
|
68
|
+
readonly localBasisA: Quaternion;
|
|
69
|
+
/**
|
|
70
|
+
* Orientation of the joint's reference frame on body B, in B's local
|
|
71
|
+
* space. At rest a fully-locked joint holds frame B aligned to frame A.
|
|
72
|
+
* When `entityB === JOINT_WORLD`, the world frame is treated as identity
|
|
73
|
+
* (angular locks hold A's frame to world axes).
|
|
74
|
+
* @readonly
|
|
75
|
+
* @type {Quaternion}
|
|
76
|
+
*/
|
|
77
|
+
readonly localBasisB: Quaternion;
|
|
78
|
+
/**
|
|
79
|
+
* Per-DOF mode, 6 entries: `[lin x, lin y, lin z, ang x, ang y, ang z]`.
|
|
80
|
+
* Default = ball-socket (linear locked, angular free).
|
|
81
|
+
* @readonly
|
|
82
|
+
* @type {Uint8Array}
|
|
83
|
+
*/
|
|
84
|
+
readonly dofMode: Uint8Array;
|
|
85
|
+
/**
|
|
86
|
+
* How the three angular DOF positions are measured. `false` (default) uses
|
|
87
|
+
* the per-axis small-angle rotation vector — exact at the rest pose and
|
|
88
|
+
* cheap, correct for welds, hinges, and modest angular limits. `true`
|
|
89
|
+
* switches to the **swing-twist** decomposition: angular X is the *twist*
|
|
90
|
+
* (rotation about the bone / X axis) and angular Y/Z are the *swing* (tilt
|
|
91
|
+
* off it), each measured as an exact angle. Use it for wide cone-twist
|
|
92
|
+
* range-of-motion (ragdoll shoulders) where the small-angle measure
|
|
93
|
+
* under-reports large angles. See {@link asConeTwist}.
|
|
94
|
+
* @type {boolean}
|
|
95
|
+
*/
|
|
96
|
+
swingTwist: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Lower / upper bounds per DOF, used by {@link DofMode.LIMITED}. Linear in
|
|
99
|
+
* metres, angular in radians. (Reserved — consumed once the LIMITED mode
|
|
100
|
+
* lands.)
|
|
101
|
+
* @readonly
|
|
102
|
+
* @type {Float64Array}
|
|
103
|
+
*/
|
|
104
|
+
readonly dofLowerLimit: Float64Array;
|
|
105
|
+
/** @readonly @type {Float64Array} */
|
|
106
|
+
readonly dofUpperLimit: Float64Array;
|
|
107
|
+
/**
|
|
108
|
+
* Spring stiffness / damping per DOF, used by {@link DofMode.SPRING}.
|
|
109
|
+
* (Reserved — consumed once the SPRING mode lands.)
|
|
110
|
+
* @readonly
|
|
111
|
+
* @type {Float64Array}
|
|
112
|
+
*/
|
|
113
|
+
readonly dofStiffness: Float64Array;
|
|
114
|
+
/** @readonly @type {Float64Array} */
|
|
115
|
+
readonly dofDamping: Float64Array;
|
|
116
|
+
/**
|
|
117
|
+
* Motor target velocity / max force per DOF, used by
|
|
118
|
+
* {@link DofMode.MOTOR}. (Reserved — consumed once the MOTOR mode lands.)
|
|
119
|
+
* @readonly
|
|
120
|
+
* @type {Float64Array}
|
|
121
|
+
*/
|
|
122
|
+
readonly dofMotorTargetVelocity: Float64Array;
|
|
123
|
+
/** @readonly @type {Float64Array} */
|
|
124
|
+
readonly dofMotorMaxForce: Float64Array;
|
|
125
|
+
/**
|
|
126
|
+
* Accumulated constraint impulse per DOF — warm-start state carried across
|
|
127
|
+
* frames. System-owned.
|
|
128
|
+
* @readonly
|
|
129
|
+
* @type {Float64Array}
|
|
130
|
+
*/
|
|
131
|
+
readonly dofImpulse: Float64Array;
|
|
132
|
+
/**
|
|
133
|
+
* Resolved packed body id of A, set at link time. System-private.
|
|
134
|
+
* @type {number}
|
|
135
|
+
*/
|
|
136
|
+
_bodyIdA: number;
|
|
137
|
+
/**
|
|
138
|
+
* Resolved packed body id of B, or {@link JOINT_WORLD}. System-private.
|
|
139
|
+
* @type {number}
|
|
140
|
+
*/
|
|
141
|
+
_bodyIdB: number;
|
|
142
|
+
/**
|
|
143
|
+
* Packed joint handle assigned at link. System-private.
|
|
144
|
+
* @type {number}
|
|
145
|
+
*/
|
|
146
|
+
_jointId: number;
|
|
147
|
+
/**
|
|
148
|
+
* Configure this joint as a ball-socket (point-to-point) between two
|
|
149
|
+
* anchors. Linear DOFs locked, angular free — the default, provided as a
|
|
150
|
+
* named helper for clarity at call sites.
|
|
151
|
+
* @returns {Joint} this
|
|
152
|
+
*/
|
|
153
|
+
asBallSocket(): Joint;
|
|
154
|
+
/**
|
|
155
|
+
* Configure as a weld (fixed) joint: all 6 DOFs locked, holding the two
|
|
156
|
+
* bodies rigidly in their relative pose.
|
|
157
|
+
* @returns {Joint} this
|
|
158
|
+
*/
|
|
159
|
+
asWeld(): Joint;
|
|
160
|
+
/**
|
|
161
|
+
* Configure as a hinge (revolute): 3 linear + 2 angular locked, free to
|
|
162
|
+
* rotate about a single frame axis. Orient {@link localBasisA} /
|
|
163
|
+
* {@link localBasisB} so that frame axis is the desired hinge axis.
|
|
164
|
+
*
|
|
165
|
+
* @param {number} [freeAngularAxis] which frame axis is free: 0 = x
|
|
166
|
+
* (default), 1 = y, 2 = z.
|
|
167
|
+
* @returns {Joint} this
|
|
168
|
+
*/
|
|
169
|
+
asHinge(freeAngularAxis?: number): Joint;
|
|
170
|
+
/**
|
|
171
|
+
* Configure as a prismatic (slider): 2 linear + 3 angular locked, free to
|
|
172
|
+
* translate along a single frame axis. Orient {@link localBasisA} /
|
|
173
|
+
* {@link localBasisB} so that frame axis is the desired slide direction.
|
|
174
|
+
*
|
|
175
|
+
* @param {number} [freeLinearAxis] which frame axis is free: 0 = x
|
|
176
|
+
* (default), 1 = y, 2 = z.
|
|
177
|
+
* @returns {Joint} this
|
|
178
|
+
*/
|
|
179
|
+
asPrismatic(freeLinearAxis?: number): Joint;
|
|
180
|
+
/**
|
|
181
|
+
* Configure as a cone-twist (ragdoll) joint: a ball-socket point (3 linear
|
|
182
|
+
* locked) whose angular motion is a limited **twist** about the bone (frame
|
|
183
|
+
* X) and a limited **swing** cone off it (frame Y / Z). Enables
|
|
184
|
+
* {@link swingTwist} so the limits are measured as exact angles, holding
|
|
185
|
+
* accurately at the wide ranges ragdoll shoulders need.
|
|
186
|
+
*
|
|
187
|
+
* Orient {@link localBasisA} / {@link localBasisB} so frame X runs along the
|
|
188
|
+
* bone. The swing cone is box-shaped: independent Y and Z half-angles
|
|
189
|
+
* (`swingLimitZ` defaults to `swingLimitY` for a circular cone).
|
|
190
|
+
*
|
|
191
|
+
* @param {number} twistLower @param {number} twistUpper twist bounds, rad.
|
|
192
|
+
* @param {number} swingLimitY swing half-angle about frame Y, rad.
|
|
193
|
+
* @param {number} [swingLimitZ] swing half-angle about frame Z, rad
|
|
194
|
+
* (defaults to `swingLimitY`).
|
|
195
|
+
* @returns {Joint} this
|
|
196
|
+
*/
|
|
197
|
+
asConeTwist(twistLower: number, twistUpper: number, swingLimitY: number, swingLimitZ?: number): Joint;
|
|
198
|
+
/**
|
|
199
|
+
* Limit a linear DOF to a travel range along its frame axis (slider
|
|
200
|
+
* end-stops): the DOF slides freely within `[lower, upper]` metres and is
|
|
201
|
+
* resisted at the stops. Sets {@link DofMode.LIMITED} on that axis.
|
|
202
|
+
*
|
|
203
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
204
|
+
* @param {number} lower @param {number} upper travel bounds in metres
|
|
205
|
+
* (signed anchor-A offset from anchor-B along the frame axis).
|
|
206
|
+
* @returns {Joint} this
|
|
207
|
+
*/
|
|
208
|
+
setLinearLimit(axis: number, lower: number, upper: number): Joint;
|
|
209
|
+
/**
|
|
210
|
+
* Limit an angular DOF to a rotation range about its frame axis (joint
|
|
211
|
+
* range-of-motion): free within `[lower, upper]` radians, resisted at the
|
|
212
|
+
* stops. Sets {@link DofMode.LIMITED} on that angular axis.
|
|
213
|
+
*
|
|
214
|
+
* The angular position is a first-order (small-angle) measure, so the
|
|
215
|
+
* effective stop is accurate for modest ranges (hinge / slider end-stops)
|
|
216
|
+
* but under-reports large angles — wide cones (ragdoll shoulders) want the
|
|
217
|
+
* swing-twist decomposition (already available as
|
|
218
|
+
* `Quaternion.computeSwingAndTwist` / `computeTwistAngle`). See the solver
|
|
219
|
+
* module docs.
|
|
220
|
+
*
|
|
221
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
222
|
+
* @param {number} lower @param {number} upper rotation bounds in radians.
|
|
223
|
+
* @returns {Joint} this
|
|
224
|
+
*/
|
|
225
|
+
setAngularLimit(axis: number, lower: number, upper: number): Joint;
|
|
226
|
+
/**
|
|
227
|
+
* Drive a linear DOF at a target speed along its frame axis (piston,
|
|
228
|
+
* conveyor, powered slider). A force-limited velocity servo: it pulls the
|
|
229
|
+
* relative velocity toward `targetVelocity` as hard as `maxForce` allows.
|
|
230
|
+
* Sets {@link DofMode.MOTOR} on that axis.
|
|
231
|
+
*
|
|
232
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
233
|
+
* @param {number} targetVelocity desired relative anchor speed of A w.r.t.
|
|
234
|
+
* B along the frame axis, m/s (sign convention A − B).
|
|
235
|
+
* @param {number} maxForce force budget in newtons (`Infinity` for an
|
|
236
|
+
* ideal velocity drive; `0` makes the motor inert).
|
|
237
|
+
* @returns {Joint} this
|
|
238
|
+
*/
|
|
239
|
+
setLinearMotor(axis: number, targetVelocity: number, maxForce: number): Joint;
|
|
240
|
+
/**
|
|
241
|
+
* Drive an angular DOF at a target rate about its frame axis (wheel drive,
|
|
242
|
+
* powered hinge / door, turntable). A force-(torque-)limited velocity servo
|
|
243
|
+
* pulling the relative angular velocity toward `targetVelocity`. Sets
|
|
244
|
+
* {@link DofMode.MOTOR} on that angular axis.
|
|
245
|
+
*
|
|
246
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
247
|
+
* @param {number} targetVelocity desired relative angular rate of B w.r.t.
|
|
248
|
+
* A about the frame axis, rad/s (sign convention B − A — so for a
|
|
249
|
+
* world-anchored motor a positive target spins body A negatively about
|
|
250
|
+
* the axis).
|
|
251
|
+
* @param {number} maxForce torque budget in newton-metres (`Infinity` for
|
|
252
|
+
* an ideal drive; `0` makes the motor inert).
|
|
253
|
+
* @returns {Joint} this
|
|
254
|
+
*/
|
|
255
|
+
setAngularMotor(axis: number, targetVelocity: number, maxForce: number): Joint;
|
|
256
|
+
/**
|
|
257
|
+
* Make a linear DOF a compliant spring along its frame axis (suspension,
|
|
258
|
+
* bungee, soft-return slider). The spring drives the DOF toward its zero
|
|
259
|
+
* (the rest pose — place the anchors / basis so the relaxed position is
|
|
260
|
+
* `C·axis = 0`) with stiffness and damping, yielding under load rather than
|
|
261
|
+
* holding rigid. Sets {@link DofMode.SPRING} on that axis.
|
|
262
|
+
*
|
|
263
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
264
|
+
* @param {number} stiffness spring constant `k`, N/m (0 ⇒ pure damper).
|
|
265
|
+
* @param {number} damping damping coefficient `c`, N·s/m (0 ⇒ undamped).
|
|
266
|
+
* @returns {Joint} this
|
|
267
|
+
*/
|
|
268
|
+
setLinearSpring(axis: number, stiffness: number, damping: number): Joint;
|
|
269
|
+
/**
|
|
270
|
+
* Make an angular DOF a compliant torsional spring about its frame axis
|
|
271
|
+
* (soft-return hinge, sway bar, soft ragdoll joint). Drives the relative
|
|
272
|
+
* rotation about the axis toward zero with stiffness and damping. Sets
|
|
273
|
+
* {@link DofMode.SPRING} on that angular axis. Uses the small-angle measure
|
|
274
|
+
* (see the solver module docs), so it is for modest ranges.
|
|
275
|
+
*
|
|
276
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
277
|
+
* @param {number} stiffness torsional spring constant `k`, N·m/rad
|
|
278
|
+
* (0 ⇒ pure damper).
|
|
279
|
+
* @param {number} damping torsional damping, N·m·s/rad (0 ⇒ undamped).
|
|
280
|
+
* @returns {Joint} this
|
|
281
|
+
*/
|
|
282
|
+
setAngularSpring(axis: number, stiffness: number, damping: number): Joint;
|
|
283
|
+
/**
|
|
284
|
+
* @readonly
|
|
285
|
+
* @type {boolean}
|
|
286
|
+
*/
|
|
287
|
+
readonly isJoint: boolean;
|
|
288
|
+
}
|
|
289
|
+
export namespace Joint {
|
|
290
|
+
let typeName: string;
|
|
291
|
+
}
|
|
292
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
293
|
+
import Quaternion from "../../../core/geom/Quaternion.js";
|
|
294
|
+
//# sourceMappingURL=Joint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Joint.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/ecs/Joint.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,gCAFU,MAAM,CAEoB;AAEpC;;;;GAIG;AACH,0BAFU,MAAM,CAEc;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAEI;;;OAGG;IACH,SAFU,MAAM,CAEH;IAEb;;;OAGG;IACH,SAFU,MAAM,CAEM;IAEtB;;;;OAIG;IACH,uBAFU,OAAO,CAEmB;IAEpC;;;;;OAKG;IACH,uBAFU,OAAO,CAEmB;IAEpC;;;;;;;;;OASG;IACH,sBAFU,UAAU,CAEW;IAE/B;;;;;;;OAOG;IACH,sBAFU,UAAU,CAEW;IAE/B;;;;;OAKG;IACH,kBAFU,UAAU,CAKjB;IAEH;;;;;;;;;;OAUG;IACH,YAFU,OAAO,CAEE;IAEnB;;;;;;OAMG;IACH,wBAFU,YAAY,CAEc;IACpC,qCAAqC;IACrC,wBADqB,YAAY,CACG;IAEpC;;;;;OAKG;IACH,uBAFU,YAAY,CAEa;IACnC,qCAAqC;IACrC,qBADqB,YAAY,CACA;IAEjC;;;;;OAKG;IACH,iCAFU,YAAY,CAEuB;IAC7C,qCAAqC;IACrC,2BADqB,YAAY,CACM;IAEvC;;;;;OAKG;IACH,qBAFU,YAAY,CAEW;IAEjC;;;OAGG;IACH,UAFU,MAAM,CAEF;IACd;;;OAGG;IACH,UAFU,MAAM,CAEO;IACvB;;;OAGG;IACH,UAFU,MAAM,CAEa;IAE7B;;;;;OAKG;IACH,gBAFa,KAAK,CAUjB;IAED;;;;OAIG;IACH,UAFa,KAAK,CAKjB;IAED;;;;;;;;OAQG;IACH,0BAJW,MAAM,GAEJ,KAAK,CAWjB;IAED;;;;;;;;OAQG;IACH,6BAJW,MAAM,GAEJ,KAAK,CAWjB;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,wBANW,MAAM,cAAqB,MAAM,eACjC,MAAM,gBACN,MAAM,GAEJ,KAAK,CAiBjB;IAED;;;;;;;;;OASG;IACH,qBALW,MAAM,SACN,MAAM,SAAgB,MAAM,GAE1B,KAAK,CAOjB;IAED;;;;;;;;;;;;;;;OAeG;IACH,sBAJW,MAAM,SACN,MAAM,SAAgB,MAAM,GAC1B,KAAK,CAOjB;IAED;;;;;;;;;;;;OAYG;IACH,qBAPW,MAAM,kBACN,MAAM,YAEN,MAAM,GAEJ,KAAK,CAOjB;IAED;;;;;;;;;;;;;;OAcG;IACH,sBATW,MAAM,kBACN,MAAM,YAIN,MAAM,GAEJ,KAAK,CAOjB;IAED;;;;;;;;;;;OAWG;IACH,sBALW,MAAM,aACN,MAAM,WACN,MAAM,GACJ,KAAK,CAOjB;IAED;;;;;;;;;;;;OAYG;IACH,uBANW,MAAM,aACN,MAAM,WAEN,MAAM,GACJ,KAAK,CAOjB;IASL;;;OAGG;IACH,kBAFU,OAAO,CAEM;CAZtB;;kBAIS,MAAM;;oBAzYI,+BAA+B;uBAC5B,kCAAkC"}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
2
|
+
import Quaternion from "../../../core/geom/Quaternion.js";
|
|
3
|
+
import { DofMode } from "../constraint/DofMode.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sentinel for {@link Joint#_jointId} before the joint is linked into a
|
|
7
|
+
* {@link PhysicsSystem}.
|
|
8
|
+
* @type {number}
|
|
9
|
+
*/
|
|
10
|
+
export const JOINT_UNALLOCATED = -1;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* `entityB` value meaning "the world" — body A is constrained to a fixed
|
|
14
|
+
* world anchor rather than to a second body.
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
export const JOINT_WORLD = -1;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A configurable 6-DOF constraint between two bodies (or a body and the
|
|
21
|
+
* world). Connects body A's anchor frame to body B's; each of the 6 relative
|
|
22
|
+
* degrees of freedom (3 linear, 3 angular) is independently
|
|
23
|
+
* locked / free / limited / springy / motorised ({@link DofMode}). One
|
|
24
|
+
* constraint type expresses the whole joint taxonomy — see DofMode.
|
|
25
|
+
*
|
|
26
|
+
* The default configuration is a **ball-socket** (point-to-point): the three
|
|
27
|
+
* linear DOFs LOCKED (the two anchor points are held coincident), the three
|
|
28
|
+
* angular DOFs FREE. That alone gives chains, ropes, and pendulums.
|
|
29
|
+
*
|
|
30
|
+
* Anchors live in body-local frames. When `entityB === JOINT_WORLD`,
|
|
31
|
+
* `localAnchorB` is interpreted as a fixed **world** point instead of a
|
|
32
|
+
* local anchor on a second body.
|
|
33
|
+
*
|
|
34
|
+
* Solver state ({@link dofImpulse}, the `_*` fields) is owned by the
|
|
35
|
+
* PhysicsSystem; user code must not write it.
|
|
36
|
+
*
|
|
37
|
+
* @author Alex Goldring
|
|
38
|
+
* @copyright Company Named Limited (c) 2026
|
|
39
|
+
*/
|
|
40
|
+
export class Joint {
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Entity owning body A (the constraint's first body — always a real body).
|
|
44
|
+
* @type {number}
|
|
45
|
+
*/
|
|
46
|
+
entityA = -1;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Entity owning body B, or {@link JOINT_WORLD} to anchor A to the world.
|
|
50
|
+
* @type {number}
|
|
51
|
+
*/
|
|
52
|
+
entityB = JOINT_WORLD;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Anchor point on body A, in A's local frame.
|
|
56
|
+
* @readonly
|
|
57
|
+
* @type {Vector3}
|
|
58
|
+
*/
|
|
59
|
+
localAnchorA = new Vector3(0, 0, 0);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Anchor point on body B in B's local frame — or, when
|
|
63
|
+
* `entityB === JOINT_WORLD`, a fixed world-space anchor point.
|
|
64
|
+
* @readonly
|
|
65
|
+
* @type {Vector3}
|
|
66
|
+
*/
|
|
67
|
+
localAnchorB = new Vector3(0, 0, 0);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Orientation of the joint's reference frame on body A, in A's local
|
|
71
|
+
* space (a unit quaternion; identity = the joint frame is the body
|
|
72
|
+
* frame). The 3 linear and 3 angular DOFs are expressed in this frame:
|
|
73
|
+
* locked/limited/etc. axes are the frame's axes, not world axes. For a
|
|
74
|
+
* hinge, the free angular axis is one of these frame axes — orient the
|
|
75
|
+
* frame so that axis is the hinge axis.
|
|
76
|
+
* @readonly
|
|
77
|
+
* @type {Quaternion}
|
|
78
|
+
*/
|
|
79
|
+
localBasisA = new Quaternion();
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Orientation of the joint's reference frame on body B, in B's local
|
|
83
|
+
* space. At rest a fully-locked joint holds frame B aligned to frame A.
|
|
84
|
+
* When `entityB === JOINT_WORLD`, the world frame is treated as identity
|
|
85
|
+
* (angular locks hold A's frame to world axes).
|
|
86
|
+
* @readonly
|
|
87
|
+
* @type {Quaternion}
|
|
88
|
+
*/
|
|
89
|
+
localBasisB = new Quaternion();
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Per-DOF mode, 6 entries: `[lin x, lin y, lin z, ang x, ang y, ang z]`.
|
|
93
|
+
* Default = ball-socket (linear locked, angular free).
|
|
94
|
+
* @readonly
|
|
95
|
+
* @type {Uint8Array}
|
|
96
|
+
*/
|
|
97
|
+
dofMode = Uint8Array.from([
|
|
98
|
+
DofMode.LOCKED, DofMode.LOCKED, DofMode.LOCKED,
|
|
99
|
+
DofMode.FREE, DofMode.FREE, DofMode.FREE,
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* How the three angular DOF positions are measured. `false` (default) uses
|
|
104
|
+
* the per-axis small-angle rotation vector — exact at the rest pose and
|
|
105
|
+
* cheap, correct for welds, hinges, and modest angular limits. `true`
|
|
106
|
+
* switches to the **swing-twist** decomposition: angular X is the *twist*
|
|
107
|
+
* (rotation about the bone / X axis) and angular Y/Z are the *swing* (tilt
|
|
108
|
+
* off it), each measured as an exact angle. Use it for wide cone-twist
|
|
109
|
+
* range-of-motion (ragdoll shoulders) where the small-angle measure
|
|
110
|
+
* under-reports large angles. See {@link asConeTwist}.
|
|
111
|
+
* @type {boolean}
|
|
112
|
+
*/
|
|
113
|
+
swingTwist = false;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Lower / upper bounds per DOF, used by {@link DofMode.LIMITED}. Linear in
|
|
117
|
+
* metres, angular in radians. (Reserved — consumed once the LIMITED mode
|
|
118
|
+
* lands.)
|
|
119
|
+
* @readonly
|
|
120
|
+
* @type {Float64Array}
|
|
121
|
+
*/
|
|
122
|
+
dofLowerLimit = new Float64Array(6);
|
|
123
|
+
/** @readonly @type {Float64Array} */
|
|
124
|
+
dofUpperLimit = new Float64Array(6);
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Spring stiffness / damping per DOF, used by {@link DofMode.SPRING}.
|
|
128
|
+
* (Reserved — consumed once the SPRING mode lands.)
|
|
129
|
+
* @readonly
|
|
130
|
+
* @type {Float64Array}
|
|
131
|
+
*/
|
|
132
|
+
dofStiffness = new Float64Array(6);
|
|
133
|
+
/** @readonly @type {Float64Array} */
|
|
134
|
+
dofDamping = new Float64Array(6);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Motor target velocity / max force per DOF, used by
|
|
138
|
+
* {@link DofMode.MOTOR}. (Reserved — consumed once the MOTOR mode lands.)
|
|
139
|
+
* @readonly
|
|
140
|
+
* @type {Float64Array}
|
|
141
|
+
*/
|
|
142
|
+
dofMotorTargetVelocity = new Float64Array(6);
|
|
143
|
+
/** @readonly @type {Float64Array} */
|
|
144
|
+
dofMotorMaxForce = new Float64Array(6);
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Accumulated constraint impulse per DOF — warm-start state carried across
|
|
148
|
+
* frames. System-owned.
|
|
149
|
+
* @readonly
|
|
150
|
+
* @type {Float64Array}
|
|
151
|
+
*/
|
|
152
|
+
dofImpulse = new Float64Array(6);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Resolved packed body id of A, set at link time. System-private.
|
|
156
|
+
* @type {number}
|
|
157
|
+
*/
|
|
158
|
+
_bodyIdA = -1;
|
|
159
|
+
/**
|
|
160
|
+
* Resolved packed body id of B, or {@link JOINT_WORLD}. System-private.
|
|
161
|
+
* @type {number}
|
|
162
|
+
*/
|
|
163
|
+
_bodyIdB = JOINT_WORLD;
|
|
164
|
+
/**
|
|
165
|
+
* Packed joint handle assigned at link. System-private.
|
|
166
|
+
* @type {number}
|
|
167
|
+
*/
|
|
168
|
+
_jointId = JOINT_UNALLOCATED;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Configure this joint as a ball-socket (point-to-point) between two
|
|
172
|
+
* anchors. Linear DOFs locked, angular free — the default, provided as a
|
|
173
|
+
* named helper for clarity at call sites.
|
|
174
|
+
* @returns {Joint} this
|
|
175
|
+
*/
|
|
176
|
+
asBallSocket() {
|
|
177
|
+
this.dofMode[0] = DofMode.LOCKED;
|
|
178
|
+
this.dofMode[1] = DofMode.LOCKED;
|
|
179
|
+
this.dofMode[2] = DofMode.LOCKED;
|
|
180
|
+
this.dofMode[3] = DofMode.FREE;
|
|
181
|
+
this.dofMode[4] = DofMode.FREE;
|
|
182
|
+
this.dofMode[5] = DofMode.FREE;
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Configure as a weld (fixed) joint: all 6 DOFs locked, holding the two
|
|
188
|
+
* bodies rigidly in their relative pose.
|
|
189
|
+
* @returns {Joint} this
|
|
190
|
+
*/
|
|
191
|
+
asWeld() {
|
|
192
|
+
for (let i = 0; i < 6; i++) this.dofMode[i] = DofMode.LOCKED;
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Configure as a hinge (revolute): 3 linear + 2 angular locked, free to
|
|
198
|
+
* rotate about a single frame axis. Orient {@link localBasisA} /
|
|
199
|
+
* {@link localBasisB} so that frame axis is the desired hinge axis.
|
|
200
|
+
*
|
|
201
|
+
* @param {number} [freeAngularAxis] which frame axis is free: 0 = x
|
|
202
|
+
* (default), 1 = y, 2 = z.
|
|
203
|
+
* @returns {Joint} this
|
|
204
|
+
*/
|
|
205
|
+
asHinge(freeAngularAxis = 0) {
|
|
206
|
+
this.dofMode[0] = DofMode.LOCKED;
|
|
207
|
+
this.dofMode[1] = DofMode.LOCKED;
|
|
208
|
+
this.dofMode[2] = DofMode.LOCKED;
|
|
209
|
+
this.dofMode[3] = DofMode.LOCKED;
|
|
210
|
+
this.dofMode[4] = DofMode.LOCKED;
|
|
211
|
+
this.dofMode[5] = DofMode.LOCKED;
|
|
212
|
+
this.dofMode[3 + freeAngularAxis] = DofMode.FREE;
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Configure as a prismatic (slider): 2 linear + 3 angular locked, free to
|
|
218
|
+
* translate along a single frame axis. Orient {@link localBasisA} /
|
|
219
|
+
* {@link localBasisB} so that frame axis is the desired slide direction.
|
|
220
|
+
*
|
|
221
|
+
* @param {number} [freeLinearAxis] which frame axis is free: 0 = x
|
|
222
|
+
* (default), 1 = y, 2 = z.
|
|
223
|
+
* @returns {Joint} this
|
|
224
|
+
*/
|
|
225
|
+
asPrismatic(freeLinearAxis = 0) {
|
|
226
|
+
this.dofMode[0] = DofMode.LOCKED;
|
|
227
|
+
this.dofMode[1] = DofMode.LOCKED;
|
|
228
|
+
this.dofMode[2] = DofMode.LOCKED;
|
|
229
|
+
this.dofMode[freeLinearAxis] = DofMode.FREE;
|
|
230
|
+
this.dofMode[3] = DofMode.LOCKED;
|
|
231
|
+
this.dofMode[4] = DofMode.LOCKED;
|
|
232
|
+
this.dofMode[5] = DofMode.LOCKED;
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Configure as a cone-twist (ragdoll) joint: a ball-socket point (3 linear
|
|
238
|
+
* locked) whose angular motion is a limited **twist** about the bone (frame
|
|
239
|
+
* X) and a limited **swing** cone off it (frame Y / Z). Enables
|
|
240
|
+
* {@link swingTwist} so the limits are measured as exact angles, holding
|
|
241
|
+
* accurately at the wide ranges ragdoll shoulders need.
|
|
242
|
+
*
|
|
243
|
+
* Orient {@link localBasisA} / {@link localBasisB} so frame X runs along the
|
|
244
|
+
* bone. The swing cone is box-shaped: independent Y and Z half-angles
|
|
245
|
+
* (`swingLimitZ` defaults to `swingLimitY` for a circular cone).
|
|
246
|
+
*
|
|
247
|
+
* @param {number} twistLower @param {number} twistUpper twist bounds, rad.
|
|
248
|
+
* @param {number} swingLimitY swing half-angle about frame Y, rad.
|
|
249
|
+
* @param {number} [swingLimitZ] swing half-angle about frame Z, rad
|
|
250
|
+
* (defaults to `swingLimitY`).
|
|
251
|
+
* @returns {Joint} this
|
|
252
|
+
*/
|
|
253
|
+
asConeTwist(twistLower, twistUpper, swingLimitY, swingLimitZ = swingLimitY) {
|
|
254
|
+
this.dofMode[0] = DofMode.LOCKED;
|
|
255
|
+
this.dofMode[1] = DofMode.LOCKED;
|
|
256
|
+
this.dofMode[2] = DofMode.LOCKED;
|
|
257
|
+
this.swingTwist = true;
|
|
258
|
+
this.dofMode[3] = DofMode.LIMITED;
|
|
259
|
+
this.dofLowerLimit[3] = twistLower;
|
|
260
|
+
this.dofUpperLimit[3] = twistUpper;
|
|
261
|
+
this.dofMode[4] = DofMode.LIMITED;
|
|
262
|
+
this.dofLowerLimit[4] = -swingLimitY;
|
|
263
|
+
this.dofUpperLimit[4] = swingLimitY;
|
|
264
|
+
this.dofMode[5] = DofMode.LIMITED;
|
|
265
|
+
this.dofLowerLimit[5] = -swingLimitZ;
|
|
266
|
+
this.dofUpperLimit[5] = swingLimitZ;
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Limit a linear DOF to a travel range along its frame axis (slider
|
|
272
|
+
* end-stops): the DOF slides freely within `[lower, upper]` metres and is
|
|
273
|
+
* resisted at the stops. Sets {@link DofMode.LIMITED} on that axis.
|
|
274
|
+
*
|
|
275
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
276
|
+
* @param {number} lower @param {number} upper travel bounds in metres
|
|
277
|
+
* (signed anchor-A offset from anchor-B along the frame axis).
|
|
278
|
+
* @returns {Joint} this
|
|
279
|
+
*/
|
|
280
|
+
setLinearLimit(axis, lower, upper) {
|
|
281
|
+
this.dofMode[axis] = DofMode.LIMITED;
|
|
282
|
+
this.dofLowerLimit[axis] = lower;
|
|
283
|
+
this.dofUpperLimit[axis] = upper;
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Limit an angular DOF to a rotation range about its frame axis (joint
|
|
289
|
+
* range-of-motion): free within `[lower, upper]` radians, resisted at the
|
|
290
|
+
* stops. Sets {@link DofMode.LIMITED} on that angular axis.
|
|
291
|
+
*
|
|
292
|
+
* The angular position is a first-order (small-angle) measure, so the
|
|
293
|
+
* effective stop is accurate for modest ranges (hinge / slider end-stops)
|
|
294
|
+
* but under-reports large angles — wide cones (ragdoll shoulders) want the
|
|
295
|
+
* swing-twist decomposition (already available as
|
|
296
|
+
* `Quaternion.computeSwingAndTwist` / `computeTwistAngle`). See the solver
|
|
297
|
+
* module docs.
|
|
298
|
+
*
|
|
299
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
300
|
+
* @param {number} lower @param {number} upper rotation bounds in radians.
|
|
301
|
+
* @returns {Joint} this
|
|
302
|
+
*/
|
|
303
|
+
setAngularLimit(axis, lower, upper) {
|
|
304
|
+
this.dofMode[3 + axis] = DofMode.LIMITED;
|
|
305
|
+
this.dofLowerLimit[3 + axis] = lower;
|
|
306
|
+
this.dofUpperLimit[3 + axis] = upper;
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Drive a linear DOF at a target speed along its frame axis (piston,
|
|
312
|
+
* conveyor, powered slider). A force-limited velocity servo: it pulls the
|
|
313
|
+
* relative velocity toward `targetVelocity` as hard as `maxForce` allows.
|
|
314
|
+
* Sets {@link DofMode.MOTOR} on that axis.
|
|
315
|
+
*
|
|
316
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
317
|
+
* @param {number} targetVelocity desired relative anchor speed of A w.r.t.
|
|
318
|
+
* B along the frame axis, m/s (sign convention A − B).
|
|
319
|
+
* @param {number} maxForce force budget in newtons (`Infinity` for an
|
|
320
|
+
* ideal velocity drive; `0` makes the motor inert).
|
|
321
|
+
* @returns {Joint} this
|
|
322
|
+
*/
|
|
323
|
+
setLinearMotor(axis, targetVelocity, maxForce) {
|
|
324
|
+
this.dofMode[axis] = DofMode.MOTOR;
|
|
325
|
+
this.dofMotorTargetVelocity[axis] = targetVelocity;
|
|
326
|
+
this.dofMotorMaxForce[axis] = maxForce;
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Drive an angular DOF at a target rate about its frame axis (wheel drive,
|
|
332
|
+
* powered hinge / door, turntable). A force-(torque-)limited velocity servo
|
|
333
|
+
* pulling the relative angular velocity toward `targetVelocity`. Sets
|
|
334
|
+
* {@link DofMode.MOTOR} on that angular axis.
|
|
335
|
+
*
|
|
336
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
337
|
+
* @param {number} targetVelocity desired relative angular rate of B w.r.t.
|
|
338
|
+
* A about the frame axis, rad/s (sign convention B − A — so for a
|
|
339
|
+
* world-anchored motor a positive target spins body A negatively about
|
|
340
|
+
* the axis).
|
|
341
|
+
* @param {number} maxForce torque budget in newton-metres (`Infinity` for
|
|
342
|
+
* an ideal drive; `0` makes the motor inert).
|
|
343
|
+
* @returns {Joint} this
|
|
344
|
+
*/
|
|
345
|
+
setAngularMotor(axis, targetVelocity, maxForce) {
|
|
346
|
+
this.dofMode[3 + axis] = DofMode.MOTOR;
|
|
347
|
+
this.dofMotorTargetVelocity[3 + axis] = targetVelocity;
|
|
348
|
+
this.dofMotorMaxForce[3 + axis] = maxForce;
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Make a linear DOF a compliant spring along its frame axis (suspension,
|
|
354
|
+
* bungee, soft-return slider). The spring drives the DOF toward its zero
|
|
355
|
+
* (the rest pose — place the anchors / basis so the relaxed position is
|
|
356
|
+
* `C·axis = 0`) with stiffness and damping, yielding under load rather than
|
|
357
|
+
* holding rigid. Sets {@link DofMode.SPRING} on that axis.
|
|
358
|
+
*
|
|
359
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
360
|
+
* @param {number} stiffness spring constant `k`, N/m (0 ⇒ pure damper).
|
|
361
|
+
* @param {number} damping damping coefficient `c`, N·s/m (0 ⇒ undamped).
|
|
362
|
+
* @returns {Joint} this
|
|
363
|
+
*/
|
|
364
|
+
setLinearSpring(axis, stiffness, damping) {
|
|
365
|
+
this.dofMode[axis] = DofMode.SPRING;
|
|
366
|
+
this.dofStiffness[axis] = stiffness;
|
|
367
|
+
this.dofDamping[axis] = damping;
|
|
368
|
+
return this;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Make an angular DOF a compliant torsional spring about its frame axis
|
|
373
|
+
* (soft-return hinge, sway bar, soft ragdoll joint). Drives the relative
|
|
374
|
+
* rotation about the axis toward zero with stiffness and damping. Sets
|
|
375
|
+
* {@link DofMode.SPRING} on that angular axis. Uses the small-angle measure
|
|
376
|
+
* (see the solver module docs), so it is for modest ranges.
|
|
377
|
+
*
|
|
378
|
+
* @param {number} axis frame axis: 0 = x, 1 = y, 2 = z.
|
|
379
|
+
* @param {number} stiffness torsional spring constant `k`, N·m/rad
|
|
380
|
+
* (0 ⇒ pure damper).
|
|
381
|
+
* @param {number} damping torsional damping, N·m·s/rad (0 ⇒ undamped).
|
|
382
|
+
* @returns {Joint} this
|
|
383
|
+
*/
|
|
384
|
+
setAngularSpring(axis, stiffness, damping) {
|
|
385
|
+
this.dofMode[3 + axis] = DofMode.SPRING;
|
|
386
|
+
this.dofStiffness[3 + axis] = stiffness;
|
|
387
|
+
this.dofDamping[3 + axis] = damping;
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @readonly
|
|
394
|
+
* @type {string}
|
|
395
|
+
*/
|
|
396
|
+
Joint.typeName = "Joint";
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* @readonly
|
|
400
|
+
* @type {boolean}
|
|
401
|
+
*/
|
|
402
|
+
Joint.prototype.isJoint = true;
|