@nakednous/tree 0.0.18 → 0.0.20
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 +25 -1
- package/dist/index.js +227 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -166,6 +166,30 @@ For matrix-based capture use `track.add({ mat4Model: mat4Eye })` for full-fideli
|
|
|
166
166
|
|
|
167
167
|
---
|
|
168
168
|
|
|
169
|
+
### Path sampling
|
|
170
|
+
|
|
171
|
+
The interpolated path of a track can be sampled without advancing the transport cursor or firing hooks. All samplers are zero-alloc — the caller owns the output buffers — and honour the track's interpolation mode (`hermite` / `linear` / `step`) and the same stored-tangent → auto-CR fallback chain used by `eval()`.
|
|
172
|
+
|
|
173
|
+
**`PoseTrack`:**
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
track.samplePos(out, seg, t) // interpolated pos at (seg, t ∈ [0, 1])
|
|
177
|
+
track.sampleTangents(outIn, outOut, i) // effective in/out tangents at keyframe i
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**`CameraTrack`:**
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
track.sampleEye(out, seg, t)
|
|
184
|
+
track.sampleCenter(out, seg, t)
|
|
185
|
+
track.sampleEyeTangents(outIn, outOut, i)
|
|
186
|
+
track.sampleCenterTangents(outIn, outOut, i)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Tangent samplers mirror the missing side at boundary keyframes so the first and last keyframes produce visible tangent vectors. Intended uses: custom rendering of the path (polyline overlays, arclength-based placement), pedagogical visualisations of Hermite / Catmull-Rom, and gizmos — `p5.tree`'s `trackPath` is built on top of these.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
169
193
|
### Shared Track transport
|
|
170
194
|
|
|
171
195
|
Both `PoseTrack` and `CameraTrack` extend `Track`, which holds all transport machinery:
|
|
@@ -298,7 +322,7 @@ Exported individually for use in hot paths.
|
|
|
298
322
|
qSet qCopy qDot qNormalize qNegate qMul
|
|
299
323
|
qSlerp qNlerp
|
|
300
324
|
qFromAxisAngle qFromLookDir qFromRotMat3x3 qFromMat4 qToMat4
|
|
301
|
-
|
|
325
|
+
qToAxisAngle
|
|
302
326
|
```
|
|
303
327
|
|
|
304
328
|
**Spline / vector:** `hermiteVec3`, `lerpVec3`
|
package/dist/index.js
CHANGED
|
@@ -215,7 +215,7 @@ const qToMat4 = (out, q) => {
|
|
|
215
215
|
* @param {Object} [out]
|
|
216
216
|
* @returns {{ axis: number[], angle: number }}
|
|
217
217
|
*/
|
|
218
|
-
const
|
|
218
|
+
const qToAxisAngle = (q, out) => {
|
|
219
219
|
out = out || {};
|
|
220
220
|
const x=q[0],y=q[1],z=q[2],w=q[3];
|
|
221
221
|
const sinHalf = Math.sqrt(x*x+y*y+z*z);
|
|
@@ -1164,7 +1164,7 @@ function mat4ToRotation(out4, m) {
|
|
|
1164
1164
|
* Quaternion helpers (re-exported from quat.js)
|
|
1165
1165
|
* qSet qCopy qDot qNormalize qNegate qMul qSlerp qNlerp
|
|
1166
1166
|
* qFromAxisAngle qFromLookDir qFromRotMat3x3 qFromMat4 qToMat4
|
|
1167
|
-
*
|
|
1167
|
+
* qToAxisAngle
|
|
1168
1168
|
* Spline / vector helpers
|
|
1169
1169
|
* hermiteVec3 lerpVec3
|
|
1170
1170
|
* Transform / mat4 helpers
|
|
@@ -1182,6 +1182,19 @@ function mat4ToRotation(out4, m) {
|
|
|
1182
1182
|
* hooks, rate semantics. Subclasses add only keyframe storage and
|
|
1183
1183
|
* add() / eval() for their respective data shape.
|
|
1184
1184
|
*
|
|
1185
|
+
* ── Path samplers (public, zero-alloc, no cursor side effects) ──────────────
|
|
1186
|
+
* PoseTrack
|
|
1187
|
+
* samplePos(out, seg, t) writes interpolated pos at (seg, t∈[0,1])
|
|
1188
|
+
* sampleTangents(outIn, outOut, i) effective in/out tangents at keyframe i
|
|
1189
|
+
* CameraTrack
|
|
1190
|
+
* sampleEye(out, seg, t)
|
|
1191
|
+
* sampleCenter(out, seg, t)
|
|
1192
|
+
* sampleEyeTangents(outIn, outOut, i)
|
|
1193
|
+
* sampleCenterTangents(outIn, outOut, i)
|
|
1194
|
+
*
|
|
1195
|
+
* Samplers honour the corresponding interpolation mode (hermite/linear/step)
|
|
1196
|
+
* and the stored-tangent / auto-CR fallback chain used by eval().
|
|
1197
|
+
*
|
|
1185
1198
|
* ── Hook architecture ─────────────────────────────────────────────────────────
|
|
1186
1199
|
* Lib-space hooks (underscore prefix — reserved for host layer / UI layer):
|
|
1187
1200
|
* _onActivate / _onDeactivate — fire on playing transitions false→true / true→false.
|
|
@@ -1259,19 +1272,22 @@ const hermiteVec3 = (out, p0, m0, p1, m1, t) => {
|
|
|
1259
1272
|
};
|
|
1260
1273
|
|
|
1261
1274
|
// Centripetal CR outgoing tangent at p1 for segment p1→p2, scaled by dt1.
|
|
1275
|
+
// Signature: (out, p0, p1, p2). Returns tangent AT p1 (the middle point).
|
|
1262
1276
|
const _crTanOut = (out, p0, p1, p2) => {
|
|
1263
1277
|
const dt0=Math.pow(_dist3(p0,p1),0.5)||1, dt1=Math.pow(_dist3(p1,p2),0.5)||1;
|
|
1264
1278
|
for (let i=0;i<3;i++) out[i]=((p1[i]-p0[i])/dt0-(p2[i]-p0[i])/(dt0+dt1)+(p2[i]-p1[i])/dt1)*dt1;
|
|
1265
1279
|
return out;
|
|
1266
1280
|
};
|
|
1267
1281
|
|
|
1282
|
+
// Centripetal CR incoming tangent at p2 for segment p1→p2, scaled by dt1.
|
|
1283
|
+
// Signature: (out, p1, p2, p3). Returns tangent AT p2 (the middle point).
|
|
1268
1284
|
const _crTanIn = (out, p1, p2, p3) => {
|
|
1269
1285
|
const dt1=Math.pow(_dist3(p1,p2),0.5)||1, dt2=Math.pow(_dist3(p2,p3),0.5)||1;
|
|
1270
1286
|
for (let i=0;i<3;i++) out[i]=((p2[i]-p1[i])/dt1-(p3[i]-p1[i])/(dt1+dt2)+(p3[i]-p2[i])/dt2)*dt1;
|
|
1271
1287
|
return out;
|
|
1272
1288
|
};
|
|
1273
1289
|
|
|
1274
|
-
// Module-level scratch — shared
|
|
1290
|
+
// Module-level scratch — shared across all track instances (non-reentrant hot path).
|
|
1275
1291
|
const _m0=[0,0,0], _m1=[0,0,0];
|
|
1276
1292
|
|
|
1277
1293
|
/**
|
|
@@ -1289,6 +1305,121 @@ const lerpVec3 = (out, a, b, t) => {
|
|
|
1289
1305
|
return out;
|
|
1290
1306
|
};
|
|
1291
1307
|
|
|
1308
|
+
// =========================================================================
|
|
1309
|
+
// S2b Path samplers — shared core
|
|
1310
|
+
// =========================================================================
|
|
1311
|
+
//
|
|
1312
|
+
// These helpers factor out the per-field interpolation from eval(), so that
|
|
1313
|
+
// the samplers (samplePos / sampleEye / sampleCenter / sampleTangents / ...)
|
|
1314
|
+
// can write into caller buffers without touching the cursor state.
|
|
1315
|
+
//
|
|
1316
|
+
// The field name and its associated tangent field names are passed as keys
|
|
1317
|
+
// so the same core serves 'pos'/'tanIn'/'tanOut' for PoseTrack and
|
|
1318
|
+
// 'eye'|'center' + matching tangent keys for CameraTrack.
|
|
1319
|
+
|
|
1320
|
+
/**
|
|
1321
|
+
* Sample interpolated vec3 path at (seg, t) into out.
|
|
1322
|
+
* @private
|
|
1323
|
+
* @param {number[]} out
|
|
1324
|
+
* @param {Array} kfs keyframe array
|
|
1325
|
+
* @param {string} interp 'hermite' | 'linear' | 'step'
|
|
1326
|
+
* @param {string} field keyframe property holding the vec3 path point
|
|
1327
|
+
* @param {string} tanInName keyframe property for incoming tangent
|
|
1328
|
+
* @param {string} tanOutName keyframe property for outgoing tangent
|
|
1329
|
+
* @param {number} seg segment index
|
|
1330
|
+
* @param {number} t local parameter in [0,1]
|
|
1331
|
+
*/
|
|
1332
|
+
function _samplePathCore(out, kfs, interp, field, tanInName, tanOutName, seg, t) {
|
|
1333
|
+
const n = kfs.length;
|
|
1334
|
+
if (n === 0) { out[0]=0; out[1]=0; out[2]=0; return out; }
|
|
1335
|
+
if (n === 1) {
|
|
1336
|
+
const p = kfs[0][field];
|
|
1337
|
+
out[0]=p[0]; out[1]=p[1]; out[2]=p[2];
|
|
1338
|
+
return out;
|
|
1339
|
+
}
|
|
1340
|
+
const nSeg = n - 1;
|
|
1341
|
+
seg = _clampS(seg | 0, 0, nSeg - 1);
|
|
1342
|
+
t = _clamp01(t);
|
|
1343
|
+
const k0 = kfs[seg];
|
|
1344
|
+
const k1 = kfs[seg + 1];
|
|
1345
|
+
|
|
1346
|
+
if (interp === 'step') {
|
|
1347
|
+
const p = k0[field];
|
|
1348
|
+
out[0]=p[0]; out[1]=p[1]; out[2]=p[2];
|
|
1349
|
+
return out;
|
|
1350
|
+
}
|
|
1351
|
+
if (interp === 'linear') {
|
|
1352
|
+
return lerpVec3(out, k0[field], k1[field], t);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// hermite (default)
|
|
1356
|
+
const p0 = seg > 0 ? kfs[seg - 1][field] : k0[field];
|
|
1357
|
+
const p3 = seg + 2 < n ? kfs[seg + 2][field] : k1[field];
|
|
1358
|
+
const m0 = k0[tanOutName] != null ? k0[tanOutName]
|
|
1359
|
+
: k0[tanInName] != null ? k0[tanInName]
|
|
1360
|
+
: _crTanOut(_m0, p0, k0[field], k1[field]);
|
|
1361
|
+
const m1 = k1[tanInName] != null ? k1[tanInName]
|
|
1362
|
+
: k1[tanOutName] != null ? k1[tanOutName]
|
|
1363
|
+
: _crTanIn(_m1, k0[field], k1[field], p3);
|
|
1364
|
+
return hermiteVec3(out, k0[field], m0, k1[field], m1, t);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Write the effective in/out tangents at keyframe i.
|
|
1369
|
+
*
|
|
1370
|
+
* Stored tanIn/tanOut take precedence, then each mirrors the other when only
|
|
1371
|
+
* one is stored, else centripetal Catmull-Rom tangents are auto-computed from
|
|
1372
|
+
* neighbours.
|
|
1373
|
+
*
|
|
1374
|
+
* At endpoints one side has no adjacent segment; that side mirrors the other
|
|
1375
|
+
* side's tangent. Callers drawing arrows at endpoints therefore see a vector
|
|
1376
|
+
* that matches the curve's derivative into / out of the curve's boundary.
|
|
1377
|
+
*
|
|
1378
|
+
* @private
|
|
1379
|
+
*/
|
|
1380
|
+
function _sampleTangentsCore(outIn, outOut, kfs, field, tanInName, tanOutName, i) {
|
|
1381
|
+
const n = kfs.length;
|
|
1382
|
+
if (n === 0) {
|
|
1383
|
+
outIn[0]=outIn[1]=outIn[2]=0; outOut[0]=outOut[1]=outOut[2]=0;
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
i = _clampS(i | 0, 0, n - 1);
|
|
1387
|
+
const ki = kfs[i];
|
|
1388
|
+
const hasTI = ki[tanInName] != null;
|
|
1389
|
+
const hasTO = ki[tanOutName] != null;
|
|
1390
|
+
|
|
1391
|
+
// ── outgoing tangent at keyframe i (for segment i → i+1) ──────────────
|
|
1392
|
+
if (hasTO) {
|
|
1393
|
+
outOut[0]=ki[tanOutName][0]; outOut[1]=ki[tanOutName][1]; outOut[2]=ki[tanOutName][2];
|
|
1394
|
+
} else if (hasTI) {
|
|
1395
|
+
outOut[0]=ki[tanInName][0]; outOut[1]=ki[tanInName][1]; outOut[2]=ki[tanInName][2];
|
|
1396
|
+
} else if (i < n - 1) {
|
|
1397
|
+
const k1 = kfs[i + 1];
|
|
1398
|
+
const p0 = i > 0 ? kfs[i - 1][field] : ki[field];
|
|
1399
|
+
_crTanOut(outOut, p0, ki[field], k1[field]);
|
|
1400
|
+
} else {
|
|
1401
|
+
outOut[0]=0; outOut[1]=0; outOut[2]=0; // filled below by mirror
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// ── incoming tangent at keyframe i (for segment i-1 → i) ──────────────
|
|
1405
|
+
if (hasTI) {
|
|
1406
|
+
outIn[0]=ki[tanInName][0]; outIn[1]=ki[tanInName][1]; outIn[2]=ki[tanInName][2];
|
|
1407
|
+
} else if (hasTO) {
|
|
1408
|
+
outIn[0]=ki[tanOutName][0]; outIn[1]=ki[tanOutName][1]; outIn[2]=ki[tanOutName][2];
|
|
1409
|
+
} else if (i > 0) {
|
|
1410
|
+
const k0 = kfs[i - 1];
|
|
1411
|
+
const p3 = i + 1 < n ? kfs[i + 1][field] : ki[field];
|
|
1412
|
+
_crTanIn(outIn, k0[field], ki[field], p3);
|
|
1413
|
+
} else {
|
|
1414
|
+
outIn[0]=outOut[0]; outIn[1]=outOut[1]; outIn[2]=outOut[2];
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
// Boundary mirror the other way: last keyframe with no stored tangents.
|
|
1418
|
+
if (i === n - 1 && !hasTO && !hasTI) {
|
|
1419
|
+
outOut[0]=outIn[0]; outOut[1]=outIn[1]; outOut[2]=outIn[2];
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1292
1423
|
// =========================================================================
|
|
1293
1424
|
// S3 Transform <-> Mat4
|
|
1294
1425
|
// =========================================================================
|
|
@@ -1503,10 +1634,6 @@ function _sameTransform(a, b) {
|
|
|
1503
1634
|
* eyeTanIn/Out and centerTanIn/Out are optional vec3 tangents for Hermite.
|
|
1504
1635
|
* When absent, centripetal Catmull-Rom tangents are auto-computed at eval time.
|
|
1505
1636
|
*
|
|
1506
|
-
* Removed forms (task 2):
|
|
1507
|
-
* { mat4View } and { mat4Eye } — use PoseTrack.add({ mat4Model: mat4Eye }) for
|
|
1508
|
-
* full-fidelity capture including roll, or cam.capturePose() for lookat-style.
|
|
1509
|
-
*
|
|
1510
1637
|
* @param {Object} spec
|
|
1511
1638
|
* @returns {{ eye:number[], center:number[], up:number[],
|
|
1512
1639
|
* fov:number|null, halfHeight:number|null,
|
|
@@ -1526,12 +1653,12 @@ function _parseCameraSpec(spec) {
|
|
|
1526
1653
|
return {
|
|
1527
1654
|
eye, center,
|
|
1528
1655
|
up: [up[0]/ul, up[1]/ul, up[2]/ul],
|
|
1529
|
-
fov:
|
|
1530
|
-
halfHeight:
|
|
1531
|
-
eyeTanIn:
|
|
1532
|
-
eyeTanOut:
|
|
1533
|
-
centerTanIn:
|
|
1534
|
-
centerTanOut:_parseVec3(spec.centerTanOut)|| null,
|
|
1656
|
+
fov: typeof spec.fov === 'number' ? spec.fov : null,
|
|
1657
|
+
halfHeight: typeof spec.halfHeight === 'number' ? spec.halfHeight : null,
|
|
1658
|
+
eyeTanIn: _parseVec3(spec.eyeTanIn) || null,
|
|
1659
|
+
eyeTanOut: _parseVec3(spec.eyeTanOut) || null,
|
|
1660
|
+
centerTanIn: _parseVec3(spec.centerTanIn) || null,
|
|
1661
|
+
centerTanOut: _parseVec3(spec.centerTanOut)|| null,
|
|
1535
1662
|
};
|
|
1536
1663
|
}
|
|
1537
1664
|
|
|
@@ -1558,7 +1685,7 @@ class Track {
|
|
|
1558
1685
|
this.playing = false;
|
|
1559
1686
|
/** Loop at boundaries. @type {boolean} */
|
|
1560
1687
|
this.loop = false;
|
|
1561
|
-
/** Ping-pong bounce (
|
|
1688
|
+
/** Ping-pong bounce (independent of loop). @type {boolean} */
|
|
1562
1689
|
this.bounce = false;
|
|
1563
1690
|
/** Frames per segment (≥1). @type {number} */
|
|
1564
1691
|
this.duration = 30;
|
|
@@ -1773,14 +1900,12 @@ class Track {
|
|
|
1773
1900
|
// ── loop:false, bounce:true — bounce once, stop at origin ────────────
|
|
1774
1901
|
if (!this.loop && this.bounce) {
|
|
1775
1902
|
if (next >= total) {
|
|
1776
|
-
// far boundary: reflect and flip direction once
|
|
1777
1903
|
this._setCursorFromScalar(Math.min(total, 2 * total - next));
|
|
1778
1904
|
this._dir = -this._dir;
|
|
1779
1905
|
this._bounced = true;
|
|
1780
1906
|
return true;
|
|
1781
1907
|
}
|
|
1782
1908
|
if (next <= 0) {
|
|
1783
|
-
// origin: stop (whether we bounced or started backward)
|
|
1784
1909
|
this._setCursorFromScalar(0);
|
|
1785
1910
|
this.playing = false;
|
|
1786
1911
|
this._dir = 1; this._bounced = false;
|
|
@@ -1907,6 +2032,39 @@ class PoseTrack extends Track {
|
|
|
1907
2032
|
return true;
|
|
1908
2033
|
}
|
|
1909
2034
|
|
|
2035
|
+
/**
|
|
2036
|
+
* Sample the position path at (seg, t).
|
|
2037
|
+
*
|
|
2038
|
+
* Pure function of the keyframes — does not read or modify the transport
|
|
2039
|
+
* cursor, fires no hooks, allocates nothing. seg is clamped to
|
|
2040
|
+
* [0, segments-1] and t to [0, 1].
|
|
2041
|
+
*
|
|
2042
|
+
* @param {number[]} out 3-element result buffer.
|
|
2043
|
+
* @param {number} seg Segment index.
|
|
2044
|
+
* @param {number} t Local parameter in [0, 1].
|
|
2045
|
+
* @returns {number[]} out
|
|
2046
|
+
*/
|
|
2047
|
+
samplePos(out, seg, t) {
|
|
2048
|
+
return _samplePathCore(out, this.keyframes, this.posInterp, 'pos', 'tanIn', 'tanOut', seg, t);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
/**
|
|
2052
|
+
* Write the effective incoming / outgoing tangents at keyframe i.
|
|
2053
|
+
* Stored tanIn/tanOut take precedence, then each mirrors the other when
|
|
2054
|
+
* only one is stored, else centripetal Catmull-Rom tangents are auto-
|
|
2055
|
+
* computed from neighbours. Endpoint tangents mirror across the missing
|
|
2056
|
+
* side so drawing arrows at boundary keyframes produces a visible vector.
|
|
2057
|
+
*
|
|
2058
|
+
* @param {number[]} outIn 3-element result — incoming tangent at kf i.
|
|
2059
|
+
* @param {number[]} outOut 3-element result — outgoing tangent at kf i.
|
|
2060
|
+
* @param {number} i Keyframe index.
|
|
2061
|
+
* @returns {PoseTrack} this
|
|
2062
|
+
*/
|
|
2063
|
+
sampleTangents(outIn, outOut, i) {
|
|
2064
|
+
_sampleTangentsCore(outIn, outOut, this.keyframes, 'pos', 'tanIn', 'tanOut', i);
|
|
2065
|
+
return this;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
1910
2068
|
/**
|
|
1911
2069
|
* Evaluate interpolated TRS pose at current cursor.
|
|
1912
2070
|
* @param {{ pos:number[], rot:number[], scl:number[] }} [out]
|
|
@@ -1932,22 +2090,8 @@ class PoseTrack extends Track {
|
|
|
1932
2090
|
const k0 = this.keyframes[seg];
|
|
1933
2091
|
const k1 = this.keyframes[seg + 1];
|
|
1934
2092
|
|
|
1935
|
-
// pos —
|
|
1936
|
-
|
|
1937
|
-
out.pos[0]=k0.pos[0]; out.pos[1]=k0.pos[1]; out.pos[2]=k0.pos[2];
|
|
1938
|
-
} else if (this.posInterp === 'linear') {
|
|
1939
|
-
lerpVec3(out.pos, k0.pos, k1.pos, t);
|
|
1940
|
-
} else {
|
|
1941
|
-
const p0 = seg > 0 ? this.keyframes[seg - 1].pos : k0.pos;
|
|
1942
|
-
seg + 2 < n ? this.keyframes[seg + 2].pos : k1.pos;
|
|
1943
|
-
const m0 = k0.tanOut != null ? k0.tanOut
|
|
1944
|
-
: k0.tanIn != null ? k0.tanIn
|
|
1945
|
-
: _crTanOut(_m0, p0, k0.pos, k1.pos);
|
|
1946
|
-
const m1 = k1.tanIn != null ? k1.tanIn
|
|
1947
|
-
: k1.tanOut != null ? k1.tanOut
|
|
1948
|
-
: _crTanIn(_m1, p0, k0.pos, k1.pos);
|
|
1949
|
-
hermiteVec3(out.pos, k0.pos, m0, k1.pos, m1, t);
|
|
1950
|
-
}
|
|
2093
|
+
// pos — shared sampler (respects posInterp + tangent fallback chain)
|
|
2094
|
+
_samplePathCore(out.pos, this.keyframes, this.posInterp, 'pos', 'tanIn', 'tanOut', seg, t);
|
|
1951
2095
|
|
|
1952
2096
|
// rot — step, slerp, or nlerp
|
|
1953
2097
|
if (this.rotInterp === 'step') {
|
|
@@ -2055,6 +2199,52 @@ class CameraTrack extends Track {
|
|
|
2055
2199
|
return true;
|
|
2056
2200
|
}
|
|
2057
2201
|
|
|
2202
|
+
/**
|
|
2203
|
+
* Sample the eye path at (seg, t). See PoseTrack.samplePos for semantics.
|
|
2204
|
+
* @param {number[]} out
|
|
2205
|
+
* @param {number} seg
|
|
2206
|
+
* @param {number} t
|
|
2207
|
+
* @returns {number[]} out
|
|
2208
|
+
*/
|
|
2209
|
+
sampleEye(out, seg, t) {
|
|
2210
|
+
return _samplePathCore(out, this.keyframes, this.eyeInterp, 'eye', 'eyeTanIn', 'eyeTanOut', seg, t);
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
/**
|
|
2214
|
+
* Sample the center path at (seg, t). See PoseTrack.samplePos for semantics.
|
|
2215
|
+
* @param {number[]} out
|
|
2216
|
+
* @param {number} seg
|
|
2217
|
+
* @param {number} t
|
|
2218
|
+
* @returns {number[]} out
|
|
2219
|
+
*/
|
|
2220
|
+
sampleCenter(out, seg, t) {
|
|
2221
|
+
return _samplePathCore(out, this.keyframes, this.centerInterp, 'center', 'centerTanIn', 'centerTanOut', seg, t);
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
/**
|
|
2225
|
+
* Effective in/out eye tangents at keyframe i. See PoseTrack.sampleTangents.
|
|
2226
|
+
* @param {number[]} outIn
|
|
2227
|
+
* @param {number[]} outOut
|
|
2228
|
+
* @param {number} i
|
|
2229
|
+
* @returns {CameraTrack} this
|
|
2230
|
+
*/
|
|
2231
|
+
sampleEyeTangents(outIn, outOut, i) {
|
|
2232
|
+
_sampleTangentsCore(outIn, outOut, this.keyframes, 'eye', 'eyeTanIn', 'eyeTanOut', i);
|
|
2233
|
+
return this;
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
/**
|
|
2237
|
+
* Effective in/out center tangents at keyframe i. See PoseTrack.sampleTangents.
|
|
2238
|
+
* @param {number[]} outIn
|
|
2239
|
+
* @param {number[]} outOut
|
|
2240
|
+
* @param {number} i
|
|
2241
|
+
* @returns {CameraTrack} this
|
|
2242
|
+
*/
|
|
2243
|
+
sampleCenterTangents(outIn, outOut, i) {
|
|
2244
|
+
_sampleTangentsCore(outIn, outOut, this.keyframes, 'center', 'centerTanIn', 'centerTanOut', i);
|
|
2245
|
+
return this;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2058
2248
|
/**
|
|
2059
2249
|
* Evaluate interpolated camera pose at current cursor.
|
|
2060
2250
|
*
|
|
@@ -2083,39 +2273,11 @@ class CameraTrack extends Track {
|
|
|
2083
2273
|
const k0 = this.keyframes[seg];
|
|
2084
2274
|
const k1 = this.keyframes[seg + 1];
|
|
2085
2275
|
|
|
2086
|
-
// eye —
|
|
2087
|
-
|
|
2088
|
-
out.eye[0]=k0.eye[0]; out.eye[1]=k0.eye[1]; out.eye[2]=k0.eye[2];
|
|
2089
|
-
} else if (this.eyeInterp === 'linear') {
|
|
2090
|
-
lerpVec3(out.eye, k0.eye, k1.eye, t);
|
|
2091
|
-
} else {
|
|
2092
|
-
const p0 = seg > 0 ? this.keyframes[seg - 1].eye : k0.eye;
|
|
2093
|
-
seg + 2 < n ? this.keyframes[seg + 2].eye : k1.eye;
|
|
2094
|
-
const m0 = k0.eyeTanOut != null ? k0.eyeTanOut
|
|
2095
|
-
: k0.eyeTanIn != null ? k0.eyeTanIn
|
|
2096
|
-
: _crTanOut(_m0, p0, k0.eye, k1.eye);
|
|
2097
|
-
const m1 = k1.eyeTanIn != null ? k1.eyeTanIn
|
|
2098
|
-
: k1.eyeTanOut != null ? k1.eyeTanOut
|
|
2099
|
-
: _crTanIn(_m1, p0, k0.eye, k1.eye);
|
|
2100
|
-
hermiteVec3(out.eye, k0.eye, m0, k1.eye, m1, t);
|
|
2101
|
-
}
|
|
2276
|
+
// eye — shared sampler
|
|
2277
|
+
_samplePathCore(out.eye, this.keyframes, this.eyeInterp, 'eye', 'eyeTanIn', 'eyeTanOut', seg, t);
|
|
2102
2278
|
|
|
2103
|
-
// center —
|
|
2104
|
-
|
|
2105
|
-
out.center[0]=k0.center[0]; out.center[1]=k0.center[1]; out.center[2]=k0.center[2];
|
|
2106
|
-
} else if (this.centerInterp === 'hermite') {
|
|
2107
|
-
const c0 = seg > 0 ? this.keyframes[seg - 1].center : k0.center;
|
|
2108
|
-
seg + 2 < n ? this.keyframes[seg + 2].center : k1.center;
|
|
2109
|
-
const m0 = k0.centerTanOut != null ? k0.centerTanOut
|
|
2110
|
-
: k0.centerTanIn != null ? k0.centerTanIn
|
|
2111
|
-
: _crTanOut(_m0, c0, k0.center, k1.center);
|
|
2112
|
-
const m1 = k1.centerTanIn != null ? k1.centerTanIn
|
|
2113
|
-
: k1.centerTanOut != null ? k1.centerTanOut
|
|
2114
|
-
: _crTanIn(_m1, c0, k0.center, k1.center);
|
|
2115
|
-
hermiteVec3(out.center, k0.center, m0, k1.center, m1, t);
|
|
2116
|
-
} else {
|
|
2117
|
-
lerpVec3(out.center, k0.center, k1.center, t);
|
|
2118
|
-
}
|
|
2279
|
+
// center — shared sampler
|
|
2280
|
+
_samplePathCore(out.center, this.keyframes, this.centerInterp, 'center', 'centerTanIn', 'centerTanOut', seg, t);
|
|
2119
2281
|
|
|
2120
2282
|
// up — nlerp on unit sphere
|
|
2121
2283
|
lerpVec3(out.up, k0.up, k1.up, t);
|
|
@@ -2292,5 +2454,5 @@ function boxVisibility(planes, x0, y0, z0, x1, y1, z1) {
|
|
|
2292
2454
|
return allIn ? VISIBLE : SEMIVISIBLE;
|
|
2293
2455
|
}
|
|
2294
2456
|
|
|
2295
|
-
export { CameraTrack, EYE, INVISIBLE, MATRIX, MODEL, NDC, ORIGIN, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP, PoseTrack, SCREEN, SEMIVISIBLE, VISIBLE, WEBGL, WEBGPU, WORLD, _i, _j, _k, boxVisibility, distanceToPlane, frustumPlanes, hermiteVec3, i, j, k, lerpVec3, mapDirection, mapLocation, mat3Direction, mat3NormalFromMat4, mat4Bias, mat4Eye, mat4FromBasis, mat4FromScale, mat4FromTRS, mat4FromTranslation, mat4Invert, mat4Location, mat4MV, mat4Mul, mat4MulDir, mat4MulPoint, mat4Ortho, mat4PV, mat4Persp, mat4Pick, mat4Reflect, mat4ToRotation, mat4ToScale, mat4ToTransform, mat4ToTranslation, mat4View, pixelRatio, pointVisibility, projBottom, projFar, projFov, projHfov, projIsOrtho, projLeft, projNear, projRight, projTop, qCopy, qDot, qFromAxisAngle, qFromLookDir, qFromMat4, qFromRotMat3x3, qMul, qNegate, qNlerp, qNormalize, qSet, qSlerp,
|
|
2457
|
+
export { CameraTrack, EYE, INVISIBLE, MATRIX, MODEL, NDC, ORIGIN, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP, PoseTrack, SCREEN, SEMIVISIBLE, VISIBLE, WEBGL, WEBGPU, WORLD, _i, _j, _k, boxVisibility, distanceToPlane, frustumPlanes, hermiteVec3, i, j, k, lerpVec3, mapDirection, mapLocation, mat3Direction, mat3NormalFromMat4, mat4Bias, mat4Eye, mat4FromBasis, mat4FromScale, mat4FromTRS, mat4FromTranslation, mat4Invert, mat4Location, mat4MV, mat4Mul, mat4MulDir, mat4MulPoint, mat4Ortho, mat4PV, mat4Persp, mat4Pick, mat4Reflect, mat4ToRotation, mat4ToScale, mat4ToTransform, mat4ToTranslation, mat4View, pixelRatio, pointVisibility, projBottom, projFar, projFov, projHfov, projIsOrtho, projLeft, projNear, projRight, projTop, qCopy, qDot, qFromAxisAngle, qFromLookDir, qFromMat4, qFromRotMat3x3, qMul, qNegate, qNlerp, qNormalize, qSet, qSlerp, qToAxisAngle, qToMat4, sphereVisibility, transformToMat4 };
|
|
2296
2458
|
//# sourceMappingURL=index.js.map
|