reze-engine 0.13.0 → 0.13.2
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 +32 -29
- package/dist/ik-solver.d.ts +5 -6
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +163 -98
- package/dist/math.d.ts +20 -0
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +300 -0
- package/dist/model.d.ts +9 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +113 -52
- package/dist/physics.d.ts.map +1 -1
- package/dist/physics.js +27 -19
- package/package.json +1 -1
- package/src/ik-solver.ts +164 -111
- package/src/math.ts +291 -0
- package/src/model.ts +124 -60
- package/src/physics.ts +31 -23
package/dist/math.js
CHANGED
|
@@ -52,6 +52,48 @@ export class Vec3 {
|
|
|
52
52
|
this.z = other.z;
|
|
53
53
|
return this;
|
|
54
54
|
}
|
|
55
|
+
setXYZ(x, y, z) {
|
|
56
|
+
this.x = x;
|
|
57
|
+
this.y = y;
|
|
58
|
+
this.z = z;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
// out = a - b (no allocation)
|
|
62
|
+
static subtractInto(a, b, out) {
|
|
63
|
+
out.x = a.x - b.x;
|
|
64
|
+
out.y = a.y - b.y;
|
|
65
|
+
out.z = a.z - b.z;
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
// out = a × b (no allocation). Safe when out === a or out === b.
|
|
69
|
+
static crossInto(a, b, out) {
|
|
70
|
+
const ax = a.x, ay = a.y, az = a.z;
|
|
71
|
+
const bx = b.x, by = b.y, bz = b.z;
|
|
72
|
+
out.x = ay * bz - az * by;
|
|
73
|
+
out.y = az * bx - ax * bz;
|
|
74
|
+
out.z = ax * by - ay * bx;
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
// Read translation from Mat4 values array (column-major) into out.
|
|
78
|
+
static setFromMat4Translation(m, out) {
|
|
79
|
+
out.x = m[12];
|
|
80
|
+
out.y = m[13];
|
|
81
|
+
out.z = m[14];
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
// Transform normal by the upper-left 3x3 of a Mat4 (column-major) into out.
|
|
85
|
+
// Safe when out === normal.
|
|
86
|
+
static transformMat4RotationInto(normal, m, out) {
|
|
87
|
+
const nx = normal.x, ny = normal.y, nz = normal.z;
|
|
88
|
+
out.x = m[0] * nx + m[4] * ny + m[8] * nz;
|
|
89
|
+
out.y = m[1] * nx + m[5] * ny + m[9] * nz;
|
|
90
|
+
out.z = m[2] * nx + m[6] * ny + m[10] * nz;
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
// In-place normalize returning length squared info via Vec3. Alias for normalize() but explicit.
|
|
94
|
+
normalizeInPlace() {
|
|
95
|
+
return this.normalize();
|
|
96
|
+
}
|
|
55
97
|
}
|
|
56
98
|
export class Quat {
|
|
57
99
|
constructor(x, y, z, w) {
|
|
@@ -158,6 +200,78 @@ export class Quat {
|
|
|
158
200
|
const s1 = Math.sin(theta) / sinTheta0;
|
|
159
201
|
return new Quat(s0 * a.x + s1 * bx, s0 * a.y + s1 * by, s0 * a.z + s1 * bz, s0 * a.w + s1 * bw);
|
|
160
202
|
}
|
|
203
|
+
// out = a * b (quaternion multiplication, rotation composition).
|
|
204
|
+
// Safe when out === a or out === b.
|
|
205
|
+
static multiplyInto(a, b, out) {
|
|
206
|
+
const ax = a.x, ay = a.y, az = a.z, aw = a.w;
|
|
207
|
+
const bx = b.x, by = b.y, bz = b.z, bw = b.w;
|
|
208
|
+
out.x = aw * bx + ax * bw + ay * bz - az * by;
|
|
209
|
+
out.y = aw * by - ax * bz + ay * bw + az * bx;
|
|
210
|
+
out.z = aw * bz + ax * by - ay * bx + az * bw;
|
|
211
|
+
out.w = aw * bw - ax * bx - ay * by - az * bz;
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
// out = quat from axis (unnormalized) and angle.
|
|
215
|
+
static fromAxisAngleInto(ax, ay, az, angle, out) {
|
|
216
|
+
const len = Math.sqrt(ax * ax + ay * ay + az * az);
|
|
217
|
+
const invLen = len > 0 ? 1 / len : 0;
|
|
218
|
+
const nx = ax * invLen, ny = ay * invLen, nz = az * invLen;
|
|
219
|
+
const half = angle * 0.5;
|
|
220
|
+
const s = Math.sin(half), c = Math.cos(half);
|
|
221
|
+
out.x = nx * s;
|
|
222
|
+
out.y = ny * s;
|
|
223
|
+
out.z = nz * s;
|
|
224
|
+
out.w = c;
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
// out = slerp(a, b, t). Safe when out === a or out === b.
|
|
228
|
+
static slerpInto(a, b, t, out) {
|
|
229
|
+
let cos = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
|
230
|
+
let bx = b.x, by = b.y, bz = b.z, bw = b.w;
|
|
231
|
+
if (cos < 0) {
|
|
232
|
+
cos = -cos;
|
|
233
|
+
bx = -bx;
|
|
234
|
+
by = -by;
|
|
235
|
+
bz = -bz;
|
|
236
|
+
bw = -bw;
|
|
237
|
+
}
|
|
238
|
+
if (cos > 0.9995) {
|
|
239
|
+
const x = a.x + t * (bx - a.x);
|
|
240
|
+
const y = a.y + t * (by - a.y);
|
|
241
|
+
const z = a.z + t * (bz - a.z);
|
|
242
|
+
const w = a.w + t * (bw - a.w);
|
|
243
|
+
const invLen = 1 / Math.hypot(x, y, z, w);
|
|
244
|
+
out.x = x * invLen;
|
|
245
|
+
out.y = y * invLen;
|
|
246
|
+
out.z = z * invLen;
|
|
247
|
+
out.w = w * invLen;
|
|
248
|
+
return out;
|
|
249
|
+
}
|
|
250
|
+
const theta0 = Math.acos(cos);
|
|
251
|
+
const sinTheta0 = Math.sin(theta0);
|
|
252
|
+
const theta = theta0 * t;
|
|
253
|
+
const s0 = Math.sin(theta0 - theta) / sinTheta0;
|
|
254
|
+
const s1 = Math.sin(theta) / sinTheta0;
|
|
255
|
+
out.x = s0 * a.x + s1 * bx;
|
|
256
|
+
out.y = s0 * a.y + s1 * by;
|
|
257
|
+
out.z = s0 * a.z + s1 * bz;
|
|
258
|
+
out.w = s0 * a.w + s1 * bw;
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
setXYZW(x, y, z, w) {
|
|
262
|
+
this.x = x;
|
|
263
|
+
this.y = y;
|
|
264
|
+
this.z = z;
|
|
265
|
+
this.w = w;
|
|
266
|
+
return this;
|
|
267
|
+
}
|
|
268
|
+
setIdentity() {
|
|
269
|
+
this.x = 0;
|
|
270
|
+
this.y = 0;
|
|
271
|
+
this.z = 0;
|
|
272
|
+
this.w = 1;
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
161
275
|
// Convert Euler angles to quaternion (ZXY order, left-handed, PMX format)
|
|
162
276
|
static fromEuler(rotX, rotY, rotZ) {
|
|
163
277
|
const cx = Math.cos(rotX * 0.5);
|
|
@@ -297,6 +411,124 @@ export class Mat4 {
|
|
|
297
411
|
clone() {
|
|
298
412
|
return new Mat4(this.values.slice());
|
|
299
413
|
}
|
|
414
|
+
// Write rotation matrix from quaternion into existing Float32Array (column-major).
|
|
415
|
+
static fromQuatInto(x, y, z, w, out, offset = 0) {
|
|
416
|
+
const x2 = x + x, y2 = y + y, z2 = z + z;
|
|
417
|
+
const xx = x * x2, xy = x * y2, xz = x * z2;
|
|
418
|
+
const yy = y * y2, yz = y * z2, zz = z * z2;
|
|
419
|
+
const wx = w * x2, wy = w * y2, wz = w * z2;
|
|
420
|
+
out[offset + 0] = 1 - (yy + zz);
|
|
421
|
+
out[offset + 1] = xy + wz;
|
|
422
|
+
out[offset + 2] = xz - wy;
|
|
423
|
+
out[offset + 3] = 0;
|
|
424
|
+
out[offset + 4] = xy - wz;
|
|
425
|
+
out[offset + 5] = 1 - (xx + zz);
|
|
426
|
+
out[offset + 6] = yz + wx;
|
|
427
|
+
out[offset + 7] = 0;
|
|
428
|
+
out[offset + 8] = xz + wy;
|
|
429
|
+
out[offset + 9] = yz - wx;
|
|
430
|
+
out[offset + 10] = 1 - (xx + yy);
|
|
431
|
+
out[offset + 11] = 0;
|
|
432
|
+
out[offset + 12] = 0;
|
|
433
|
+
out[offset + 13] = 0;
|
|
434
|
+
out[offset + 14] = 0;
|
|
435
|
+
out[offset + 15] = 1;
|
|
436
|
+
}
|
|
437
|
+
// Fused local transform: out = T(bindT) · R(quat) · T(localT).
|
|
438
|
+
// Result translation = bindT + R * localT; rotation column block = R.
|
|
439
|
+
// Column-major. Zero allocations.
|
|
440
|
+
static localTransformInto(bx, by, bz, qx, qy, qz, qw, lx, ly, lz, out) {
|
|
441
|
+
const x2 = qx + qx, y2 = qy + qy, z2 = qz + qz;
|
|
442
|
+
const xx = qx * x2, xy = qx * y2, xz = qx * z2;
|
|
443
|
+
const yy = qy * y2, yz = qy * z2, zz = qz * z2;
|
|
444
|
+
const wx = qw * x2, wy = qw * y2, wz = qw * z2;
|
|
445
|
+
const m00 = 1 - (yy + zz), m01 = xy + wz, m02 = xz - wy;
|
|
446
|
+
const m10 = xy - wz, m11 = 1 - (xx + zz), m12 = yz + wx;
|
|
447
|
+
const m20 = xz + wy, m21 = yz - wx, m22 = 1 - (xx + yy);
|
|
448
|
+
out[0] = m00;
|
|
449
|
+
out[1] = m01;
|
|
450
|
+
out[2] = m02;
|
|
451
|
+
out[3] = 0;
|
|
452
|
+
out[4] = m10;
|
|
453
|
+
out[5] = m11;
|
|
454
|
+
out[6] = m12;
|
|
455
|
+
out[7] = 0;
|
|
456
|
+
out[8] = m20;
|
|
457
|
+
out[9] = m21;
|
|
458
|
+
out[10] = m22;
|
|
459
|
+
out[11] = 0;
|
|
460
|
+
out[12] = bx + m00 * lx + m10 * ly + m20 * lz;
|
|
461
|
+
out[13] = by + m01 * lx + m11 * ly + m21 * lz;
|
|
462
|
+
out[14] = bz + m02 * lx + m12 * ly + m22 * lz;
|
|
463
|
+
out[15] = 1;
|
|
464
|
+
}
|
|
465
|
+
// Write position+rotation transform into existing Float32Array.
|
|
466
|
+
static fromPositionRotationInto(px, py, pz, qx, qy, qz, qw, out) {
|
|
467
|
+
Mat4.fromQuatInto(qx, qy, qz, qw, out, 0);
|
|
468
|
+
out[12] = px;
|
|
469
|
+
out[13] = py;
|
|
470
|
+
out[14] = pz;
|
|
471
|
+
}
|
|
472
|
+
// In-place 4x4 inverse into out array. Returns true on success, false if singular (out untouched).
|
|
473
|
+
static inverseInto(m, out) {
|
|
474
|
+
const a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3];
|
|
475
|
+
const a10 = m[4], a11 = m[5], a12 = m[6], a13 = m[7];
|
|
476
|
+
const a20 = m[8], a21 = m[9], a22 = m[10], a23 = m[11];
|
|
477
|
+
const a30 = m[12], a31 = m[13], a32 = m[14], a33 = m[15];
|
|
478
|
+
const b00 = a00 * a11 - a01 * a10;
|
|
479
|
+
const b01 = a00 * a12 - a02 * a10;
|
|
480
|
+
const b02 = a00 * a13 - a03 * a10;
|
|
481
|
+
const b03 = a01 * a12 - a02 * a11;
|
|
482
|
+
const b04 = a01 * a13 - a03 * a11;
|
|
483
|
+
const b05 = a02 * a13 - a03 * a12;
|
|
484
|
+
const b06 = a20 * a31 - a21 * a30;
|
|
485
|
+
const b07 = a20 * a32 - a22 * a30;
|
|
486
|
+
const b08 = a20 * a33 - a23 * a30;
|
|
487
|
+
const b09 = a21 * a32 - a22 * a31;
|
|
488
|
+
const b10 = a21 * a33 - a23 * a31;
|
|
489
|
+
const b11 = a22 * a33 - a23 * a32;
|
|
490
|
+
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
491
|
+
if (Math.abs(det) < 1e-10)
|
|
492
|
+
return false;
|
|
493
|
+
det = 1.0 / det;
|
|
494
|
+
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
|
|
495
|
+
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
|
|
496
|
+
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
|
|
497
|
+
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
|
|
498
|
+
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
|
|
499
|
+
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
|
|
500
|
+
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
|
|
501
|
+
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
|
|
502
|
+
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
|
|
503
|
+
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
|
|
504
|
+
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
|
|
505
|
+
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
|
|
506
|
+
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
|
|
507
|
+
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
|
|
508
|
+
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
|
|
509
|
+
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
|
|
510
|
+
return true;
|
|
511
|
+
}
|
|
512
|
+
// Copy only the rotation (upper-left 3x3) of src into dst, zero out translation, identity w.
|
|
513
|
+
// Column-major in both.
|
|
514
|
+
static copyRotationInto(src, dst) {
|
|
515
|
+
dst[0] = src[0];
|
|
516
|
+
dst[1] = src[1];
|
|
517
|
+
dst[2] = src[2];
|
|
518
|
+
dst[3] = 0;
|
|
519
|
+
dst[4] = src[4];
|
|
520
|
+
dst[5] = src[5];
|
|
521
|
+
dst[6] = src[6];
|
|
522
|
+
dst[7] = 0;
|
|
523
|
+
dst[8] = src[8];
|
|
524
|
+
dst[9] = src[9];
|
|
525
|
+
dst[10] = src[10];
|
|
526
|
+
dst[11] = 0;
|
|
527
|
+
dst[12] = 0;
|
|
528
|
+
dst[13] = 0;
|
|
529
|
+
dst[14] = 0;
|
|
530
|
+
dst[15] = 1;
|
|
531
|
+
}
|
|
300
532
|
static fromQuat(x, y, z, w) {
|
|
301
533
|
// Column-major rotation matrix from quaternion (matches glMatrix/WGSL)
|
|
302
534
|
const out = new Float32Array(16);
|
|
@@ -338,6 +570,48 @@ export class Mat4 {
|
|
|
338
570
|
toQuat() {
|
|
339
571
|
return Mat4.toQuatFromArray(this.values, 0);
|
|
340
572
|
}
|
|
573
|
+
// Extract quaternion from matrix array into an existing Quat (no allocation).
|
|
574
|
+
static toQuatFromArrayInto(m, offset, out) {
|
|
575
|
+
const m00 = m[offset + 0], m01 = m[offset + 4], m02 = m[offset + 8];
|
|
576
|
+
const m10 = m[offset + 1], m11 = m[offset + 5], m12 = m[offset + 9];
|
|
577
|
+
const m20 = m[offset + 2], m21 = m[offset + 6], m22 = m[offset + 10];
|
|
578
|
+
const trace = m00 + m11 + m22;
|
|
579
|
+
let x = 0, y = 0, z = 0, w = 1;
|
|
580
|
+
if (trace > 0) {
|
|
581
|
+
const s = Math.sqrt(trace + 1.0) * 2;
|
|
582
|
+
w = 0.25 * s;
|
|
583
|
+
x = (m21 - m12) / s;
|
|
584
|
+
y = (m02 - m20) / s;
|
|
585
|
+
z = (m10 - m01) / s;
|
|
586
|
+
}
|
|
587
|
+
else if (m00 > m11 && m00 > m22) {
|
|
588
|
+
const s = Math.sqrt(1.0 + m00 - m11 - m22) * 2;
|
|
589
|
+
w = (m21 - m12) / s;
|
|
590
|
+
x = 0.25 * s;
|
|
591
|
+
y = (m01 + m10) / s;
|
|
592
|
+
z = (m02 + m20) / s;
|
|
593
|
+
}
|
|
594
|
+
else if (m11 > m22) {
|
|
595
|
+
const s = Math.sqrt(1.0 + m11 - m00 - m22) * 2;
|
|
596
|
+
w = (m02 - m20) / s;
|
|
597
|
+
x = (m01 + m10) / s;
|
|
598
|
+
y = 0.25 * s;
|
|
599
|
+
z = (m12 + m21) / s;
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
const s = Math.sqrt(1.0 + m22 - m00 - m11) * 2;
|
|
603
|
+
w = (m10 - m01) / s;
|
|
604
|
+
x = (m02 + m20) / s;
|
|
605
|
+
y = (m12 + m21) / s;
|
|
606
|
+
z = 0.25 * s;
|
|
607
|
+
}
|
|
608
|
+
const invLen = 1 / Math.hypot(x, y, z, w);
|
|
609
|
+
out.x = x * invLen;
|
|
610
|
+
out.y = y * invLen;
|
|
611
|
+
out.z = z * invLen;
|
|
612
|
+
out.w = w * invLen;
|
|
613
|
+
return out;
|
|
614
|
+
}
|
|
341
615
|
// Static method to extract quaternion from matrix array (avoids creating Mat4 object)
|
|
342
616
|
static toQuatFromArray(m, offset) {
|
|
343
617
|
const m00 = m[offset + 0], m01 = m[offset + 4], m02 = m[offset + 8];
|
|
@@ -452,3 +726,29 @@ export class Mat4 {
|
|
|
452
726
|
return new Mat4(out);
|
|
453
727
|
}
|
|
454
728
|
}
|
|
729
|
+
// Preallocated scratch instances for hot paths. Each subsystem should use its own
|
|
730
|
+
// slot to avoid cross-call stomping. Bump the count if more call sites need scratch.
|
|
731
|
+
export const scratchMat4Values = [
|
|
732
|
+
new Float32Array(16),
|
|
733
|
+
new Float32Array(16),
|
|
734
|
+
new Float32Array(16),
|
|
735
|
+
new Float32Array(16),
|
|
736
|
+
new Float32Array(16),
|
|
737
|
+
new Float32Array(16),
|
|
738
|
+
];
|
|
739
|
+
export const scratchVec3 = [
|
|
740
|
+
new Vec3(0, 0, 0),
|
|
741
|
+
new Vec3(0, 0, 0),
|
|
742
|
+
new Vec3(0, 0, 0),
|
|
743
|
+
new Vec3(0, 0, 0),
|
|
744
|
+
new Vec3(0, 0, 0),
|
|
745
|
+
new Vec3(0, 0, 0),
|
|
746
|
+
new Vec3(0, 0, 0),
|
|
747
|
+
new Vec3(0, 0, 0),
|
|
748
|
+
];
|
|
749
|
+
export const scratchQuat = [
|
|
750
|
+
new Quat(0, 0, 0, 1),
|
|
751
|
+
new Quat(0, 0, 0, 1),
|
|
752
|
+
new Quat(0, 0, 0, 1),
|
|
753
|
+
new Quat(0, 0, 0, 1),
|
|
754
|
+
];
|
package/dist/model.d.ts
CHANGED
|
@@ -96,6 +96,10 @@ export declare class Model {
|
|
|
96
96
|
private _name;
|
|
97
97
|
get name(): string;
|
|
98
98
|
setName(value: string): void;
|
|
99
|
+
get position(): Vec3;
|
|
100
|
+
get rotation(): Quat;
|
|
101
|
+
setPosition(position: Vec3): void;
|
|
102
|
+
setRotation(rotation: Quat): void;
|
|
99
103
|
private vertexData;
|
|
100
104
|
private baseVertexData;
|
|
101
105
|
private vertexCount;
|
|
@@ -110,8 +114,11 @@ export declare class Model {
|
|
|
110
114
|
private runtimeSkeleton;
|
|
111
115
|
private runtimeMorph;
|
|
112
116
|
private morphsDirty;
|
|
113
|
-
private
|
|
114
|
-
private
|
|
117
|
+
private _position;
|
|
118
|
+
private _rotation;
|
|
119
|
+
private rootMatrixValues;
|
|
120
|
+
private rootMatrixDirty;
|
|
121
|
+
private rootIsIdentity;
|
|
115
122
|
private skinMatricesArray?;
|
|
116
123
|
private tweenState;
|
|
117
124
|
private tweenTimeMs;
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
package/dist/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Mat4, Quat, Vec3 } from "./math";
|
|
1
|
+
import { Mat4, Quat, Vec3, scratchMat4Values, scratchQuat } from "./math";
|
|
2
2
|
import { Engine } from "./engine";
|
|
3
3
|
import { joinAssetPath } from "./asset-reader";
|
|
4
4
|
import { IKSolverSystem } from "./ik-solver";
|
|
@@ -13,6 +13,23 @@ export class Model {
|
|
|
13
13
|
setName(value) {
|
|
14
14
|
this._name = value;
|
|
15
15
|
}
|
|
16
|
+
// Root transform public API. Instant setters — no tween baked in; wrap in
|
|
17
|
+
// your own lerp if you need smoothing. Changes are applied on the next
|
|
18
|
+
// getSkinMatrices() call (once per frame during rendering).
|
|
19
|
+
get position() {
|
|
20
|
+
return this._position;
|
|
21
|
+
}
|
|
22
|
+
get rotation() {
|
|
23
|
+
return this._rotation;
|
|
24
|
+
}
|
|
25
|
+
setPosition(position) {
|
|
26
|
+
this._position.set(position);
|
|
27
|
+
this.rootMatrixDirty = true;
|
|
28
|
+
}
|
|
29
|
+
setRotation(rotation) {
|
|
30
|
+
this._rotation.set(rotation);
|
|
31
|
+
this.rootMatrixDirty = true;
|
|
32
|
+
}
|
|
16
33
|
/** Called by Engine when registering the model; enables loadVmd to resolve relative paths for folder uploads. */
|
|
17
34
|
setAssetContext(reader, basePath) {
|
|
18
35
|
this.assetReader = reader;
|
|
@@ -26,9 +43,15 @@ export class Model {
|
|
|
26
43
|
this.rigidbodies = [];
|
|
27
44
|
this.joints = [];
|
|
28
45
|
this.morphsDirty = false; // Flag indicating if morphs need to be applied
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
// Root transform — model's placement in world space, independent of bones.
|
|
47
|
+
// Folded into skin matrices (see getSkinMatrices) so every pass (main VS,
|
|
48
|
+
// shadow VS, any future skinned pass) sees it without per-shader plumbing.
|
|
49
|
+
// Skip-when-identity flag avoids the extra mat mul per bone when unused.
|
|
50
|
+
this._position = Vec3.zeros();
|
|
51
|
+
this._rotation = Quat.identity();
|
|
52
|
+
this.rootMatrixValues = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
53
|
+
this.rootMatrixDirty = false;
|
|
54
|
+
this.rootIsIdentity = true;
|
|
32
55
|
this.tweenTimeMs = 0; // Time tracking for tweens (milliseconds)
|
|
33
56
|
// Animation: state and multiple slots (idle, walk, attack, etc.); commit/rollback for action-game style
|
|
34
57
|
this.animationState = new AnimationState();
|
|
@@ -426,12 +449,32 @@ export class Model {
|
|
|
426
449
|
this.skinMatricesArray = new Float32Array(boneCount * 16);
|
|
427
450
|
}
|
|
428
451
|
const skinMatrices = this.skinMatricesArray;
|
|
429
|
-
//
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
452
|
+
// Rebuild root matrix + cache identity-shortcut flag only when pos/rot changed.
|
|
453
|
+
if (this.rootMatrixDirty) {
|
|
454
|
+
const p = this._position, r = this._rotation;
|
|
455
|
+
Mat4.fromPositionRotationInto(p.x, p.y, p.z, r.x, r.y, r.z, r.w, this.rootMatrixValues);
|
|
456
|
+
this.rootIsIdentity =
|
|
457
|
+
p.x === 0 && p.y === 0 && p.z === 0 &&
|
|
458
|
+
r.x === 0 && r.y === 0 && r.z === 0 && r.w === 1;
|
|
459
|
+
this.rootMatrixDirty = false;
|
|
460
|
+
}
|
|
461
|
+
if (this.rootIsIdentity) {
|
|
462
|
+
// skinMatrix = worldMatrix × inverseBindMatrix
|
|
463
|
+
for (let i = 0; i < boneCount; i++) {
|
|
464
|
+
const off = i * 16;
|
|
465
|
+
Mat4.multiplyArrays(worldMats[i].values, 0, invBindMats, off, skinMatrices, off);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
// skinMatrix = rootMatrix × worldMatrix × inverseBindMatrix
|
|
470
|
+
// Two-mul path. scratchMat4Values[1] — [0] is owned by computeWorldMatrices.
|
|
471
|
+
const rootVals = this.rootMatrixValues;
|
|
472
|
+
const tmp = scratchMat4Values[1];
|
|
473
|
+
for (let i = 0; i < boneCount; i++) {
|
|
474
|
+
const off = i * 16;
|
|
475
|
+
Mat4.multiplyArrays(rootVals, 0, worldMats[i].values, 0, tmp, 0);
|
|
476
|
+
Mat4.multiplyArrays(tmp, 0, invBindMats, off, skinMatrices, off);
|
|
477
|
+
}
|
|
435
478
|
}
|
|
436
479
|
return skinMatrices;
|
|
437
480
|
}
|
|
@@ -864,15 +907,25 @@ export class Model {
|
|
|
864
907
|
this.computeSingleBoneWorldMatrix(b.parentIndex, applyIK);
|
|
865
908
|
}
|
|
866
909
|
// Get base rotation
|
|
867
|
-
|
|
868
|
-
|
|
910
|
+
const baseRot = localRot[boneIndex];
|
|
911
|
+
let fx = baseRot.x, fy = baseRot.y, fz = baseRot.z, fw = baseRot.w;
|
|
912
|
+
// Apply IK rotation if requested: finalRot = ik * base, then normalize
|
|
869
913
|
if (applyIK && ikChainInfo) {
|
|
870
914
|
const chainInfo = ikChainInfo[boneIndex];
|
|
871
915
|
if (chainInfo?.ikRotation) {
|
|
872
|
-
|
|
916
|
+
const ik = chainInfo.ikRotation;
|
|
917
|
+
const nx = ik.w * fx + ik.x * fw + ik.y * fz - ik.z * fy;
|
|
918
|
+
const ny = ik.w * fy - ik.x * fz + ik.y * fw + ik.z * fx;
|
|
919
|
+
const nz = ik.w * fz + ik.x * fy - ik.y * fx + ik.z * fw;
|
|
920
|
+
const nw = ik.w * fw - ik.x * fx - ik.y * fy - ik.z * fz;
|
|
921
|
+
const len = Math.sqrt(nx * nx + ny * ny + nz * nz + nw * nw);
|
|
922
|
+
const inv = len > 0 ? 1 / len : 0;
|
|
923
|
+
fx = nx * inv;
|
|
924
|
+
fy = ny * inv;
|
|
925
|
+
fz = nz * inv;
|
|
926
|
+
fw = nw * inv;
|
|
873
927
|
}
|
|
874
928
|
}
|
|
875
|
-
let rotateM = Mat4.fromQuat(boneRot.x, boneRot.y, boneRot.z, boneRot.w);
|
|
876
929
|
let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0;
|
|
877
930
|
// Handle append transformations (same logic as computeWorldMatrices)
|
|
878
931
|
const appendParentIdx = b.appendParentIndex;
|
|
@@ -885,16 +938,11 @@ export class Model {
|
|
|
885
938
|
const hasRatio = Math.abs(ratio) > 1e-6;
|
|
886
939
|
if (hasRatio) {
|
|
887
940
|
if (b.appendRotate) {
|
|
888
|
-
//
|
|
889
|
-
// During IK solving, use only base local rotation (not IK rotations) to avoid
|
|
890
|
-
// conflicts with IK rotations that are still being computed incrementally
|
|
891
|
-
// IK rotations will be applied to localRotations after IK solving completes
|
|
941
|
+
// Recurse first (may touch scratch); all scratch use below happens after it unwinds
|
|
892
942
|
if (appendParentIdx >= 0) {
|
|
893
|
-
// Compute append parent's world matrix for dependency order, but use base rotation for append
|
|
894
943
|
this.computeSingleBoneWorldMatrix(appendParentIdx, applyIK);
|
|
895
944
|
}
|
|
896
|
-
|
|
897
|
-
let appendRot = localRot[appendParentIdx];
|
|
945
|
+
const appendRot = localRot[appendParentIdx];
|
|
898
946
|
let ax = appendRot.x, ay = appendRot.y, az = appendRot.z;
|
|
899
947
|
const aw = appendRot.w;
|
|
900
948
|
const absRatio = ratio < 0 ? -ratio : ratio;
|
|
@@ -903,9 +951,20 @@ export class Model {
|
|
|
903
951
|
ay = -ay;
|
|
904
952
|
az = -az;
|
|
905
953
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
954
|
+
// slerp(identity, appendQuat, absRatio) into scratchQuat[1]
|
|
955
|
+
scratchQuat[0].setXYZW(ax, ay, az, aw);
|
|
956
|
+
scratchQuat[2].setIdentity();
|
|
957
|
+
Quat.slerpInto(scratchQuat[2], scratchQuat[0], absRatio, scratchQuat[1]);
|
|
958
|
+
// finalRot = slerpResult * finalRot (rotation composition as quat mul)
|
|
959
|
+
const sx = scratchQuat[1].x, sy = scratchQuat[1].y, sz = scratchQuat[1].z, sw = scratchQuat[1].w;
|
|
960
|
+
const nx = sw * fx + sx * fw + sy * fz - sz * fy;
|
|
961
|
+
const ny = sw * fy - sx * fz + sy * fw + sz * fx;
|
|
962
|
+
const nz = sw * fz + sx * fy - sy * fx + sz * fw;
|
|
963
|
+
const nw = sw * fw - sx * fx - sy * fy - sz * fz;
|
|
964
|
+
fx = nx;
|
|
965
|
+
fy = ny;
|
|
966
|
+
fz = nz;
|
|
967
|
+
fw = nw;
|
|
909
968
|
}
|
|
910
969
|
if (b.appendMove) {
|
|
911
970
|
const appendTrans = localTrans[appendParentIdx];
|
|
@@ -919,18 +978,16 @@ export class Model {
|
|
|
919
978
|
const localTx = boneTrans.x + addLocalTx;
|
|
920
979
|
const localTy = boneTrans.y + addLocalTy;
|
|
921
980
|
const localTz = boneTrans.z + addLocalTz;
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
this.cachedIdentityMat2.setIdentity().translateInPlace(localTx, localTy, localTz);
|
|
926
|
-
const localM = this.cachedIdentityMat1.multiply(rotateM).multiply(this.cachedIdentityMat2);
|
|
981
|
+
// Fused local transform: T_bind · R(finalRot) · T_local → scratchMat4Values[0]
|
|
982
|
+
const localMVals = scratchMat4Values[0];
|
|
983
|
+
Mat4.localTransformInto(b.bindTranslation[0], b.bindTranslation[1], b.bindTranslation[2], fx, fy, fz, fw, localTx, localTy, localTz, localMVals);
|
|
927
984
|
const worldMat = worldMats[boneIndex];
|
|
928
985
|
if (b.parentIndex >= 0) {
|
|
929
986
|
const parentMat = worldMats[b.parentIndex];
|
|
930
|
-
Mat4.multiplyArrays(parentMat.values, 0,
|
|
987
|
+
Mat4.multiplyArrays(parentMat.values, 0, localMVals, 0, worldMat.values, 0);
|
|
931
988
|
}
|
|
932
989
|
else {
|
|
933
|
-
worldMat.values.set(
|
|
990
|
+
worldMat.values.set(localMVals);
|
|
934
991
|
}
|
|
935
992
|
}
|
|
936
993
|
computeWorldMatrices() {
|
|
@@ -950,10 +1007,14 @@ export class Model {
|
|
|
950
1007
|
if (b.parentIndex >= boneCount) {
|
|
951
1008
|
console.warn(`[RZM] bone ${i} parent out of range: ${b.parentIndex}`);
|
|
952
1009
|
}
|
|
1010
|
+
// Ensure parent is computed FIRST, before we touch any scratch buffers.
|
|
1011
|
+
// Recursion may itself use scratchMat4Values[0] / scratchQuat; doing it up
|
|
1012
|
+
// front keeps the current frame's scratch slots untouched when we use them below.
|
|
1013
|
+
if (b.parentIndex >= 0 && !computed[b.parentIndex])
|
|
1014
|
+
computeWorld(b.parentIndex);
|
|
953
1015
|
const boneRot = localRot[i];
|
|
954
|
-
let
|
|
1016
|
+
let fx = boneRot.x, fy = boneRot.y, fz = boneRot.z, fw = boneRot.w;
|
|
955
1017
|
let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0;
|
|
956
|
-
// Optimized append rotation check - only check necessary conditions
|
|
957
1018
|
const appendParentIdx = b.appendParentIndex;
|
|
958
1019
|
const hasAppend = b.appendRotate && appendParentIdx !== undefined && appendParentIdx >= 0 && appendParentIdx < boneCount;
|
|
959
1020
|
if (hasAppend) {
|
|
@@ -962,9 +1023,7 @@ export class Model {
|
|
|
962
1023
|
if (hasRatio) {
|
|
963
1024
|
if (b.appendRotate) {
|
|
964
1025
|
const appendRot = localRot[appendParentIdx];
|
|
965
|
-
let ax = appendRot.x;
|
|
966
|
-
let ay = appendRot.y;
|
|
967
|
-
let az = appendRot.z;
|
|
1026
|
+
let ax = appendRot.x, ay = appendRot.y, az = appendRot.z;
|
|
968
1027
|
const aw = appendRot.w;
|
|
969
1028
|
const absRatio = ratio < 0 ? -ratio : ratio;
|
|
970
1029
|
if (ratio < 0) {
|
|
@@ -972,9 +1031,19 @@ export class Model {
|
|
|
972
1031
|
ay = -ay;
|
|
973
1032
|
az = -az;
|
|
974
1033
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1034
|
+
scratchQuat[0].setXYZW(ax, ay, az, aw);
|
|
1035
|
+
scratchQuat[2].setIdentity();
|
|
1036
|
+
Quat.slerpInto(scratchQuat[2], scratchQuat[0], absRatio, scratchQuat[1]);
|
|
1037
|
+
// finalRot = slerpResult * finalRot (quat mul)
|
|
1038
|
+
const sx = scratchQuat[1].x, sy = scratchQuat[1].y, sz = scratchQuat[1].z, sw = scratchQuat[1].w;
|
|
1039
|
+
const nx = sw * fx + sx * fw + sy * fz - sz * fy;
|
|
1040
|
+
const ny = sw * fy - sx * fz + sy * fw + sz * fx;
|
|
1041
|
+
const nz = sw * fz + sx * fy - sy * fx + sz * fw;
|
|
1042
|
+
const nw = sw * fw - sx * fx - sy * fy - sz * fz;
|
|
1043
|
+
fx = nx;
|
|
1044
|
+
fy = ny;
|
|
1045
|
+
fz = nz;
|
|
1046
|
+
fw = nw;
|
|
978
1047
|
}
|
|
979
1048
|
if (b.appendMove) {
|
|
980
1049
|
const appendTrans = localTrans[appendParentIdx];
|
|
@@ -985,27 +1054,19 @@ export class Model {
|
|
|
985
1054
|
}
|
|
986
1055
|
}
|
|
987
1056
|
}
|
|
988
|
-
// Build local matrix: identity + bind translation, then rotation, then local translation, then append translation
|
|
989
1057
|
const boneTrans = localTrans[i];
|
|
990
1058
|
const localTx = boneTrans.x + addLocalTx;
|
|
991
1059
|
const localTy = boneTrans.y + addLocalTy;
|
|
992
1060
|
const localTz = boneTrans.z + addLocalTz;
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
.translateInPlace(b.bindTranslation[0], b.bindTranslation[1], b.bindTranslation[2]);
|
|
996
|
-
this.cachedIdentityMat2.setIdentity().translateInPlace(localTx, localTy, localTz);
|
|
997
|
-
const localM = this.cachedIdentityMat1.multiply(rotateM).multiply(this.cachedIdentityMat2);
|
|
1061
|
+
const localMVals = scratchMat4Values[0];
|
|
1062
|
+
Mat4.localTransformInto(b.bindTranslation[0], b.bindTranslation[1], b.bindTranslation[2], fx, fy, fz, fw, localTx, localTy, localTz, localMVals);
|
|
998
1063
|
const worldMat = worldMats[i];
|
|
999
1064
|
if (b.parentIndex >= 0) {
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
computeWorld(p);
|
|
1003
|
-
const parentMat = worldMats[p];
|
|
1004
|
-
// Multiply parent world matrix by local matrix
|
|
1005
|
-
Mat4.multiplyArrays(parentMat.values, 0, localM.values, 0, worldMat.values, 0);
|
|
1065
|
+
const parentMat = worldMats[b.parentIndex];
|
|
1066
|
+
Mat4.multiplyArrays(parentMat.values, 0, localMVals, 0, worldMat.values, 0);
|
|
1006
1067
|
}
|
|
1007
1068
|
else {
|
|
1008
|
-
worldMat.values.set(
|
|
1069
|
+
worldMat.values.set(localMVals);
|
|
1009
1070
|
}
|
|
1010
1071
|
computed[i] = true;
|
|
1011
1072
|
};
|
package/dist/physics.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../src/physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../src/physics.ts"],"names":[],"mappings":"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"}
|