reze-engine 0.16.3 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -250
- package/dist/engine.d.ts +3 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +160 -21
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/model.d.ts +1 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/physics/body.d.ts +3 -1
- package/dist/physics/body.d.ts.map +1 -1
- package/dist/physics/body.js +84 -20
- package/dist/physics/constraint.d.ts +14 -1
- package/dist/physics/constraint.d.ts.map +1 -1
- package/dist/physics/constraint.js +43 -1
- package/dist/physics/solver.d.ts.map +1 -1
- package/dist/physics/solver.js +278 -110
- package/dist/pmx-loader.d.ts.map +1 -1
- package/dist/pmx-loader.js +1 -0
- package/dist/shaders/materials/body.d.ts +1 -1
- package/dist/shaders/materials/body.d.ts.map +1 -1
- package/dist/shaders/materials/cloth_rough.d.ts +1 -1
- package/dist/shaders/materials/cloth_rough.d.ts.map +1 -1
- package/dist/shaders/materials/cloth_smooth.d.ts +1 -1
- package/dist/shaders/materials/cloth_smooth.d.ts.map +1 -1
- package/dist/shaders/materials/common.d.ts +1 -1
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +137 -122
- package/dist/shaders/materials/default.d.ts +1 -1
- package/dist/shaders/materials/default.d.ts.map +1 -1
- package/dist/shaders/materials/eye.d.ts +1 -1
- package/dist/shaders/materials/eye.d.ts.map +1 -1
- package/dist/shaders/materials/eye.js +14 -0
- package/dist/shaders/materials/face.d.ts +1 -1
- package/dist/shaders/materials/face.d.ts.map +1 -1
- package/dist/shaders/materials/hair.d.ts +1 -1
- package/dist/shaders/materials/hair.d.ts.map +1 -1
- package/dist/shaders/materials/metal.d.ts +1 -1
- package/dist/shaders/materials/metal.d.ts.map +1 -1
- package/dist/shaders/materials/mmd_classic.d.ts +2 -0
- package/dist/shaders/materials/mmd_classic.d.ts.map +1 -0
- package/dist/shaders/materials/mmd_classic.js +66 -0
- package/dist/shaders/materials/stockings.d.ts +1 -1
- package/dist/shaders/materials/stockings.d.ts.map +1 -1
- package/package.json +42 -42
- package/src/engine.ts +4204 -4045
- package/src/index.ts +29 -28
- package/src/model.ts +3 -0
- package/src/physics/body.ts +82 -24
- package/src/physics/constraint.ts +74 -5
- package/src/physics/solver.ts +915 -752
- package/src/pmx-loader.ts +1 -0
- package/src/shaders/materials/common.ts +204 -189
- package/src/shaders/materials/eye.ts +14 -0
- package/src/shaders/materials/mmd_classic.ts +68 -0
package/dist/physics/solver.js
CHANGED
|
@@ -24,6 +24,32 @@ const MAX_ANGULAR_CORRECTION_VEL = 30; // rad/s
|
|
|
24
24
|
// instead of as a hard velocity snap.
|
|
25
25
|
const LIMIT_SOFTNESS_LINEAR = 0.7;
|
|
26
26
|
const LIMIT_SOFTNESS_ANGULAR = 0.5;
|
|
27
|
+
// Bullet spring-motor velocity factor: target velocity = (fps/numIterations)
|
|
28
|
+
// × spring force, with the applied impulse clamped to the real spring force
|
|
29
|
+
// k·|err|·dt. The big target makes the row deliver its full physical force
|
|
30
|
+
// every substep (stiff, MMD-authored hold); the clamp keeps it from ever
|
|
31
|
+
// exceeding it (no energy pumping). Matches btGeneric6DofSpringConstraint
|
|
32
|
+
// with springDamping=1 and the default 10 solver iterations.
|
|
33
|
+
const SPRING_SOLVER_ITERATIONS = 10;
|
|
34
|
+
// Slack on the spring impulse clamp: MMD rigs are authored against Bullet's
|
|
35
|
+
// spring motors, which deliver several times the naive k·err·dt per substep
|
|
36
|
+
// through their solver-row impulse bounds. Bounded slack keeps the hold
|
|
37
|
+
// stiff (breasts/hair rest near the authored pose) while still capping the
|
|
38
|
+
// energy any spring can inject per substep (the slow-boil guard).
|
|
39
|
+
const SPRING_FORCE_SLACK = 4;
|
|
40
|
+
// ERP scale for loop-closing constraints (see buildConstraints: joints that
|
|
41
|
+
// close a cycle in the joint graph, e.g. the horizontal ring welds of
|
|
42
|
+
// cross-linked skirt lattices). A loop over-determines positions — when
|
|
43
|
+
// contacts push the lattice, the ring's errors cannot all reach zero, and
|
|
44
|
+
// full-rate corrections chase each other around the cycle as violent
|
|
45
|
+
// chatter. Loop edges keep shape at a fraction of the correction rate while
|
|
46
|
+
// the spanning-tree chains stay stiff.
|
|
47
|
+
const LOOP_ERP_SCALE = 1.0;
|
|
48
|
+
// Loop-edge LOCKED axes are converted to force-clamped springs instead of
|
|
49
|
+
// weld rows: an equality row on a cycle fights the other cycle edges at any
|
|
50
|
+
// ERP (the velocity system is over-determined too). A spring bounded by its
|
|
51
|
+
// real force k·|err|·dt holds the ring's shape elastically without fighting.
|
|
52
|
+
const LOOP_SPRING_K = 900;
|
|
27
53
|
// Angular limit violations below this switch to per-axis euler rows; above
|
|
28
54
|
// it, the single geodesic row takes over (see setupConstraint).
|
|
29
55
|
const GEODESIC_THRESHOLD = 0.5; // rad
|
|
@@ -44,19 +70,21 @@ export function solveConstraints(store, constraints, contacts, dt, iterations) {
|
|
|
44
70
|
const lv = store.linearVelocities;
|
|
45
71
|
const av = store.angularVelocities;
|
|
46
72
|
const invMass = store.invMass;
|
|
47
|
-
|
|
73
|
+
// World-space inverse inertia tensors for this substep's poses.
|
|
74
|
+
store.updateInvInertiaWorld();
|
|
75
|
+
const W = store.invInertiaWorld;
|
|
48
76
|
for (let c = 0; c < constraints.length; c++) {
|
|
49
77
|
setupConstraint(constraints[c], store, dt, invDt);
|
|
50
78
|
}
|
|
51
79
|
for (let ci = 0; ci < contacts.count; ci++) {
|
|
52
|
-
setupContactRow(contacts.get(ci), lv, av, invMass,
|
|
80
|
+
setupContactRow(contacts.get(ci), lv, av, invMass, W);
|
|
53
81
|
}
|
|
54
82
|
for (let iter = 0; iter < iterations; iter++) {
|
|
55
83
|
for (let c = 0; c < constraints.length; c++) {
|
|
56
|
-
iterateConstraint(constraints[c], lv, av, invMass
|
|
84
|
+
iterateConstraint(constraints[c], lv, av, invMass);
|
|
57
85
|
}
|
|
58
86
|
for (let ci = 0; ci < contacts.count; ci++) {
|
|
59
|
-
iterateContactRow(contacts.get(ci), lv, av, invMass
|
|
87
|
+
iterateContactRow(contacts.get(ci), lv, av, invMass);
|
|
60
88
|
}
|
|
61
89
|
}
|
|
62
90
|
}
|
|
@@ -67,11 +95,13 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
67
95
|
const b = con.bodyB;
|
|
68
96
|
const imA = store.invMass[a];
|
|
69
97
|
const imB = store.invMass[b];
|
|
70
|
-
const
|
|
71
|
-
const
|
|
98
|
+
const W = store.invInertiaWorld;
|
|
99
|
+
const a9 = a * 9;
|
|
100
|
+
const b9 = b * 9;
|
|
72
101
|
con.cacheSkip = imA === 0 && imB === 0;
|
|
73
102
|
if (con.cacheSkip)
|
|
74
103
|
return;
|
|
104
|
+
const erpScale = con.isLoop ? LOOP_ERP_SCALE : 1.0;
|
|
75
105
|
buildBodyMat(store, a, _bodyMatA);
|
|
76
106
|
buildBodyMat(store, b, _bodyMatB);
|
|
77
107
|
Mat4.multiplyArrays(_bodyMatA, 0, con.frameA, 0, _TA, 0);
|
|
@@ -128,15 +158,23 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
128
158
|
const cBx = rBy * axz - rBz * axy;
|
|
129
159
|
const cBy = rBz * axx - rBx * axz;
|
|
130
160
|
const cBz = rBx * axy - rBy * axx;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
// Tensor-multiplied lever crosses: cache I⁻¹·(r×ax) for application;
|
|
162
|
+
// denominator = (r×ax)ᵀ·I⁻¹·(r×ax).
|
|
163
|
+
const wAx = W[a9 + 0] * cAx + W[a9 + 1] * cAy + W[a9 + 2] * cAz;
|
|
164
|
+
const wAy = W[a9 + 3] * cAx + W[a9 + 4] * cAy + W[a9 + 5] * cAz;
|
|
165
|
+
const wAz = W[a9 + 6] * cAx + W[a9 + 7] * cAy + W[a9 + 8] * cAz;
|
|
166
|
+
const wBx = W[b9 + 0] * cBx + W[b9 + 1] * cBy + W[b9 + 2] * cBz;
|
|
167
|
+
const wBy = W[b9 + 3] * cBx + W[b9 + 4] * cBy + W[b9 + 5] * cBz;
|
|
168
|
+
const wBz = W[b9 + 6] * cBx + W[b9 + 7] * cBy + W[b9 + 8] * cBz;
|
|
169
|
+
cA[o + 0] = wAx;
|
|
170
|
+
cA[o + 1] = wAy;
|
|
171
|
+
cA[o + 2] = wAz;
|
|
172
|
+
cB[o + 0] = wBx;
|
|
173
|
+
cB[o + 1] = wBy;
|
|
174
|
+
cB[o + 2] = wBz;
|
|
137
175
|
const denom = imA + imB +
|
|
138
|
-
(cAx *
|
|
139
|
-
(cBx *
|
|
176
|
+
(cAx * wAx + cAy * wAy + cAz * wAz) +
|
|
177
|
+
(cBx * wBx + cBy * wBy + cBz * wBz);
|
|
140
178
|
jac[i] = denom > 0 ? 1 / denom : 0;
|
|
141
179
|
const lo = con.linearMin[i];
|
|
142
180
|
const hi = con.linearMax[i];
|
|
@@ -156,7 +194,7 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
156
194
|
else if (err !== 0)
|
|
157
195
|
active = 2;
|
|
158
196
|
if (err !== 0) {
|
|
159
|
-
target = -err * STOP_ERP * invDt;
|
|
197
|
+
target = -err * STOP_ERP * erpScale * invDt;
|
|
160
198
|
if (target > MAX_LINEAR_CORRECTION_VEL)
|
|
161
199
|
target = MAX_LINEAR_CORRECTION_VEL;
|
|
162
200
|
else if (target < -MAX_LINEAR_CORRECTION_VEL)
|
|
@@ -177,9 +215,14 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
177
215
|
const k = Math.min(con.springStiffness[i], invDt * invDt);
|
|
178
216
|
const serr = curr - con.equilibriumPoint[i];
|
|
179
217
|
con.cacheLinSpringTarget[i] = -k * serr * dt;
|
|
218
|
+
// Boil guard: per-substep spring impulse bounded by (a slack over) the
|
|
219
|
+
// physical spring force — unbounded spring drives pump energy through
|
|
220
|
+
// the euler-axis mis-scale and slowly boil resting cloth.
|
|
221
|
+
con.cacheLinSpringMaxImp[i] = SPRING_FORCE_SLACK * Math.abs(k * serr) * dt;
|
|
222
|
+
con.cacheLinSpringImp[i] = 0;
|
|
180
223
|
con.cacheLinSpringActive[i] = 1;
|
|
181
224
|
}
|
|
182
|
-
else {
|
|
225
|
+
else if (!(lo === hi && con.isLoop)) {
|
|
183
226
|
con.cacheLinSpringActive[i] = 0;
|
|
184
227
|
}
|
|
185
228
|
}
|
|
@@ -234,8 +277,29 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
234
277
|
angAxes[6] = zx;
|
|
235
278
|
angAxes[7] = zy;
|
|
236
279
|
angAxes[8] = zz;
|
|
237
|
-
|
|
238
|
-
|
|
280
|
+
// Per-axis angular Jacobians with the full tensors: cache I⁻¹·axis per
|
|
281
|
+
// body plus 1/(axᵀ(I⁻¹A+I⁻¹B)ax) per axis.
|
|
282
|
+
const angJac = con.cacheAngJacInv;
|
|
283
|
+
const angWAs = con.cacheAngWA;
|
|
284
|
+
const angWBs = con.cacheAngWB;
|
|
285
|
+
for (let i = 0; i < 3; i++) {
|
|
286
|
+
const o = i * 3;
|
|
287
|
+
const axx = angAxes[o + 0], axy = angAxes[o + 1], axz = angAxes[o + 2];
|
|
288
|
+
const wAx = W[a9 + 0] * axx + W[a9 + 1] * axy + W[a9 + 2] * axz;
|
|
289
|
+
const wAy = W[a9 + 3] * axx + W[a9 + 4] * axy + W[a9 + 5] * axz;
|
|
290
|
+
const wAz = W[a9 + 6] * axx + W[a9 + 7] * axy + W[a9 + 8] * axz;
|
|
291
|
+
const wBx = W[b9 + 0] * axx + W[b9 + 1] * axy + W[b9 + 2] * axz;
|
|
292
|
+
const wBy = W[b9 + 3] * axx + W[b9 + 4] * axy + W[b9 + 5] * axz;
|
|
293
|
+
const wBz = W[b9 + 6] * axx + W[b9 + 7] * axy + W[b9 + 8] * axz;
|
|
294
|
+
angWAs[o + 0] = wAx;
|
|
295
|
+
angWAs[o + 1] = wAy;
|
|
296
|
+
angWAs[o + 2] = wAz;
|
|
297
|
+
angWBs[o + 0] = wBx;
|
|
298
|
+
angWBs[o + 1] = wBy;
|
|
299
|
+
angWBs[o + 2] = wBz;
|
|
300
|
+
const denom = axx * (wAx + wBx) + axy * (wAy + wBy) + axz * (wAz + wBz);
|
|
301
|
+
angJac[i] = denom > 0 ? 1 / denom : 0;
|
|
302
|
+
}
|
|
239
303
|
// Per-axis rows carry only the springs. Sign flip vs linear:
|
|
240
304
|
// d(angDiff)/dt = −(ω_B − ω_A)·ax.
|
|
241
305
|
const angTgt = con.cacheAngTargetVel;
|
|
@@ -244,17 +308,18 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
244
308
|
const idx = i + 3;
|
|
245
309
|
// Springs on locked axes are skipped — the limit row welds those, and
|
|
246
310
|
// double-driving a DOF overshoots every iteration (see the linear loop).
|
|
247
|
-
if (con.springEnabled[idx] &&
|
|
248
|
-
// Same deadbeat clamp as the linear springs.
|
|
311
|
+
if (con.springEnabled[idx] && angJac[i] > 0 && con.angularMin[i] !== con.angularMax[i]) {
|
|
249
312
|
const k = Math.min(con.springStiffness[idx], invDt * invDt);
|
|
250
313
|
const serr = _angDiffScratch[i] - con.equilibriumPoint[idx];
|
|
251
314
|
angTgt[i] = k * serr * dt;
|
|
315
|
+
con.cacheAngSpringMaxImp[i] = SPRING_FORCE_SLACK * Math.abs(k * serr) * dt;
|
|
252
316
|
angAct[i] = 1;
|
|
253
317
|
}
|
|
254
318
|
else {
|
|
255
319
|
angTgt[i] = 0;
|
|
256
320
|
angAct[i] = 0;
|
|
257
321
|
}
|
|
322
|
+
con.cacheAngSpringImp[i] = 0;
|
|
258
323
|
}
|
|
259
324
|
// Angular limit handling is hybrid. Small violations (the resting-cloth
|
|
260
325
|
// regime) use per-axis euler rows — they converge cleanly and keep resting
|
|
@@ -264,7 +329,10 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
264
329
|
// the asin singularity they chase phantom errors and pump angular velocity
|
|
265
330
|
// into the chain instead of converging.
|
|
266
331
|
con.cacheAngLimActive = 0;
|
|
267
|
-
|
|
332
|
+
con.cacheAngPAActive[0] = 0;
|
|
333
|
+
con.cacheAngPAActive[1] = 0;
|
|
334
|
+
con.cacheAngPAActive[2] = 0;
|
|
335
|
+
if (imA > 0 || imB > 0) {
|
|
268
336
|
const ex = _angDiffScratch[0], ey = _angDiffScratch[1], ez = _angDiffScratch[2];
|
|
269
337
|
// Free axes (min > max) follow the current angle, i.e. no correction.
|
|
270
338
|
let tx = ex, ty = ey, tz = ez;
|
|
@@ -277,19 +345,25 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
277
345
|
const errX = ex - tx, errY = ey - ty, errZ = ez - tz;
|
|
278
346
|
const maxErr = Math.max(Math.abs(errX), Math.abs(errY), Math.abs(errZ));
|
|
279
347
|
if (maxErr > 0 && maxErr < GEODESIC_THRESHOLD) {
|
|
280
|
-
// Per-axis euler limit rows
|
|
281
|
-
//
|
|
348
|
+
// Per-axis euler limit rows. Locked axes are bilateral joints; ranged
|
|
349
|
+
// axes are unilateral stops (sign-clamped accumulation) — a bilateral
|
|
350
|
+
// row on a ranged axis brakes natural recovery every substep and
|
|
351
|
+
// pumps energy into swinging cloth, and the pump grows WITH solver
|
|
352
|
+
// convergence (more iterations enforce the brake harder).
|
|
282
353
|
for (let i = 0; i < 3; i++) {
|
|
283
354
|
const err = i === 0 ? errX : i === 1 ? errY : errZ;
|
|
284
|
-
|
|
355
|
+
con.cacheAngPAImp[i] = 0;
|
|
356
|
+
if (err === 0) {
|
|
357
|
+
con.cacheAngPAActive[i] = 0;
|
|
285
358
|
continue;
|
|
286
|
-
|
|
359
|
+
}
|
|
360
|
+
let target = err * STOP_ERP * erpScale * invDt;
|
|
287
361
|
if (target > MAX_ANGULAR_CORRECTION_VEL)
|
|
288
362
|
target = MAX_ANGULAR_CORRECTION_VEL;
|
|
289
363
|
else if (target < -MAX_ANGULAR_CORRECTION_VEL)
|
|
290
364
|
target = -MAX_ANGULAR_CORRECTION_VEL;
|
|
291
|
-
|
|
292
|
-
|
|
365
|
+
con.cacheAngPATarget[i] = target;
|
|
366
|
+
con.cacheAngPAActive[i] = con.angularMin[i] === con.angularMax[i] ? 1 : 2;
|
|
293
367
|
}
|
|
294
368
|
}
|
|
295
369
|
else if (maxErr > 0) {
|
|
@@ -326,7 +400,17 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
326
400
|
lim[0] = _TA[0] * axx + _TA[4] * axy + _TA[8] * axz;
|
|
327
401
|
lim[1] = _TA[1] * axx + _TA[5] * axy + _TA[9] * axz;
|
|
328
402
|
lim[2] = _TA[2] * axx + _TA[6] * axy + _TA[10] * axz;
|
|
329
|
-
|
|
403
|
+
const gWA = con.cacheAngLimWA;
|
|
404
|
+
const gWB = con.cacheAngLimWB;
|
|
405
|
+
gWA[0] = W[a9 + 0] * lim[0] + W[a9 + 1] * lim[1] + W[a9 + 2] * lim[2];
|
|
406
|
+
gWA[1] = W[a9 + 3] * lim[0] + W[a9 + 4] * lim[1] + W[a9 + 5] * lim[2];
|
|
407
|
+
gWA[2] = W[a9 + 6] * lim[0] + W[a9 + 7] * lim[1] + W[a9 + 8] * lim[2];
|
|
408
|
+
gWB[0] = W[b9 + 0] * lim[0] + W[b9 + 1] * lim[1] + W[b9 + 2] * lim[2];
|
|
409
|
+
gWB[1] = W[b9 + 3] * lim[0] + W[b9 + 4] * lim[1] + W[b9 + 5] * lim[2];
|
|
410
|
+
gWB[2] = W[b9 + 6] * lim[0] + W[b9 + 7] * lim[1] + W[b9 + 8] * lim[2];
|
|
411
|
+
const gDenom = lim[0] * (gWA[0] + gWB[0]) + lim[1] * (gWA[1] + gWB[1]) + lim[2] * (gWA[2] + gWB[2]);
|
|
412
|
+
con.cacheAngLimJacInv = gDenom > 0 ? 1 / gDenom : 0;
|
|
413
|
+
let target = angle * STOP_ERP * erpScale * invDt;
|
|
330
414
|
if (target > MAX_ANGULAR_CORRECTION_VEL)
|
|
331
415
|
target = MAX_ANGULAR_CORRECTION_VEL;
|
|
332
416
|
con.cacheAngLimTarget = target;
|
|
@@ -337,7 +421,7 @@ function setupConstraint(con, store, dt, invDt) {
|
|
|
337
421
|
con.cacheAngLimImp = 0;
|
|
338
422
|
}
|
|
339
423
|
// ITER: read cache, compute relVel from current lv/av, apply impulse.
|
|
340
|
-
function iterateConstraint(con, lv, av, invMass
|
|
424
|
+
function iterateConstraint(con, lv, av, invMass) {
|
|
341
425
|
if (con.cacheSkip)
|
|
342
426
|
return;
|
|
343
427
|
const a = con.bodyA;
|
|
@@ -346,8 +430,6 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
346
430
|
const bi = b * 3;
|
|
347
431
|
const imA = invMass[a];
|
|
348
432
|
const imB = invMass[b];
|
|
349
|
-
const iiA = invInertia[a];
|
|
350
|
-
const iiB = invInertia[b];
|
|
351
433
|
// Linear axes — relVel at the offset point: v_pivot = v_CG + ω × r.
|
|
352
434
|
const lA = con.cacheLeverA;
|
|
353
435
|
const lB = con.cacheLeverB;
|
|
@@ -370,6 +452,8 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
370
452
|
const dvz = vBz - vAz;
|
|
371
453
|
const sprAct = con.cacheLinSpringActive;
|
|
372
454
|
const sprTgt = con.cacheLinSpringTarget;
|
|
455
|
+
const sprMax = con.cacheLinSpringMaxImp;
|
|
456
|
+
const sprImp = con.cacheLinSpringImp;
|
|
373
457
|
const limImp = con.cacheLinLimitImp;
|
|
374
458
|
for (let i = 0; i < 3; i++) {
|
|
375
459
|
if (!act[i] && !sprAct[i])
|
|
@@ -397,12 +481,25 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
397
481
|
j += dImp;
|
|
398
482
|
}
|
|
399
483
|
// Spring row: velocity-target drive; the deadbeat k-clamp at setup
|
|
400
|
-
// bounds its aggression
|
|
401
|
-
//
|
|
402
|
-
//
|
|
484
|
+
// bounds its aggression, and maxImp bounds loop-edge springs by their
|
|
485
|
+
// real force. relVel is refreshed with the limit impulse applied just
|
|
486
|
+
// above (j·denom = j / jac) — driving the spring off the stale value
|
|
487
|
+
// double-corrects the DOF and overshoots every iteration.
|
|
403
488
|
if (sprAct[i]) {
|
|
404
489
|
const relVelNow = j !== 0 ? relVel + j / jac[i] : relVel;
|
|
405
|
-
|
|
490
|
+
let dImp = (sprTgt[i] - relVelNow) * jac[i];
|
|
491
|
+
const max = sprMax[i];
|
|
492
|
+
if (max !== Infinity) {
|
|
493
|
+
const old = sprImp[i];
|
|
494
|
+
let next = old + dImp;
|
|
495
|
+
if (next > max)
|
|
496
|
+
next = max;
|
|
497
|
+
else if (next < -max)
|
|
498
|
+
next = -max;
|
|
499
|
+
dImp = next - old;
|
|
500
|
+
sprImp[i] = next;
|
|
501
|
+
}
|
|
502
|
+
j += dImp;
|
|
406
503
|
}
|
|
407
504
|
if (j === 0)
|
|
408
505
|
continue;
|
|
@@ -410,49 +507,102 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
410
507
|
lv[ai + 0] -= j * imA * axx;
|
|
411
508
|
lv[ai + 1] -= j * imA * axy;
|
|
412
509
|
lv[ai + 2] -= j * imA * axz;
|
|
413
|
-
av[ai + 0] -= j *
|
|
414
|
-
av[ai + 1] -= j *
|
|
415
|
-
av[ai + 2] -= j *
|
|
510
|
+
av[ai + 0] -= j * cA[o + 0];
|
|
511
|
+
av[ai + 1] -= j * cA[o + 1];
|
|
512
|
+
av[ai + 2] -= j * cA[o + 2];
|
|
416
513
|
}
|
|
417
514
|
if (imB > 0) {
|
|
418
515
|
lv[bi + 0] += j * imB * axx;
|
|
419
516
|
lv[bi + 1] += j * imB * axy;
|
|
420
517
|
lv[bi + 2] += j * imB * axz;
|
|
421
|
-
av[bi + 0] += j *
|
|
422
|
-
av[bi + 1] += j *
|
|
423
|
-
av[bi + 2] += j *
|
|
518
|
+
av[bi + 0] += j * cB[o + 0];
|
|
519
|
+
av[bi + 1] += j * cB[o + 1];
|
|
520
|
+
av[bi + 2] += j * cB[o + 2];
|
|
424
521
|
}
|
|
425
522
|
}
|
|
426
523
|
// Angular axes — relAv = ω_B − ω_A.
|
|
427
|
-
const angJacInv = con.cacheAngJacInv;
|
|
428
|
-
if (angJacInv === 0)
|
|
429
|
-
return;
|
|
430
524
|
const angAxes = con.cacheAngAxes;
|
|
525
|
+
const angJac = con.cacheAngJacInv;
|
|
526
|
+
const angWAs = con.cacheAngWA;
|
|
527
|
+
const angWBs = con.cacheAngWB;
|
|
431
528
|
const angTgt = con.cacheAngTargetVel;
|
|
432
529
|
const angAct = con.cacheAngActive;
|
|
433
530
|
const dax = av[bi + 0] - av[ai + 0];
|
|
434
531
|
const day = av[bi + 1] - av[ai + 1];
|
|
435
532
|
const daz = av[bi + 2] - av[ai + 2];
|
|
533
|
+
const angSprMax = con.cacheAngSpringMaxImp;
|
|
534
|
+
const angSprImp = con.cacheAngSpringImp;
|
|
436
535
|
for (let i = 0; i < 3; i++) {
|
|
437
536
|
if (!angAct[i])
|
|
438
537
|
continue;
|
|
439
538
|
const o = i * 3;
|
|
440
539
|
const axx = angAxes[o + 0], axy = angAxes[o + 1], axz = angAxes[o + 2];
|
|
441
540
|
const relAv = dax * axx + day * axy + daz * axz;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
541
|
+
let j = (angTgt[i] - relAv) * angJac[i];
|
|
542
|
+
{
|
|
543
|
+
const max = angSprMax[i];
|
|
544
|
+
const old = angSprImp[i];
|
|
545
|
+
let next = old + j;
|
|
546
|
+
if (next > max)
|
|
547
|
+
next = max;
|
|
548
|
+
else if (next < -max)
|
|
549
|
+
next = -max;
|
|
550
|
+
j = next - old;
|
|
551
|
+
angSprImp[i] = next;
|
|
552
|
+
}
|
|
445
553
|
if (j === 0)
|
|
446
554
|
continue;
|
|
447
|
-
if (
|
|
448
|
-
av[ai + 0] -= j *
|
|
449
|
-
av[ai + 1] -= j *
|
|
450
|
-
av[ai + 2] -= j *
|
|
555
|
+
if (imA > 0) {
|
|
556
|
+
av[ai + 0] -= j * angWAs[o + 0];
|
|
557
|
+
av[ai + 1] -= j * angWAs[o + 1];
|
|
558
|
+
av[ai + 2] -= j * angWAs[o + 2];
|
|
451
559
|
}
|
|
452
|
-
if (
|
|
453
|
-
av[bi + 0] += j *
|
|
454
|
-
av[bi + 1] += j *
|
|
455
|
-
av[bi + 2] += j *
|
|
560
|
+
if (imB > 0) {
|
|
561
|
+
av[bi + 0] += j * angWBs[o + 0];
|
|
562
|
+
av[bi + 1] += j * angWBs[o + 1];
|
|
563
|
+
av[bi + 2] += j * angWBs[o + 2];
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// Per-axis angular limit rows (small-violation regime), on the derived
|
|
567
|
+
// euler axes. Sign convention matches the springs: positive target reduces
|
|
568
|
+
// positive error via d(angDiff)/dt = −(ω_B − ω_A)·ax.
|
|
569
|
+
const paAct = con.cacheAngPAActive;
|
|
570
|
+
if (paAct[0] || paAct[1] || paAct[2]) {
|
|
571
|
+
const paTgt = con.cacheAngPATarget;
|
|
572
|
+
const paImp = con.cacheAngPAImp;
|
|
573
|
+
for (let i = 0; i < 3; i++) {
|
|
574
|
+
if (!paAct[i])
|
|
575
|
+
continue;
|
|
576
|
+
const o = i * 3;
|
|
577
|
+
const axx = angAxes[o + 0], axy = angAxes[o + 1], axz = angAxes[o + 2];
|
|
578
|
+
const relAv = (av[bi + 0] - av[ai + 0]) * axx +
|
|
579
|
+
(av[bi + 1] - av[ai + 1]) * axy +
|
|
580
|
+
(av[bi + 2] - av[ai + 2]) * axz;
|
|
581
|
+
const target = paTgt[i];
|
|
582
|
+
// Locked axes (act 1) are welds — full gain, like the 0.16.3 fold;
|
|
583
|
+
// softness only tempers the unilateral stops.
|
|
584
|
+
const soft = paAct[i] === 2 ? LIMIT_SOFTNESS_ANGULAR : 1.0;
|
|
585
|
+
let j = soft * (target - relAv) * angJac[i];
|
|
586
|
+
if (paAct[i] === 2) {
|
|
587
|
+
const old = paImp[i];
|
|
588
|
+
let next = old + j;
|
|
589
|
+
if (target > 0 ? next < 0 : next > 0)
|
|
590
|
+
next = 0;
|
|
591
|
+
j = next - old;
|
|
592
|
+
paImp[i] = next;
|
|
593
|
+
}
|
|
594
|
+
if (j === 0)
|
|
595
|
+
continue;
|
|
596
|
+
if (imA > 0) {
|
|
597
|
+
av[ai + 0] -= j * angWAs[o + 0];
|
|
598
|
+
av[ai + 1] -= j * angWAs[o + 1];
|
|
599
|
+
av[ai + 2] -= j * angWAs[o + 2];
|
|
600
|
+
}
|
|
601
|
+
if (imB > 0) {
|
|
602
|
+
av[bi + 0] += j * angWBs[o + 0];
|
|
603
|
+
av[bi + 1] += j * angWBs[o + 1];
|
|
604
|
+
av[bi + 2] += j * angWBs[o + 2];
|
|
605
|
+
}
|
|
456
606
|
}
|
|
457
607
|
}
|
|
458
608
|
// Geodesic limit row: drive (ω_B − ω_A)·axis toward the correction target.
|
|
@@ -465,7 +615,7 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
465
615
|
const relAv = (av[bi + 0] - av[ai + 0]) * nx +
|
|
466
616
|
(av[bi + 1] - av[ai + 1]) * ny +
|
|
467
617
|
(av[bi + 2] - av[ai + 2]) * nz;
|
|
468
|
-
let j = LIMIT_SOFTNESS_ANGULAR * (con.cacheAngLimTarget - relAv) *
|
|
618
|
+
let j = LIMIT_SOFTNESS_ANGULAR * (con.cacheAngLimTarget - relAv) * con.cacheAngLimJacInv;
|
|
469
619
|
if (con.cacheAngLimActive === 2) {
|
|
470
620
|
const old = con.cacheAngLimImp;
|
|
471
621
|
let next = old + j;
|
|
@@ -475,15 +625,17 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
475
625
|
con.cacheAngLimImp = next;
|
|
476
626
|
}
|
|
477
627
|
if (j !== 0) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
av[ai +
|
|
628
|
+
const gWA = con.cacheAngLimWA;
|
|
629
|
+
const gWB = con.cacheAngLimWB;
|
|
630
|
+
if (imA > 0) {
|
|
631
|
+
av[ai + 0] -= j * gWA[0];
|
|
632
|
+
av[ai + 1] -= j * gWA[1];
|
|
633
|
+
av[ai + 2] -= j * gWA[2];
|
|
482
634
|
}
|
|
483
|
-
if (
|
|
484
|
-
av[bi + 0] += j *
|
|
485
|
-
av[bi + 1] += j *
|
|
486
|
-
av[bi + 2] += j *
|
|
635
|
+
if (imB > 0) {
|
|
636
|
+
av[bi + 0] += j * gWB[0];
|
|
637
|
+
av[bi + 1] += j * gWB[1];
|
|
638
|
+
av[bi + 2] += j * gWB[2];
|
|
487
639
|
}
|
|
488
640
|
}
|
|
489
641
|
}
|
|
@@ -491,32 +643,38 @@ function iterateConstraint(con, lv, av, invMass, invInertia) {
|
|
|
491
643
|
// SETUP: pre-compute Jacobians, friction basis, and the bounce reference
|
|
492
644
|
// from the *initial* closing velocity (Bullet's pattern — captures restitution
|
|
493
645
|
// before iter 1 zeroes out the approach).
|
|
494
|
-
function setupContactRow(c, lv, av, invMass,
|
|
646
|
+
function setupContactRow(c, lv, av, invMass, W) {
|
|
495
647
|
const ai = c.bodyA * 3;
|
|
496
648
|
const bi = c.bodyB * 3;
|
|
649
|
+
const a9 = c.bodyA * 9;
|
|
650
|
+
const b9 = c.bodyB * 9;
|
|
497
651
|
const imA = invMass[c.bodyA];
|
|
498
652
|
const imB = invMass[c.bodyB];
|
|
499
|
-
const iiA = invInertia[c.bodyA];
|
|
500
|
-
const iiB = invInertia[c.bodyB];
|
|
501
653
|
const rAx = c.rAx, rAy = c.rAy, rAz = c.rAz;
|
|
502
654
|
const rBx = c.rBx, rBy = c.rBy, rBz = c.rBz;
|
|
503
655
|
const nx = c.nx, ny = c.ny, nz = c.nz;
|
|
504
|
-
// Normal Jacobian.
|
|
656
|
+
// Normal Jacobian. Cached vectors are tensor-multiplied I⁻¹·(r×n).
|
|
505
657
|
const cAxN = rAy * nz - rAz * ny;
|
|
506
658
|
const cAyN = rAz * nx - rAx * nz;
|
|
507
659
|
const cAzN = rAx * ny - rAy * nx;
|
|
508
660
|
const cBxN = rBy * nz - rBz * ny;
|
|
509
661
|
const cByN = rBz * nx - rBx * nz;
|
|
510
662
|
const cBzN = rBx * ny - rBy * nx;
|
|
663
|
+
const wAxN = W[a9 + 0] * cAxN + W[a9 + 1] * cAyN + W[a9 + 2] * cAzN;
|
|
664
|
+
const wAyN = W[a9 + 3] * cAxN + W[a9 + 4] * cAyN + W[a9 + 5] * cAzN;
|
|
665
|
+
const wAzN = W[a9 + 6] * cAxN + W[a9 + 7] * cAyN + W[a9 + 8] * cAzN;
|
|
666
|
+
const wBxN = W[b9 + 0] * cBxN + W[b9 + 1] * cByN + W[b9 + 2] * cBzN;
|
|
667
|
+
const wByN = W[b9 + 3] * cBxN + W[b9 + 4] * cByN + W[b9 + 5] * cBzN;
|
|
668
|
+
const wBzN = W[b9 + 6] * cBxN + W[b9 + 7] * cByN + W[b9 + 8] * cBzN;
|
|
511
669
|
const denomN = imA + imB +
|
|
512
|
-
(cAxN *
|
|
513
|
-
(cBxN *
|
|
514
|
-
c.cAxN =
|
|
515
|
-
c.cAyN =
|
|
516
|
-
c.cAzN =
|
|
517
|
-
c.cBxN =
|
|
518
|
-
c.cByN =
|
|
519
|
-
c.cBzN =
|
|
670
|
+
(cAxN * wAxN + cAyN * wAyN + cAzN * wAzN) +
|
|
671
|
+
(cBxN * wBxN + cByN * wByN + cBzN * wBzN);
|
|
672
|
+
c.cAxN = wAxN;
|
|
673
|
+
c.cAyN = wAyN;
|
|
674
|
+
c.cAzN = wAzN;
|
|
675
|
+
c.cBxN = wBxN;
|
|
676
|
+
c.cByN = wByN;
|
|
677
|
+
c.cBzN = wBzN;
|
|
520
678
|
c.jacInvN = denomN > 0 ? 1 / denomN : 0;
|
|
521
679
|
// Restitution reference, captured from initial relVelN.
|
|
522
680
|
const vAx = lv[ai + 0] + av[ai + 1] * rAz - av[ai + 2] * rAy;
|
|
@@ -569,15 +727,21 @@ function setupContactRow(c, lv, av, invMass, invInertia) {
|
|
|
569
727
|
const cBxT1 = rBy * t1z - rBz * t1y;
|
|
570
728
|
const cByT1 = rBz * t1x - rBx * t1z;
|
|
571
729
|
const cBzT1 = rBx * t1y - rBy * t1x;
|
|
730
|
+
const wAxT1 = W[a9 + 0] * cAxT1 + W[a9 + 1] * cAyT1 + W[a9 + 2] * cAzT1;
|
|
731
|
+
const wAyT1 = W[a9 + 3] * cAxT1 + W[a9 + 4] * cAyT1 + W[a9 + 5] * cAzT1;
|
|
732
|
+
const wAzT1 = W[a9 + 6] * cAxT1 + W[a9 + 7] * cAyT1 + W[a9 + 8] * cAzT1;
|
|
733
|
+
const wBxT1 = W[b9 + 0] * cBxT1 + W[b9 + 1] * cByT1 + W[b9 + 2] * cBzT1;
|
|
734
|
+
const wByT1 = W[b9 + 3] * cBxT1 + W[b9 + 4] * cByT1 + W[b9 + 5] * cBzT1;
|
|
735
|
+
const wBzT1 = W[b9 + 6] * cBxT1 + W[b9 + 7] * cByT1 + W[b9 + 8] * cBzT1;
|
|
572
736
|
const denomT1 = imA + imB +
|
|
573
|
-
(cAxT1 *
|
|
574
|
-
(cBxT1 *
|
|
575
|
-
c.cAxT1 =
|
|
576
|
-
c.cAyT1 =
|
|
577
|
-
c.cAzT1 =
|
|
578
|
-
c.cBxT1 =
|
|
579
|
-
c.cByT1 =
|
|
580
|
-
c.cBzT1 =
|
|
737
|
+
(cAxT1 * wAxT1 + cAyT1 * wAyT1 + cAzT1 * wAzT1) +
|
|
738
|
+
(cBxT1 * wBxT1 + cByT1 * wByT1 + cBzT1 * wBzT1);
|
|
739
|
+
c.cAxT1 = wAxT1;
|
|
740
|
+
c.cAyT1 = wAyT1;
|
|
741
|
+
c.cAzT1 = wAzT1;
|
|
742
|
+
c.cBxT1 = wBxT1;
|
|
743
|
+
c.cByT1 = wByT1;
|
|
744
|
+
c.cBzT1 = wBzT1;
|
|
581
745
|
c.jacInvT1 = denomT1 > 0 ? 1 / denomT1 : 0;
|
|
582
746
|
const cAxT2 = rAy * t2z - rAz * t2y;
|
|
583
747
|
const cAyT2 = rAz * t2x - rAx * t2z;
|
|
@@ -585,27 +749,31 @@ function setupContactRow(c, lv, av, invMass, invInertia) {
|
|
|
585
749
|
const cBxT2 = rBy * t2z - rBz * t2y;
|
|
586
750
|
const cByT2 = rBz * t2x - rBx * t2z;
|
|
587
751
|
const cBzT2 = rBx * t2y - rBy * t2x;
|
|
752
|
+
const wAxT2 = W[a9 + 0] * cAxT2 + W[a9 + 1] * cAyT2 + W[a9 + 2] * cAzT2;
|
|
753
|
+
const wAyT2 = W[a9 + 3] * cAxT2 + W[a9 + 4] * cAyT2 + W[a9 + 5] * cAzT2;
|
|
754
|
+
const wAzT2 = W[a9 + 6] * cAxT2 + W[a9 + 7] * cAyT2 + W[a9 + 8] * cAzT2;
|
|
755
|
+
const wBxT2 = W[b9 + 0] * cBxT2 + W[b9 + 1] * cByT2 + W[b9 + 2] * cBzT2;
|
|
756
|
+
const wByT2 = W[b9 + 3] * cBxT2 + W[b9 + 4] * cByT2 + W[b9 + 5] * cBzT2;
|
|
757
|
+
const wBzT2 = W[b9 + 6] * cBxT2 + W[b9 + 7] * cByT2 + W[b9 + 8] * cBzT2;
|
|
588
758
|
const denomT2 = imA + imB +
|
|
589
|
-
(cAxT2 *
|
|
590
|
-
(cBxT2 *
|
|
591
|
-
c.cAxT2 =
|
|
592
|
-
c.cAyT2 =
|
|
593
|
-
c.cAzT2 =
|
|
594
|
-
c.cBxT2 =
|
|
595
|
-
c.cByT2 =
|
|
596
|
-
c.cBzT2 =
|
|
759
|
+
(cAxT2 * wAxT2 + cAyT2 * wAyT2 + cAzT2 * wAzT2) +
|
|
760
|
+
(cBxT2 * wBxT2 + cByT2 * wByT2 + cBzT2 * wBzT2);
|
|
761
|
+
c.cAxT2 = wAxT2;
|
|
762
|
+
c.cAyT2 = wAyT2;
|
|
763
|
+
c.cAzT2 = wAzT2;
|
|
764
|
+
c.cBxT2 = wBxT2;
|
|
765
|
+
c.cByT2 = wByT2;
|
|
766
|
+
c.cBzT2 = wBzT2;
|
|
597
767
|
c.jacInvT2 = denomT2 > 0 ? 1 / denomT2 : 0;
|
|
598
768
|
}
|
|
599
769
|
// ITER: one push-only normal row + two Coulomb friction rows. Friction
|
|
600
770
|
// bound depends on the *current* applied normal impulse, so it tightens
|
|
601
771
|
// as the normal row converges.
|
|
602
|
-
function iterateContactRow(c, lv, av, invMass
|
|
772
|
+
function iterateContactRow(c, lv, av, invMass) {
|
|
603
773
|
const imA = invMass[c.bodyA];
|
|
604
774
|
const imB = invMass[c.bodyB];
|
|
605
775
|
if (imA === 0 && imB === 0)
|
|
606
776
|
return;
|
|
607
|
-
const iiA = invInertia[c.bodyA];
|
|
608
|
-
const iiB = invInertia[c.bodyB];
|
|
609
777
|
const ai = c.bodyA * 3, bi = c.bodyB * 3;
|
|
610
778
|
const rAx = c.rAx, rAy = c.rAy, rAz = c.rAz;
|
|
611
779
|
const rBx = c.rBx, rBy = c.rBy, rBz = c.rBz;
|
|
@@ -638,17 +806,17 @@ function iterateContactRow(c, lv, av, invMass, invInertia) {
|
|
|
638
806
|
lv[ai + 0] -= dImpN * imA * nx;
|
|
639
807
|
lv[ai + 1] -= dImpN * imA * ny;
|
|
640
808
|
lv[ai + 2] -= dImpN * imA * nz;
|
|
641
|
-
av[ai + 0] -= dImpN *
|
|
642
|
-
av[ai + 1] -= dImpN *
|
|
643
|
-
av[ai + 2] -= dImpN *
|
|
809
|
+
av[ai + 0] -= dImpN * cAxN;
|
|
810
|
+
av[ai + 1] -= dImpN * cAyN;
|
|
811
|
+
av[ai + 2] -= dImpN * cAzN;
|
|
644
812
|
}
|
|
645
813
|
if (imB > 0) {
|
|
646
814
|
lv[bi + 0] += dImpN * imB * nx;
|
|
647
815
|
lv[bi + 1] += dImpN * imB * ny;
|
|
648
816
|
lv[bi + 2] += dImpN * imB * nz;
|
|
649
|
-
av[bi + 0] += dImpN *
|
|
650
|
-
av[bi + 1] += dImpN *
|
|
651
|
-
av[bi + 2] += dImpN *
|
|
817
|
+
av[bi + 0] += dImpN * cBxN;
|
|
818
|
+
av[bi + 1] += dImpN * cByN;
|
|
819
|
+
av[bi + 2] += dImpN * cBzN;
|
|
652
820
|
}
|
|
653
821
|
}
|
|
654
822
|
}
|
|
@@ -666,10 +834,10 @@ function iterateContactRow(c, lv, av, invMass, invInertia) {
|
|
|
666
834
|
const dvx2 = vBx2 - vAx2;
|
|
667
835
|
const dvy2 = vBy2 - vAy2;
|
|
668
836
|
const dvz2 = vBz2 - vAz2;
|
|
669
|
-
applyFrictionTangent(c, ai, bi, dvx2, dvy2, dvz2, c.t1x, c.t1y, c.t1z, c.cAxT1, c.cAyT1, c.cAzT1, c.cBxT1, c.cByT1, c.cBzT1, c.jacInvT1, muNormal, imA, imB,
|
|
670
|
-
applyFrictionTangent(c, ai, bi, dvx2, dvy2, dvz2, c.t2x, c.t2y, c.t2z, c.cAxT2, c.cAyT2, c.cAzT2, c.cBxT2, c.cByT2, c.cBzT2, c.jacInvT2, muNormal, imA, imB,
|
|
837
|
+
applyFrictionTangent(c, ai, bi, dvx2, dvy2, dvz2, c.t1x, c.t1y, c.t1z, c.cAxT1, c.cAyT1, c.cAzT1, c.cBxT1, c.cByT1, c.cBzT1, c.jacInvT1, muNormal, imA, imB, lv, av, 1);
|
|
838
|
+
applyFrictionTangent(c, ai, bi, dvx2, dvy2, dvz2, c.t2x, c.t2y, c.t2z, c.cAxT2, c.cAyT2, c.cAzT2, c.cBxT2, c.cByT2, c.cBzT2, c.jacInvT2, muNormal, imA, imB, lv, av, 2);
|
|
671
839
|
}
|
|
672
|
-
function applyFrictionTangent(c, ai, bi, dvx, dvy, dvz, tx, ty, tz, cAx, cAy, cAz, cBx, cBy, cBz, jacInv, muNormal, imA, imB,
|
|
840
|
+
function applyFrictionTangent(c, ai, bi, dvx, dvy, dvz, tx, ty, tz, cAx, cAy, cAz, cBx, cBy, cBz, jacInv, muNormal, imA, imB, lv, av, slot) {
|
|
673
841
|
if (jacInv <= 0)
|
|
674
842
|
return;
|
|
675
843
|
const relVel = dvx * tx + dvy * ty + dvz * tz;
|
|
@@ -694,17 +862,17 @@ function applyFrictionTangent(c, ai, bi, dvx, dvy, dvz, tx, ty, tz, cAx, cAy, cA
|
|
|
694
862
|
lv[ai + 0] -= dImp * imA * tx;
|
|
695
863
|
lv[ai + 1] -= dImp * imA * ty;
|
|
696
864
|
lv[ai + 2] -= dImp * imA * tz;
|
|
697
|
-
av[ai + 0] -= dImp *
|
|
698
|
-
av[ai + 1] -= dImp *
|
|
699
|
-
av[ai + 2] -= dImp *
|
|
865
|
+
av[ai + 0] -= dImp * cAx;
|
|
866
|
+
av[ai + 1] -= dImp * cAy;
|
|
867
|
+
av[ai + 2] -= dImp * cAz;
|
|
700
868
|
}
|
|
701
869
|
if (imB > 0) {
|
|
702
870
|
lv[bi + 0] += dImp * imB * tx;
|
|
703
871
|
lv[bi + 1] += dImp * imB * ty;
|
|
704
872
|
lv[bi + 2] += dImp * imB * tz;
|
|
705
|
-
av[bi + 0] += dImp *
|
|
706
|
-
av[bi + 1] += dImp *
|
|
707
|
-
av[bi + 2] += dImp *
|
|
873
|
+
av[bi + 0] += dImp * cBx;
|
|
874
|
+
av[bi + 1] += dImp * cBy;
|
|
875
|
+
av[bi + 2] += dImp * cBz;
|
|
708
876
|
}
|
|
709
877
|
}
|
|
710
878
|
function buildBodyMat(store, i, out) {
|
package/dist/pmx-loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pmx-loader.d.ts","sourceRoot":"","sources":["../src/pmx-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAWN,MAAM,SAAS,CAAA;AAGhB,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEzE,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,mBAAmB,CAAI;IAC/B,OAAO,CAAC,eAAe,CAAI;IAC3B,OAAO,CAAC,gBAAgB,CAAI;IAC5B,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,kBAAkB,CAAI;IAC9B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAe;IAE/B,OAAO;IAQP,OAAO,CAAC,IAAI;WAMC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAI9C,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK;WAIpC,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAKxF,OAAO,CAAC,KAAK;IAiBb,OAAO,CAAC,WAAW;IA+CnB,OAAO,CAAC,aAAa;IA+FrB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"pmx-loader.d.ts","sourceRoot":"","sources":["../src/pmx-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAWN,MAAM,SAAS,CAAA;AAGhB,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEzE,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,mBAAmB,CAAI;IAC/B,OAAO,CAAC,eAAe,CAAI;IAC3B,OAAO,CAAC,gBAAgB,CAAI;IAC5B,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,kBAAkB,CAAI;IAC9B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAe;IAE/B,OAAO;IAQP,OAAO,CAAC,IAAI;WAMC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAI9C,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK;WAIpC,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAKxF,OAAO,CAAC,KAAK;IAiBb,OAAO,CAAC,WAAW;IA+CnB,OAAO,CAAC,aAAa;IA+FrB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,cAAc;IAqEtB,OAAO,CAAC,UAAU;IAsKlB,OAAO,CAAC,WAAW;IA2JnB,OAAO,CAAC,iBAAiB;IAgDzB,OAAO,CAAC,gBAAgB;IA+FxB,OAAO,CAAC,WAAW;IAmGnB,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,OAAO;IAkJf,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,OAAO;IAmBf,OAAO,CAAC,QAAQ;CAIjB"}
|