@rig-c/play 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -0
- package/dist/index.js +183 -15
- package/dist/index.js.map +1 -1
- package/dist/player.d.ts +81 -3
- package/dist/player.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -643,6 +643,63 @@ physics state) and nothing when no physics hangs under a re-posed bone. Three li
|
|
|
643
643
|
- A later `seek` replays from the start with the sets then active, as it
|
|
644
644
|
always has, so it does not reproduce a carried switch.
|
|
645
645
|
|
|
646
|
+
**Easing a drawn set in and out** (#174). A drawn set snaps its bones to the
|
|
647
|
+
drawn angles in one frame. `ease` turns them there over a duration instead,
|
|
648
|
+
and swaps the attachments halfway, the way an alternate drawing takes over
|
|
649
|
+
at a middle angle:
|
|
650
|
+
|
|
651
|
+
```ts
|
|
652
|
+
player.setSets(['wave_r'], { ease: 0.5 }); // also setSet, addSet, removeSet
|
|
653
|
+
player.setSets([], { ease: 0.5 }); // and back
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
- **The curve.** Each bone whose drawn rotation the call adds, removes or
|
|
657
|
+
changes turns from what it shows to its new local rotation along the
|
|
658
|
+
shorter way: `start + shortestΔ(start, end) · smoothstep(u)`, with
|
|
659
|
+
`u = elapsed / ease`. Going on, the start is the clip's value at the time
|
|
660
|
+
(it moves with the clip) and the end the drawn local; going off, the start
|
|
661
|
+
is the drawn local and the end the clip's value. So the progress from start
|
|
662
|
+
to end never leaves `[0, 1]` and never turns back, while the clip plays
|
|
663
|
+
underneath. On `@rig-c/parts`' public wind example with its gesture set
|
|
664
|
+
(`wave_r`, 0.5 s), it is 0 to 1 and non-decreasing on every frame, on and
|
|
665
|
+
off; on a clip that holds the arm still, the sleeve's world angle goes
|
|
666
|
+
−119.32° → −110° and back with no overshoot.
|
|
667
|
+
- **The swap.** The held pose draws the attachments it showed until the frame
|
|
668
|
+
whose `u` is nearest ½, then the set's (a tie goes to the later frame; the
|
|
669
|
+
next step is predicted from the current one, so a constant `dt` lands on
|
|
670
|
+
the nearest frame). On the wind example at `frame(1/60)`, 0.5 s swaps on
|
|
671
|
+
frame 15 and 0.25 s on frame 8. `activeSets`, `set` and `slotIdentity().sets`
|
|
672
|
+
name the call's sets from the call on; `slotIdentity().slots` reports what
|
|
673
|
+
the pose draws, so before the swap it shows the previous attachments.
|
|
674
|
+
- **The end.** On the frame the elapsed time reaches `ease`, the player is in
|
|
675
|
+
exactly the instant switch's state: from then on every bone matches an
|
|
676
|
+
instant switch made at the same frame (0° measured) and the slot identity
|
|
677
|
+
too.
|
|
678
|
+
- **Time.** The elapsed time is the player's step (`dt × timeScale`): a
|
|
679
|
+
paused player, or a step of 0, holds the ease where it is. Before `play`
|
|
680
|
+
there is nothing to step and the switch is instant; so is a call that
|
|
681
|
+
re-poses no bone. A `seek` or a skin change lands an ease in flight at
|
|
682
|
+
once.
|
|
683
|
+
- **A call during an ease** starts a new one from the angles shown (no jump:
|
|
684
|
+
reversing a 0.5 s ease at 0.3 makes no frame-to-frame step larger than the
|
|
685
|
+
ease's own), and the attachment swap starts again from what is drawn. A
|
|
686
|
+
call without `ease` during an ease lands it at once.
|
|
687
|
+
- `ease: 0`, or no `ease`, is the instant switch, frame for frame. Anything
|
|
688
|
+
but a finite number at or above 0 is refused by name before anything
|
|
689
|
+
changes.
|
|
690
|
+
|
|
691
|
+
With physics: `ease` and `physics: 'carry'` carry the chains under the eased
|
|
692
|
+
bones on every eased frame — before each step, the turn the frame's blend
|
|
693
|
+
makes is read as #173's switch is (a trial pose at the previous time) and
|
|
694
|
+
the chains are moved by it — so the ease's own turn is not read as motion.
|
|
695
|
+
`physics: 'reset'` with `ease` restarts them once, at the call. On `drape`
|
|
696
|
+
(0.5 s raise, sleeve tips in the arm's frame): the ease alone moves the
|
|
697
|
+
sleeve up to 30 units a frame relative to the arm (the chain reads the turn
|
|
698
|
+
as motion), ease + carry at most 3.9 on the `idle` clip (its idle ranges are
|
|
699
|
+
1.5 hanging and 4.2 raised) and 2.3 on `shift` (0.85 and 0.07), where
|
|
700
|
+
gravity re-settles the chain in the turning arm's frame (with gravity at 0,
|
|
701
|
+
0.83 against 0.84).
|
|
702
|
+
|
|
646
703
|
`sets.json` keys are read strictly. Besides `slots`, `hides` and `drawn`, a
|
|
647
704
|
set may carry `drawnLength`, `registration` and `threshold`, which parts
|
|
648
705
|
writes and which place nothing under `check --set`: play reads past them by
|
package/dist/index.js
CHANGED
|
@@ -8962,6 +8962,20 @@ function frameOf(source, pose, color = [1, 1, 1, 1], draws = () => true) {
|
|
|
8962
8962
|
return { order };
|
|
8963
8963
|
}
|
|
8964
8964
|
const DEFAULT_ENVIRONMENT = Object.freeze({ wind: Object.freeze([1, 0]), gravity: Object.freeze([0, 1]) });
|
|
8965
|
+
function setEaseOption(call, options) {
|
|
8966
|
+
const ease = options?.ease;
|
|
8967
|
+
if (ease === void 0) return 0;
|
|
8968
|
+
if (typeof ease !== "number" || !Number.isFinite(ease) || ease < 0) {
|
|
8969
|
+
throw new Error(`${call}: options.ease must be a finite number of seconds at or above 0, got ${typeof ease === "number" ? String(ease) : JSON.stringify(ease)}`);
|
|
8970
|
+
}
|
|
8971
|
+
return ease;
|
|
8972
|
+
}
|
|
8973
|
+
function easeProgress(ease) {
|
|
8974
|
+
return Math.min(Math.max(ease.elapsed / ease.duration, 0), 1);
|
|
8975
|
+
}
|
|
8976
|
+
function smoothstep(u) {
|
|
8977
|
+
return u * u * (3 - 2 * u);
|
|
8978
|
+
}
|
|
8965
8979
|
function setPhysicsOption(call, options) {
|
|
8966
8980
|
if (options === void 0) return void 0;
|
|
8967
8981
|
if (options === null || typeof options !== "object") {
|
|
@@ -9285,6 +9299,12 @@ class RigPlayer {
|
|
|
9285
9299
|
drawnPose = null;
|
|
9286
9300
|
/** Test-only (#173's planted control): `carry` maps every state through the identity instead of the anchor's turn. Not API. */
|
|
9287
9301
|
carryPlant = false;
|
|
9302
|
+
/** An eased set switch in flight (#174), or null. */
|
|
9303
|
+
easing = null;
|
|
9304
|
+
/** The last positive step `advance` took: what predicts the next one when an ease starts. */
|
|
9305
|
+
lastStep = 0;
|
|
9306
|
+
/** Test-only (#174's planted controls): swap the attachments at u = 0, or ease by w = 1.2u (1 at u = 1). Not API. */
|
|
9307
|
+
easePlant = null;
|
|
9288
9308
|
adjustFn = null;
|
|
9289
9309
|
/** Current preview patches, reapplied through the public core API on replay; no edit history. */
|
|
9290
9310
|
physicsPatches = /* @__PURE__ */ new Map();
|
|
@@ -9295,7 +9315,8 @@ class RigPlayer {
|
|
|
9295
9315
|
draws = () => true;
|
|
9296
9316
|
/** Handed to every track the player opens; reads the current `adjust` so setting it later needs no reopen. */
|
|
9297
9317
|
adjustHook = (locals, ctx) => {
|
|
9298
|
-
if (this.
|
|
9318
|
+
if (this.easing !== null) this.applyEase(this.easing, locals);
|
|
9319
|
+
else if (this.drawnPose !== null) for (const [bone2, rotation] of this.drawnPose) locals.bone(bone2).rotation = rotation;
|
|
9299
9320
|
if (this.adjustFn !== null) this.adjustFn(locals, ctx);
|
|
9300
9321
|
};
|
|
9301
9322
|
listeners = {
|
|
@@ -9504,11 +9525,12 @@ class RigPlayer {
|
|
|
9504
9525
|
if (time > 0) this.stepTo(time);
|
|
9505
9526
|
return tracks;
|
|
9506
9527
|
}
|
|
9507
|
-
/** Stores `raw` and applies `activeSet
|
|
9528
|
+
/** Stores `raw` and applies the shown set (`activeSet`, or before an ease's swap the composition it eases from). Zero work when none. */
|
|
9508
9529
|
setRawPose(raw) {
|
|
9509
9530
|
this.rawPose = raw;
|
|
9510
9531
|
this.heldParameters = null;
|
|
9511
|
-
|
|
9532
|
+
const set = this.shownSet();
|
|
9533
|
+
this.pose = set === null ? raw : applySetToPose(this.view, raw, set);
|
|
9512
9534
|
this.poseGeneration++;
|
|
9513
9535
|
this.cachedIdentity = null;
|
|
9514
9536
|
}
|
|
@@ -9626,6 +9648,7 @@ class RigPlayer {
|
|
|
9626
9648
|
if (this.animation === null) throw new Error("seek before play: no animation is open");
|
|
9627
9649
|
if (!(time >= 0) || !Number.isFinite(time)) throw new Error(`seek time must be a finite time at or above 0, got ${String(time)}`);
|
|
9628
9650
|
if (this.beyondBase) throw new Error("seek is defined for a single animation on track 0; after a mix, another track, a queue or a clear the player cannot replay to a time — step it forward with frame/advance instead");
|
|
9651
|
+
this.easing = null;
|
|
9629
9652
|
const cache = this.ensureSeekCache();
|
|
9630
9653
|
const stepper = this.tracks ?? this.track;
|
|
9631
9654
|
const exactHit = cache.exact.get(time);
|
|
@@ -9781,6 +9804,8 @@ class RigPlayer {
|
|
|
9781
9804
|
if (this.pose === null) return;
|
|
9782
9805
|
const step = dt * this.timeScale;
|
|
9783
9806
|
if (this.paused || !(step > 0)) return;
|
|
9807
|
+
this.lastStep = step;
|
|
9808
|
+
if (this.easing !== null) this.advanceEase(this.easing, step);
|
|
9784
9809
|
const tracks = this.tracks;
|
|
9785
9810
|
if (tracks !== null) {
|
|
9786
9811
|
const before2 = [];
|
|
@@ -9823,6 +9848,7 @@ class RigPlayer {
|
|
|
9823
9848
|
this.source = frameSource(view, this.read.parsed);
|
|
9824
9849
|
this.skinName = name;
|
|
9825
9850
|
this.setup = null;
|
|
9851
|
+
this.easing = null;
|
|
9826
9852
|
this.clearSeekCache();
|
|
9827
9853
|
if (this.animation !== null && (this.track !== null || this.tracks !== null)) {
|
|
9828
9854
|
const time = this.time;
|
|
@@ -9881,7 +9907,8 @@ class RigPlayer {
|
|
|
9881
9907
|
throw new Error(`cannot setSet(${JSON.stringify(name)}): this model has no sets.json`);
|
|
9882
9908
|
}
|
|
9883
9909
|
const physics = setPhysicsOption("setSet", options);
|
|
9884
|
-
|
|
9910
|
+
const ease = setEaseOption("setSet", options);
|
|
9911
|
+
this.activate(name === null ? [] : [this.namedSet(name)], physics, ease);
|
|
9885
9912
|
}
|
|
9886
9913
|
/**
|
|
9887
9914
|
* Makes exactly `names` the active attachment sets (#168), together: each
|
|
@@ -9903,19 +9930,42 @@ class RigPlayer {
|
|
|
9903
9930
|
* under a re-posed bone. A later `seek` replays from the start with the sets
|
|
9904
9931
|
* then active and does not reproduce a carried switch. `setSet`, `addSet`
|
|
9905
9932
|
* and `removeSet` take the same option.
|
|
9933
|
+
*
|
|
9934
|
+
* `options.ease` (#174, seconds, a finite number at or above 0) eases the
|
|
9935
|
+
* bones the call re-poses instead of snapping them. Each bone whose drawn
|
|
9936
|
+
* rotation the call adds, removes or changes turns from what it shows to
|
|
9937
|
+
* its new local rotation along the shorter way, as
|
|
9938
|
+
* `start + shortestΔ(start, end) · smoothstep(elapsed / ease)`: going on,
|
|
9939
|
+
* from the clip's value at the time to the drawn local; going off, from the
|
|
9940
|
+
* drawn local to the clip's value. The attachments the pose draws stay the
|
|
9941
|
+
* previous ones until the frame whose `elapsed / ease` is nearest ½ (the
|
|
9942
|
+
* next step predicted from the current one; a tie goes to the later frame),
|
|
9943
|
+
* then become the call's; `activeSets` and `slotIdentity().sets` name the
|
|
9944
|
+
* call's sets at once, while `slotIdentity().slots` follows what is drawn.
|
|
9945
|
+
* On the frame the elapsed time reaches `ease` the player is in exactly the
|
|
9946
|
+
* instant switch's state. The elapsed time is the player's step
|
|
9947
|
+
* (`dt × timeScale`), so a paused player or a zero step holds the ease;
|
|
9948
|
+
* before `play`, or when no bone's rotation changes, the switch is instant.
|
|
9949
|
+
* A call during an ease eases again from the angles shown (a call without
|
|
9950
|
+
* `ease` lands it at once), and `seek` or a skin change lands it at once.
|
|
9951
|
+
* With `physics: 'carry'` the chains under the eased bones are carried on
|
|
9952
|
+
* every eased frame, by the turn that frame's blend makes; with `'reset'`
|
|
9953
|
+
* they restart once, at the call. `0` or absent is the instant switch on
|
|
9954
|
+
* the same code path; anything else throws by name before anything changes.
|
|
9906
9955
|
*/
|
|
9907
9956
|
setSets(names, options) {
|
|
9908
9957
|
if (this.setList.length === 0) {
|
|
9909
9958
|
throw new Error(`cannot setSets(${JSON.stringify(names)}): this model has no sets.json`);
|
|
9910
9959
|
}
|
|
9911
9960
|
const physics = setPhysicsOption("setSets", options);
|
|
9961
|
+
const ease = setEaseOption("setSets", options);
|
|
9912
9962
|
const sets = names.map((name) => this.namedSet(name));
|
|
9913
9963
|
for (let i = 0; i < sets.length; i++) {
|
|
9914
9964
|
for (let j = 0; j < i; j++) {
|
|
9915
9965
|
if (sets[i] === sets[j]) throw new Error(`set ${JSON.stringify(sets[i].name)} is named twice in setSets`);
|
|
9916
9966
|
}
|
|
9917
9967
|
}
|
|
9918
|
-
this.activate(sets, physics);
|
|
9968
|
+
this.activate(sets, physics, ease);
|
|
9919
9969
|
}
|
|
9920
9970
|
/**
|
|
9921
9971
|
* Activates `name` beside the sets already active (#168): a set already
|
|
@@ -9927,9 +9977,10 @@ class RigPlayer {
|
|
|
9927
9977
|
throw new Error(`cannot addSet(${JSON.stringify(name)}): this model has no sets.json`);
|
|
9928
9978
|
}
|
|
9929
9979
|
const physics = setPhysicsOption("addSet", options);
|
|
9980
|
+
const ease = setEaseOption("addSet", options);
|
|
9930
9981
|
const found = this.namedSet(name);
|
|
9931
9982
|
if (this.activeList.includes(found)) return;
|
|
9932
|
-
this.activate([...this.activeList, found], physics);
|
|
9983
|
+
this.activate([...this.activeList, found], physics, ease);
|
|
9933
9984
|
}
|
|
9934
9985
|
/**
|
|
9935
9986
|
* Deactivates `name`, keeping every other active set (#168). An unknown name
|
|
@@ -9940,9 +9991,10 @@ class RigPlayer {
|
|
|
9940
9991
|
throw new Error(`cannot removeSet(${JSON.stringify(name)}): this model has no sets.json`);
|
|
9941
9992
|
}
|
|
9942
9993
|
const physics = setPhysicsOption("removeSet", options);
|
|
9994
|
+
const ease = setEaseOption("removeSet", options);
|
|
9943
9995
|
const found = this.namedSet(name);
|
|
9944
9996
|
if (!this.activeList.includes(found)) return;
|
|
9945
|
-
this.activate(this.activeList.filter((s) => s !== found), physics);
|
|
9997
|
+
this.activate(this.activeList.filter((s) => s !== found), physics, ease);
|
|
9946
9998
|
}
|
|
9947
9999
|
/** The declared set named `name`, or a throw naming it and the available sets. */
|
|
9948
10000
|
namedSet(name) {
|
|
@@ -9990,16 +10042,16 @@ class RigPlayer {
|
|
|
9990
10042
|
}
|
|
9991
10043
|
/**
|
|
9992
10044
|
* The physics under the bones a set switch re-poses (#173), before the
|
|
9993
|
-
* repose step: the
|
|
9994
|
-
*
|
|
10045
|
+
* repose step: the `changed` bones' rotations went from what the held pose
|
|
10046
|
+
* shows to what the player now applies (`drawnPose`, or an ease's next
|
|
10047
|
+
* blend, #174), and every physics constraint whose bone is one of the
|
|
9995
10048
|
* changed bones or a descendant of one is carried or reset. Nothing to do
|
|
9996
10049
|
* before `play` (the setup pose carries no physics state) or when no
|
|
9997
10050
|
* constraint hangs under a changed bone.
|
|
9998
10051
|
*/
|
|
9999
|
-
handOverPhysics(
|
|
10052
|
+
handOverPhysics(changed, mode) {
|
|
10000
10053
|
const stepper = this.tracks ?? this.track;
|
|
10001
10054
|
if (stepper === null || this.pose === null || this.rawPose === null) return;
|
|
10002
|
-
const changed = drawnChanged(before, after);
|
|
10003
10055
|
if (changed.size === 0) return;
|
|
10004
10056
|
const parentOf = new Map(this.view.bones.map((b) => [b.name, b.parent]));
|
|
10005
10057
|
const anchorOf = (bone2) => {
|
|
@@ -10079,11 +10131,112 @@ class RigPlayer {
|
|
|
10079
10131
|
s.ty = c * tx + d * s.ty;
|
|
10080
10132
|
}
|
|
10081
10133
|
}
|
|
10134
|
+
/**
|
|
10135
|
+
* The composition the held pose draws: `activeSet`, except before an ease's
|
|
10136
|
+
* swap (#174), when it is the composition the ease started from.
|
|
10137
|
+
*/
|
|
10138
|
+
shownSet() {
|
|
10139
|
+
const easing = this.easing;
|
|
10140
|
+
return easing === null || easing.swapped ? this.activeSet : easing.fromSet;
|
|
10141
|
+
}
|
|
10142
|
+
/** The local an eased bone shows at the ease's current progress, given the clip's local `clip`. */
|
|
10143
|
+
easedLocal(easing, from, to, clip) {
|
|
10144
|
+
const start = from ?? clip;
|
|
10145
|
+
const end = to ?? clip;
|
|
10146
|
+
const u = easeProgress(easing);
|
|
10147
|
+
const w = this.easePlant === "overshoot" ? u < 1 ? 1.2 * u : 1 : smoothstep(u);
|
|
10148
|
+
return start + normaliseDegrees(end - start) * w;
|
|
10149
|
+
}
|
|
10150
|
+
/**
|
|
10151
|
+
* The ease's part of `adjustHook` (#174): every drawn bone the ease does not
|
|
10152
|
+
* turn takes its drawn local, as without an ease; every eased bone reads
|
|
10153
|
+
* the clip's local (what the timelines left) and then takes its blend.
|
|
10154
|
+
*/
|
|
10155
|
+
applyEase(easing, locals) {
|
|
10156
|
+
for (const bone2 of easing.bones.keys()) easing.clip.set(bone2, locals.bone(bone2).rotation);
|
|
10157
|
+
if (this.drawnPose !== null) {
|
|
10158
|
+
for (const [bone2, rotation] of this.drawnPose) if (!easing.bones.has(bone2)) locals.bone(bone2).rotation = rotation;
|
|
10159
|
+
}
|
|
10160
|
+
for (const [bone2, { from, to }] of easing.bones) {
|
|
10161
|
+
locals.bone(bone2).rotation = this.easedLocal(easing, from, to, easing.clip.get(bone2));
|
|
10162
|
+
}
|
|
10163
|
+
}
|
|
10164
|
+
/**
|
|
10165
|
+
* Starts an eased switch (#174) to the sets already made active, from what
|
|
10166
|
+
* the held pose shows: an eased bone's start is the local it shows (fixed),
|
|
10167
|
+
* or the clip's value for a bone that showed the clip's; its end is the new
|
|
10168
|
+
* drawn local, or the clip's value for a bone whose set went. Returns false,
|
|
10169
|
+
* changing nothing, when there is nothing to ease — before `play` (no step
|
|
10170
|
+
* to ease over) or when no bone's rotation changes — and the call is then
|
|
10171
|
+
* an instant one.
|
|
10172
|
+
*/
|
|
10173
|
+
startEase(duration, shownBefore, drawn, physics) {
|
|
10174
|
+
const stepper = this.tracks ?? this.track;
|
|
10175
|
+
if (stepper === null || this.pose === null) return false;
|
|
10176
|
+
const before = this.drawnPose;
|
|
10177
|
+
const after = drawn === void 0 ? null : drawnLocals(this.view, drawn);
|
|
10178
|
+
const previous = this.easing;
|
|
10179
|
+
const candidates = drawnChanged(before, after);
|
|
10180
|
+
if (previous !== null) for (const bone2 of previous.bones.keys()) candidates.add(bone2);
|
|
10181
|
+
const bones = /* @__PURE__ */ new Map();
|
|
10182
|
+
for (const bone2 of candidates) {
|
|
10183
|
+
const to = after?.get(bone2) ?? null;
|
|
10184
|
+
let from;
|
|
10185
|
+
const eased = previous?.bones.get(bone2);
|
|
10186
|
+
if (previous !== null && eased !== void 0) {
|
|
10187
|
+
from = previous.elapsed > 0 ? this.easedLocal(previous, eased.from, eased.to, previous.clip.get(bone2)) : eased.from;
|
|
10188
|
+
} else {
|
|
10189
|
+
from = before?.get(bone2) ?? null;
|
|
10190
|
+
}
|
|
10191
|
+
if (from === to) continue;
|
|
10192
|
+
bones.set(bone2, { from, to });
|
|
10193
|
+
}
|
|
10194
|
+
if (bones.size === 0) return false;
|
|
10195
|
+
const easing = {
|
|
10196
|
+
duration,
|
|
10197
|
+
elapsed: 0,
|
|
10198
|
+
bones,
|
|
10199
|
+
clip: /* @__PURE__ */ new Map(),
|
|
10200
|
+
fromSet: shownBefore,
|
|
10201
|
+
swapped: false,
|
|
10202
|
+
physics
|
|
10203
|
+
};
|
|
10204
|
+
if (this.easePlant === "swap-at-0" || this.swapsNow(0, this.lastStep / duration)) easing.swapped = true;
|
|
10205
|
+
this.easing = easing;
|
|
10206
|
+
this.drawnPose = after;
|
|
10207
|
+
if (physics === "reset") this.handOverPhysics(new Set(bones.keys()), "reset");
|
|
10208
|
+
this.reposeDrawn();
|
|
10209
|
+
return true;
|
|
10210
|
+
}
|
|
10211
|
+
/**
|
|
10212
|
+
* Whether the frame at progress `u` is the one nearest ½, the next frame
|
|
10213
|
+
* being at `next`: it is when `u` reached ½ or the next one would be
|
|
10214
|
+
* farther from it; a tie (within 1e-9) goes to the later frame.
|
|
10215
|
+
*/
|
|
10216
|
+
swapsNow(u, next) {
|
|
10217
|
+
if (u >= 0.5) return true;
|
|
10218
|
+
return next > u && 0.5 - u < next - 0.5 - 1e-9;
|
|
10219
|
+
}
|
|
10220
|
+
/**
|
|
10221
|
+
* One step of an eased switch (#174), before the track steps: the elapsed
|
|
10222
|
+
* time advances by the step, the attachments swap when this is the frame
|
|
10223
|
+
* nearest ½ (`swapsNow`, the next step predicted by this one), and the
|
|
10224
|
+
* ease ends — the instant switch's state, `drawnPose` alone — on the frame
|
|
10225
|
+
* it reaches its duration. With `physics: 'carry'`, the chains under the
|
|
10226
|
+
* eased bones are carried by the turn this frame's blend makes, read by a
|
|
10227
|
+
* trial `step(0)` at the previous time (`handOverPhysics`).
|
|
10228
|
+
*/
|
|
10229
|
+
advanceEase(easing, step) {
|
|
10230
|
+
easing.elapsed += step;
|
|
10231
|
+
if (easing.elapsed >= easing.duration) this.easing = null;
|
|
10232
|
+
else if (!easing.swapped && this.swapsNow(easing.elapsed / easing.duration, (easing.elapsed + step) / easing.duration)) easing.swapped = true;
|
|
10233
|
+
if (easing.physics === "carry") this.handOverPhysics(new Set(easing.bones.keys()), "carry");
|
|
10234
|
+
}
|
|
10082
10235
|
/**
|
|
10083
10236
|
* Makes `sets` (distinct) the active sets: refuses any two touching one slot
|
|
10084
10237
|
* before changing anything, then applies their composition to the held pose.
|
|
10085
10238
|
*/
|
|
10086
|
-
activate(sets, physics) {
|
|
10239
|
+
activate(sets, physics, ease = 0) {
|
|
10087
10240
|
for (let i = 0; i < sets.length; i++) {
|
|
10088
10241
|
for (let j = 0; j < i; j++) {
|
|
10089
10242
|
const other = this.touched(sets[j]);
|
|
@@ -10105,14 +10258,27 @@ class RigPlayer {
|
|
|
10105
10258
|
}
|
|
10106
10259
|
}
|
|
10107
10260
|
const drawnBefore = this.activeSet?.drawn;
|
|
10261
|
+
const shownBefore = this.shownSet();
|
|
10108
10262
|
this.activeList = this.setList.filter((s) => sets.includes(s));
|
|
10109
10263
|
this.activeSet = composeSets(this.activeList);
|
|
10110
10264
|
this.clearSeekCache();
|
|
10111
10265
|
const drawn = this.activeSet?.drawn;
|
|
10266
|
+
if (ease > 0 && this.startEase(ease, shownBefore, drawn, physics)) return;
|
|
10267
|
+
const easing = this.easing;
|
|
10268
|
+
if (easing !== null) {
|
|
10269
|
+
this.easing = null;
|
|
10270
|
+
const posedBefore = this.drawnPose;
|
|
10271
|
+
this.drawnPose = drawn === void 0 ? null : drawnLocals(this.view, drawn);
|
|
10272
|
+
const changed = drawnChanged(posedBefore, this.drawnPose);
|
|
10273
|
+
for (const bone2 of easing.bones.keys()) changed.add(bone2);
|
|
10274
|
+
if (physics !== void 0) this.handOverPhysics(changed, physics);
|
|
10275
|
+
this.reposeDrawn();
|
|
10276
|
+
return;
|
|
10277
|
+
}
|
|
10112
10278
|
if (drawn !== drawnBefore && !(drawn === void 0 && drawnBefore === void 0)) {
|
|
10113
10279
|
const posedBefore = this.drawnPose;
|
|
10114
10280
|
this.drawnPose = drawn === void 0 ? null : drawnLocals(this.view, drawn);
|
|
10115
|
-
if (physics !== void 0) this.handOverPhysics(posedBefore, this.drawnPose, physics);
|
|
10281
|
+
if (physics !== void 0) this.handOverPhysics(drawnChanged(posedBefore, this.drawnPose), physics);
|
|
10116
10282
|
this.reposeDrawn();
|
|
10117
10283
|
return;
|
|
10118
10284
|
}
|
|
@@ -10304,9 +10470,10 @@ class RigPlayer {
|
|
|
10304
10470
|
const setupShownSlots = new Set(setupPose.shown.map((s) => s.slot));
|
|
10305
10471
|
const rawRowBySlot = new Map(raw.slots.map((r) => [r[0], r]));
|
|
10306
10472
|
const slots = [];
|
|
10473
|
+
const shownSet = this.shownSet();
|
|
10307
10474
|
for (let z = 0; z < pose.drawOrder.length; z++) {
|
|
10308
10475
|
const slotName = pose.drawOrder[z];
|
|
10309
|
-
if (
|
|
10476
|
+
if (shownSet !== null && hiddenBySet(slotName, shownSet)) {
|
|
10310
10477
|
slots.push(Object.freeze({
|
|
10311
10478
|
slot: slotName,
|
|
10312
10479
|
z,
|
|
@@ -10341,7 +10508,7 @@ class RigPlayer {
|
|
|
10341
10508
|
continue;
|
|
10342
10509
|
}
|
|
10343
10510
|
const rawRow = rawRowBySlot.get(slotName);
|
|
10344
|
-
const overriddenBySet =
|
|
10511
|
+
const overriddenBySet = shownSet !== null && slotName in shownSet.slots;
|
|
10345
10512
|
const setupHadAttachment = setupShownSlots.has(slotName);
|
|
10346
10513
|
const isTimelineNull = !overriddenBySet && (setupHadAttachment && rawRow?.[1] === null || this.isSlotKeyedNullByTimeline(slotName, raw.animationTime));
|
|
10347
10514
|
slots.push(Object.freeze({
|
|
@@ -10406,6 +10573,7 @@ class RigPlayer {
|
|
|
10406
10573
|
this.renderer.dispose();
|
|
10407
10574
|
this.clearSeekCache();
|
|
10408
10575
|
this.cachedIdentity = null;
|
|
10576
|
+
this.easing = null;
|
|
10409
10577
|
this.tracks = null;
|
|
10410
10578
|
this.track = null;
|
|
10411
10579
|
this.pose = null;
|