@nakednous/tree 0.0.15 → 0.0.17
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 +21 -15
- package/dist/index.js +79 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,10 +82,10 @@ Playback features: signed `rate` (negative reverses), `loop`, `bounce`, `seek(t)
|
|
|
82
82
|
`add()` accepts flexible specs. Top-level forms:
|
|
83
83
|
|
|
84
84
|
```js
|
|
85
|
-
track.add({ pos, rot, scl })
|
|
86
|
-
track.add({ pos, rot, scl, tanIn, tanOut })
|
|
87
|
-
track.add({
|
|
88
|
-
track.add([ spec, spec, ... ])
|
|
85
|
+
track.add({ pos, rot, scl }) // explicit TRS — rot accepts any form below
|
|
86
|
+
track.add({ pos, rot, scl, tanIn, tanOut }) // with Hermite tangents (vec3, optional)
|
|
87
|
+
track.add({ mat4Model: mat4 }) // decompose a column-major model matrix into TRS
|
|
88
|
+
track.add([ spec, spec, ... ]) // bulk
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
`tanIn` is the incoming position tangent at this keyframe; `tanOut` is the outgoing tangent. When only one is given, the other mirrors it. When neither is given, centripetal Catmull-Rom tangents are auto-computed from neighboring keyframes.
|
|
@@ -100,16 +100,16 @@ track.add({ pos:[300,0,0] }) // auto tangents
|
|
|
100
100
|
`rot` sub-forms — all normalised internally:
|
|
101
101
|
|
|
102
102
|
```js
|
|
103
|
-
rot: [x,y,z,w]
|
|
104
|
-
rot: { axis:[x,y,z], angle }
|
|
105
|
-
rot: { dir:[x,y,z], up?:[x,y,z] }
|
|
106
|
-
rot: { euler:[rx,ry,rz], order?:'YXZ' }
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
rot: { from:[x,y,z], to:[x,y,z] }
|
|
111
|
-
rot: { mat3: Float32Array|Array }
|
|
112
|
-
rot: {
|
|
103
|
+
rot: [x,y,z,w] // raw quaternion
|
|
104
|
+
rot: { axis:[x,y,z], angle } // axis-angle
|
|
105
|
+
rot: { dir:[x,y,z], up?:[x,y,z] } // look direction (−Z forward)
|
|
106
|
+
rot: { euler:[rx,ry,rz], order?:'YXZ' } // intrinsic Euler angles (radians)
|
|
107
|
+
// orders: YXZ (default), XYZ, ZYX,
|
|
108
|
+
// ZXY, XZY, YZX
|
|
109
|
+
// extrinsic ABC = intrinsic CBA
|
|
110
|
+
rot: { from:[x,y,z], to:[x,y,z] } // shortest-arc between directions
|
|
111
|
+
rot: { mat3: Float32Array|Array } // column-major 3×3 rotation matrix
|
|
112
|
+
rot: { mat4Eye: mat4 } // rotation block of an eye matrix
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
---
|
|
@@ -160,7 +160,7 @@ track.add({ eye, center?, up?, fov?, halfHeight?,
|
|
|
160
160
|
track.add([ spec, spec, ... ]) // bulk
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
For matrix-based capture use `
|
|
163
|
+
For matrix-based capture use `track.add({ mat4Model: mat4Eye })` for full-fidelity TRS including roll, or `cam.capturePose()` (p5.tree bridge) for lookat-style capture.
|
|
164
164
|
|
|
165
165
|
`fov` and `halfHeight` are lerped between keyframes only when both adjacent keyframes carry a non-null value for that field. Mixed or null entries pass `null` through — the bridge leaves the projection unchanged.
|
|
166
166
|
|
|
@@ -284,6 +284,8 @@ pointVisibility(planes, px, py, pz)
|
|
|
284
284
|
|
|
285
285
|
Three-state result: `VISIBLE` (fully inside), `SEMIVISIBLE` (intersecting), `INVISIBLE` (fully outside).
|
|
286
286
|
|
|
287
|
+
**Sign contract:** `top > 0`, `bottom < 0`, `right > 0`, `left < 0` for standard y-up camera.
|
|
288
|
+
|
|
287
289
|
---
|
|
288
290
|
|
|
289
291
|
### Quaternion and matrix math
|
|
@@ -323,6 +325,10 @@ mat4Ortho — orthographic projection (ndcZMin, ndcYSign)
|
|
|
323
325
|
mat4Frustum — off-centre perspective (ndcZMin, ndcYSign)
|
|
324
326
|
mat4Bias — NDC→texture/UV remap [0,1] for shadow mapping
|
|
325
327
|
mat4Reflect — reflection across a plane
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Mat4 decomposition** (`query.js`):
|
|
331
|
+
```
|
|
326
332
|
mat4ToTranslation — extract translation (col 3)
|
|
327
333
|
mat4ToScale — extract scale (column lengths)
|
|
328
334
|
mat4ToRotation — extract rotation as unit quaternion
|
package/dist/index.js
CHANGED
|
@@ -346,7 +346,7 @@ function mat4Eye(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
|
|
|
346
346
|
*
|
|
347
347
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
348
348
|
* @param {number} tx,ty,tz Translation.
|
|
349
|
-
* @param {number} qx,qy,qz,qw
|
|
349
|
+
* @param {number} qx,qy,qz,qw Rotation quaternion [x,y,z,w].
|
|
350
350
|
* @param {number} sx,sy,sz Scale.
|
|
351
351
|
*/
|
|
352
352
|
function mat4FromTRS(out, tx,ty,tz, qx,qy,qz,qw, sx,sy,sz) {
|
|
@@ -503,49 +503,6 @@ function mat4Reflect(out, nx,ny,nz,d) {
|
|
|
503
503
|
return out;
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
-
// =========================================================================
|
|
507
|
-
// Partial decomposition (mat4To___ mirrors mat4From___)
|
|
508
|
-
// =========================================================================
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Extract translation from a column-major mat4 (column 3).
|
|
512
|
-
* @param {Float32Array|number[]} out3 3-element destination.
|
|
513
|
-
* @param {Float32Array|number[]} m 16-element source.
|
|
514
|
-
*/
|
|
515
|
-
function mat4ToTranslation(out3, m) {
|
|
516
|
-
out3[0]=m[12]; out3[1]=m[13]; out3[2]=m[14];
|
|
517
|
-
return out3;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* Extract scale from a column-major mat4 (column lengths of the rotation block).
|
|
522
|
-
* Assumes no shear.
|
|
523
|
-
* @param {Float32Array|number[]} out3 3-element destination.
|
|
524
|
-
* @param {Float32Array|number[]} m 16-element source.
|
|
525
|
-
*/
|
|
526
|
-
function mat4ToScale(out3, m) {
|
|
527
|
-
out3[0]=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2]);
|
|
528
|
-
out3[1]=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6]);
|
|
529
|
-
out3[2]=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10]);
|
|
530
|
-
return out3;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* Extract rotation as a unit quaternion from a column-major mat4.
|
|
535
|
-
* Scale is factored out from each column. Assumes no shear.
|
|
536
|
-
* @param {number[]} out4 4-element [x,y,z,w] destination.
|
|
537
|
-
* @param {Float32Array|number[]} m 16-element source.
|
|
538
|
-
*/
|
|
539
|
-
function mat4ToRotation(out4, m) {
|
|
540
|
-
const sx=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2])||1;
|
|
541
|
-
const sy=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6])||1;
|
|
542
|
-
const sz=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10])||1;
|
|
543
|
-
return qFromRotMat3x3(out4,
|
|
544
|
-
m[0]/sx, m[4]/sy, m[8]/sz,
|
|
545
|
-
m[1]/sx, m[5]/sy, m[9]/sz,
|
|
546
|
-
m[2]/sx, m[6]/sy, m[10]/sz);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
506
|
/**
|
|
550
507
|
* @file Matrix arithmetic, space-transform dispatch, and projection queries.
|
|
551
508
|
* @module tree/query
|
|
@@ -763,10 +720,30 @@ function mat4MV(out, model, view) { return mat4Mul(out, view, model); }
|
|
|
763
720
|
|
|
764
721
|
/**
|
|
765
722
|
* Location transform between frames: out = inv(to) · from.
|
|
723
|
+
* Assumes both matrices are affine (bottom row [0,0,0,1]).
|
|
766
724
|
* @returns {ArrayLike<number>|null} out, or null if `to` is singular.
|
|
767
725
|
*/
|
|
768
726
|
function mat4Location(out, from, to) {
|
|
769
|
-
return mat4Invert(out, to) && mat4Mul(out, out, from);
|
|
727
|
+
// Same as: return mat4Invert(out, to) && mat4Mul(out, out, from);
|
|
728
|
+
const a00=to[0],a01=to[1],a02=to[2],
|
|
729
|
+
a10=to[4],a11=to[5],a12=to[6],
|
|
730
|
+
a20=to[8],a21=to[9],a22=to[10];
|
|
731
|
+
const b01=a22*a11-a12*a21, b11=a12*a20-a22*a10, b21=a21*a10-a11*a20;
|
|
732
|
+
let det=a00*b01+a01*b11+a02*b21;
|
|
733
|
+
if (Math.abs(det) < 1e-12) return null;
|
|
734
|
+
det=1/det;
|
|
735
|
+
const i00=b01*det, i01=(a02*a21-a22*a01)*det, i02=(a12*a01-a02*a11)*det;
|
|
736
|
+
const i10=b11*det, i11=(a22*a00-a02*a20)*det, i12=(a02*a10-a12*a00)*det;
|
|
737
|
+
const i20=b21*det, i21=(a01*a20-a21*a00)*det, i22=(a11*a00-a01*a10)*det;
|
|
738
|
+
const f00=from[0],f01=from[1],f02=from[2],
|
|
739
|
+
f10=from[4],f11=from[5],f12=from[6],
|
|
740
|
+
f20=from[8],f21=from[9],f22=from[10];
|
|
741
|
+
out[0]=i00*f00+i01*f01+i02*f02; out[1]=i10*f00+i11*f01+i12*f02; out[2]=i20*f00+i21*f01+i22*f02; out[3]=0;
|
|
742
|
+
out[4]=i00*f10+i01*f11+i02*f12; out[5]=i10*f10+i11*f11+i12*f12; out[6]=i20*f10+i21*f11+i22*f12; out[7]=0;
|
|
743
|
+
out[8]=i00*f20+i01*f21+i02*f22; out[9]=i10*f20+i11*f21+i12*f22; out[10]=i20*f20+i21*f21+i22*f22; out[11]=0;
|
|
744
|
+
const dx=from[12]-to[12], dy=from[13]-to[13], dz=from[14]-to[14];
|
|
745
|
+
out[12]=i00*dx+i01*dy+i02*dz; out[13]=i10*dx+i11*dy+i12*dz; out[14]=i20*dx+i21*dy+i22*dz; out[15]=1;
|
|
746
|
+
return out;
|
|
770
747
|
}
|
|
771
748
|
|
|
772
749
|
/**
|
|
@@ -1149,6 +1126,49 @@ function mat4Pick(proj, px, py, vp) {
|
|
|
1149
1126
|
}
|
|
1150
1127
|
}
|
|
1151
1128
|
|
|
1129
|
+
// =========================================================================
|
|
1130
|
+
// Decomposition
|
|
1131
|
+
// =========================================================================
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Extract translation from a column-major mat4 (column 3).
|
|
1135
|
+
* @param {Float32Array|number[]} out3 3-element destination.
|
|
1136
|
+
* @param {Float32Array|number[]} m 16-element source.
|
|
1137
|
+
*/
|
|
1138
|
+
function mat4ToTranslation(out3, m) {
|
|
1139
|
+
out3[0]=m[12]; out3[1]=m[13]; out3[2]=m[14];
|
|
1140
|
+
return out3;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* Extract scale from a column-major mat4 (column lengths of the rotation block).
|
|
1145
|
+
* Assumes no shear.
|
|
1146
|
+
* @param {Float32Array|number[]} out3 3-element destination.
|
|
1147
|
+
* @param {Float32Array|number[]} m 16-element source.
|
|
1148
|
+
*/
|
|
1149
|
+
function mat4ToScale(out3, m) {
|
|
1150
|
+
out3[0]=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2]);
|
|
1151
|
+
out3[1]=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6]);
|
|
1152
|
+
out3[2]=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10]);
|
|
1153
|
+
return out3;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Extract rotation as a unit quaternion from a column-major mat4.
|
|
1158
|
+
* Scale is factored out from each column. Assumes no shear.
|
|
1159
|
+
* @param {number[]} out4 4-element [x,y,z,w] destination.
|
|
1160
|
+
* @param {Float32Array|number[]} m 16-element source.
|
|
1161
|
+
*/
|
|
1162
|
+
function mat4ToRotation(out4, m) {
|
|
1163
|
+
const sx=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2])||1;
|
|
1164
|
+
const sy=Math.sqrt(m[4]*m[4]+m[5]*m[5]+m[6]*m[6])||1;
|
|
1165
|
+
const sz=Math.sqrt(m[8]*m[8]+m[9]*m[9]+m[10]*m[10])||1;
|
|
1166
|
+
return qFromRotMat3x3(out4,
|
|
1167
|
+
m[0]/sx, m[4]/sy, m[8]/sz,
|
|
1168
|
+
m[1]/sx, m[5]/sy, m[9]/sz,
|
|
1169
|
+
m[2]/sx, m[6]/sy, m[10]/sz);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1152
1172
|
/**
|
|
1153
1173
|
* @file Spline math and keyframe animation state machines.
|
|
1154
1174
|
* @module tree/track
|
|
@@ -1357,11 +1377,11 @@ const _EULER_ORDERS = new Set(['XYZ','XZY','YXZ','YZX','ZXY','ZYX']);
|
|
|
1357
1377
|
*
|
|
1358
1378
|
* [x,y,z,w] — raw quaternion array
|
|
1359
1379
|
* { axis:[x,y,z], angle } — axis-angle
|
|
1360
|
-
* { dir:[x,y,z], up?:[x,y,z] }
|
|
1361
|
-
* {
|
|
1380
|
+
* { dir:[x,y,z], up?:[x,y,z] } — forward direction (−Z) with optional up
|
|
1381
|
+
* { mat4Eye: mat4 } — rotation block of an eye matrix
|
|
1362
1382
|
* { mat3: mat3 } — column-major 3×3 rotation matrix
|
|
1363
1383
|
* { euler:[rx,ry,rz], order? } — intrinsic Euler (default order: YXZ)
|
|
1364
|
-
* { from:[x,y,z], to:[x,y,z] }
|
|
1384
|
+
* { from:[x,y,z], to:[x,y,z] } — shortest-arc rotation
|
|
1365
1385
|
*
|
|
1366
1386
|
* @param {*} v
|
|
1367
1387
|
* @returns {number[]|null} [x,y,z,w] or null if unparseable.
|
|
@@ -1388,10 +1408,10 @@ function _parseQuat(v) {
|
|
|
1388
1408
|
return qFromLookDir([0,0,0,1], d, u);
|
|
1389
1409
|
}
|
|
1390
1410
|
|
|
1391
|
-
// {
|
|
1392
|
-
if (v.
|
|
1393
|
-
const m = (ArrayBuffer.isView(v.
|
|
1394
|
-
? v.
|
|
1411
|
+
// { mat4Eye }
|
|
1412
|
+
if (v.mat4Eye != null) {
|
|
1413
|
+
const m = (ArrayBuffer.isView(v.mat4Eye) || Array.isArray(v.mat4Eye))
|
|
1414
|
+
? v.mat4Eye : (v.mat4Eye.mat4 ?? null);
|
|
1395
1415
|
if (!m || m.length < 16) return null;
|
|
1396
1416
|
return qFromRotMat3x3([0,0,0,1], m[0],m[4],m[8], m[1],m[5],m[9], m[2],m[6],m[10]);
|
|
1397
1417
|
}
|
|
@@ -1449,7 +1469,7 @@ function _parseQuat(v) {
|
|
|
1449
1469
|
*
|
|
1450
1470
|
* Accepted forms:
|
|
1451
1471
|
*
|
|
1452
|
-
* {
|
|
1472
|
+
* { mat4Model }
|
|
1453
1473
|
* Decompose a column-major mat4 into TRS via mat4ToTransform.
|
|
1454
1474
|
* Float32Array(16), plain Array, or { mat4 } wrapper.
|
|
1455
1475
|
*
|
|
@@ -1465,10 +1485,10 @@ function _parseQuat(v) {
|
|
|
1465
1485
|
function _parseSpec(spec) {
|
|
1466
1486
|
if (!spec || typeof spec !== 'object') return null;
|
|
1467
1487
|
|
|
1468
|
-
// {
|
|
1469
|
-
if (spec.
|
|
1470
|
-
const m = (ArrayBuffer.isView(spec.
|
|
1471
|
-
? spec.
|
|
1488
|
+
// { mat4Model } — full TRS decomposition from model matrix
|
|
1489
|
+
if (spec.mat4Model != null) {
|
|
1490
|
+
const m = (ArrayBuffer.isView(spec.mat4Model) || Array.isArray(spec.mat4Model))
|
|
1491
|
+
? spec.mat4Model : (spec.mat4Model.mat4 ?? null);
|
|
1472
1492
|
if (!m || m.length < 16) return null;
|
|
1473
1493
|
const kf = mat4ToTransform({ pos:[0,0,0], rot:[0,0,0,1], scl:[1,1,1] }, m);
|
|
1474
1494
|
kf.tanIn = null; kf.tanOut = null;
|
|
@@ -1505,7 +1525,7 @@ function _sameTransform(a, b) {
|
|
|
1505
1525
|
* When absent, centripetal Catmull-Rom tangents are auto-computed at eval time.
|
|
1506
1526
|
*
|
|
1507
1527
|
* Removed forms (task 2):
|
|
1508
|
-
* {
|
|
1528
|
+
* { mat4View } and { mat4Eye } — use PoseTrack.add({ mat4Model: mat4Eye }) for
|
|
1509
1529
|
* full-fidelity capture including roll, or cam.capturePose() for lookat-style.
|
|
1510
1530
|
*
|
|
1511
1531
|
* @param {Object} spec
|
|
@@ -2004,7 +2024,7 @@ class PoseTrack extends Track {
|
|
|
2004
2024
|
* { eye, center?, up?, fov?, halfHeight?,
|
|
2005
2025
|
* eyeTanIn?, eyeTanOut?, centerTanIn?, centerTanOut? }
|
|
2006
2026
|
*
|
|
2007
|
-
* To capture a matrix-based pose, use PoseTrack.add({
|
|
2027
|
+
* To capture a matrix-based pose, use PoseTrack.add({ mat4Model: mat4Eye })
|
|
2008
2028
|
* for full-fidelity including roll, or cam.capturePose() for lookat-style.
|
|
2009
2029
|
*/
|
|
2010
2030
|
class CameraTrack extends Track {
|