@rig-c/pose 0.31.0 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -200,7 +200,7 @@ Re-checked on a @rig-c/parts fixture rig with the short hold, the flip guard and
200
200
 
201
201
  A knee bending toward the camera is seen from the front only as a shorter leg, and a rig with rigid legs cannot lower its hip without lifting its feet ([#47](https://github.com/rig-c/pose/issues/47)). Two flags, both off by default:
202
202
 
203
- **`--leg-scale <min,max>`** scales each mapped leg segment (two of one side's hip, knee and ankle) along its own x axis — a `scalex` key — by its picture length on the frame over its **straight length**, the larger of the two sides' 95th-percentile picture lengths for that segment over the sequence ([#148](https://github.com/rig-c/pose/issues/148), weighted by the segment's share of the two legs' mean setup bone length when the rig's setup legs differ by more than 0.1 % so an asymmetrically drawn rig places both ankles at the sequence's relative height, [#225](https://github.com/rig-c/pose/issues/225); on a non-`in-place` sequence longer than 25 frames, each frame's segment length is normalised by a continuous rate-limited figure-scale signal `figureScaleOf` derived from posture- and crouch-invariant segment measures — `max(r_thigh + r_shin, l_thigh + l_shin)` plus the `mid_hip → mid_shoulder` trunk segment held at each support span's 95th-percentile straight length when the 5-series consensus moves past ±2 %, never vertical `ankle.y − nose.y` — with frame-to-frame step ≤ 1 % and frozen spans ≥ 5 frames held at their median, so neither camera zoom, a forward trunk bend nor a landing crouch reads as the figure changing size, and `--camera <file>` writes that track as `rig-pose-camera/1` without changing `motion.json`, [#159](https://github.com/rig-c/pose/issues/159), [#161](https://github.com/rig-c/pose/issues/161), [#163](https://github.com/rig-c/pose/issues/163), [#172](https://github.com/rig-c/pose/issues/172), [#226](https://github.com/rig-c/pose/issues/226)), clamped to [min, max]. When the camera-normalised trunk (`neck → mid_hip` or `mid_shoulder → mid_hip`) foreshortens or extends by more than 4 % from its standing length, the trunk bone is keyed in `scaley` (for a `+y`-aimed trunk, `scalex` for `+x`) clamped to the same `[min, max]` bounds, carrying the trunk and head's depth bend while keeping the aimed rotation ([#172](https://github.com/rig-c/pose/issues/172)). The bounds are `<min,max>` with `0 < min ≤ 1 ≤ max`. A segment the map aims other than `"x"` is refused (`LEGS_MAP`). `LEG-SCALE` lists each segment's frames clamped at either limit with the unclamped `asked` scale range on each clamped run (`legScale[].clamped` in `--report`, `{ frames, times, limit, asked: { min, max } }`, [#225](https://github.com/rig-c/pose/issues/225)).
203
+ **`--leg-scale <min,max>`** scales each mapped leg segment (two of one side's hip, knee and ankle) along its own x axis — a `scalex` key — by its picture length on the frame over its **straight length**, the larger of the two sides' 95th-percentile picture lengths for that segment over the sequence ([#148](https://github.com/rig-c/pose/issues/148), weighted by the segment's share of the two legs' mean setup bone length when the rig's setup legs differ by more than 0.1 % so an asymmetrically drawn rig places both ankles at the sequence's relative height, [#225](https://github.com/rig-c/pose/issues/225); on a non-`in-place` sequence longer than 25 frames, each frame's segment length is normalised by a continuous rate-limited figure-scale signal `figureScaleOf` derived from posture- and crouch-invariant segment measures — `max(r_thigh + r_shin, l_thigh + l_shin)` plus the `mid_hip → mid_shoulder` trunk segment held at each support span's 95th-percentile straight length and ramped linearly across non-support airborne gaps into a larger incoming support span when the 5-series consensus moves past ±2 %, never vertical `ankle.y − nose.y` — with frame-to-frame step ≤ 1 % and frozen spans ≥ 5 frames held at their median, so neither camera zoom, a forward trunk bend nor a landing crouch reads as the figure changing size or steps the denominator on landing, and `--camera <file>` writes that track as `rig-pose-camera/1` without changing `motion.json`, [#159](https://github.com/rig-c/pose/issues/159), [#161](https://github.com/rig-c/pose/issues/161), [#163](https://github.com/rig-c/pose/issues/163), [#172](https://github.com/rig-c/pose/issues/172), [#226](https://github.com/rig-c/pose/issues/226), [#231](https://github.com/rig-c/pose/issues/231)), clamped to [min, max]. When the camera-normalised trunk (`neck → mid_hip` or `mid_shoulder → mid_hip`) foreshortens or extends by more than 4 % from its standing length, the trunk bone is keyed in `scaley` (for a `+y`-aimed trunk, `scalex` for `+x`) clamped to the same `[min, max]` bounds, carrying the trunk and head's depth bend while keeping the aimed rotation ([#172](https://github.com/rig-c/pose/issues/172)). The bounds are `<min,max>` with `0 < min ≤ 1 ≤ max`. A segment the map aims other than `"x"` is refused (`LEGS_MAP`). `LEG-SCALE` lists each segment's frames clamped at either limit with the unclamped `asked` scale range on each clamped run (`legScale[].clamped` in `--report`, `{ frames, times, limit, asked: { min, max } }`, [#225](https://github.com/rig-c/pose/issues/225)).
204
204
 
205
205
  rig-c's `scalex` multiplies the bone's x axis, and a child with the `normal` inherit mode takes its parent's whole world matrix. So under a thigh scaled by s, a shin at angle φ in the thigh's axes points at atan2(sin φ, s·cos φ), and is itself scaled by |(s·cos φ, sin φ)|. A child (or its intermediate control bone) with `noScale` or `noScaleOrReflection` ([#153](https://github.com/rig-c/pose/issues/153)) still has its direction carried through the parent's scaled matrix, so its angle is skewed the same way, while rig-c normalises that direction to unit length so the parent's scale is not inherited. The rotate key `turn − turn above` assumes unit scale. A mapped bone under a scaled bone is therefore keyed through its parent's posed matrix: a `rotate` key k and a `scalex` key s' put its world x axis on its target at the scale asked (under `noScale`, s' is the bone's own asked scale s directly). On `dance-a` the unit-scale formula missed the shins by up to 2.4°, their length by 0.16 of setup and the ankles by 38 units; solved, every bone lands. A `normal` child's art is still sheared by its parent's scale, and a bone under it (a foot) is squashed along the shin: `SHEAR` reads both.
206
206
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rig-c/pose",
3
- "version": "0.31.0",
3
+ "version": "0.31.1",
4
4
  "description": "Puts motion from a body-18 pose sequence onto a rig built with rig-c: bone keys in rig-c's motion format, checked through rig-c's gate before anything is written. A CLI for agents that cannot see the rig.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/legs.ts CHANGED
@@ -942,7 +942,9 @@ export function figureScaleOf(raw: readonly number[], maxStep = FIGURE_SCALE_STE
942
942
  if (gap > 0) {
943
943
  const needed = Math.abs(b.val - a.val) / gap;
944
944
  if (needed > r0) {
945
- for (let i = a.hi; i < b.lo; i++) r[i] = needed * 1.0001;
945
+ for (let i = a.hi; i < b.lo; i++) {
946
+ r[i] = Math.max(needed, Math.abs(u[i + 1]! - u[i]!)) * 1.0001;
947
+ }
946
948
  }
947
949
  }
948
950
  }
package/src/retarget.ts CHANGED
@@ -845,9 +845,21 @@ export function retarget(rest: Rest, map: JointMap, frames: ReadonlyArray<Partia
845
845
  : legSum;
846
846
  const out = winPercentile(segH, 15, STRAIGHT_PERCENTILE);
847
847
  if (feet !== null) {
848
- for (const sp of feet.supports) {
849
- const m = percentile(segH.slice(sp.frames[0], sp.frames[1] + 1), STRAIGHT_PERCENTILE);
850
- for (let i = sp.frames[0]; i <= sp.frames[1]; i++) out[i] = m;
848
+ const ms = feet.supports.map((sp) => percentile(segH.slice(sp.frames[0], sp.frames[1] + 1), STRAIGHT_PERCENTILE));
849
+ feet.supports.forEach((sp, k) => {
850
+ for (let i = sp.frames[0]; i <= sp.frames[1]; i++) out[i] = ms[k]!;
851
+ });
852
+ for (let k = 0; k + 1 < feet.supports.length; k++) {
853
+ const a = feet.supports[k]!.frames[1] + 1;
854
+ const b = feet.supports[k + 1]!.frames[0] - 1;
855
+ if (a <= b && ms[k + 1]! > ms[k]!) {
856
+ const start = Math.max(ms[k]!, out[a]!);
857
+ const end = ms[k + 1]!;
858
+ for (let i = a; i <= b; i++) {
859
+ const u = b > a ? (i - a) / (b - a) : 1;
860
+ out[i] = start + (end - start) * u;
861
+ }
862
+ }
851
863
  }
852
864
  }
853
865
  return out;