Give machine props world-space 3D form that rotates with the camera
Scene shapes, cable anchors, bar angles, pad perpendiculars, and roller offsets all resolve in the authored view exactly as before, then rotate about the world-vertical axis through the root anchor - the same resolve-then-rotate pattern as the figure's pins and the mat - so at the authored yaw every exercise renders bit-identically to today, and under an orbiting camera the equipment turns with the figure while staying welded to its hands and feet. Scene lines gain an optional depth plane (z) and slab extrusion (depth) so seats, backrests, and platforms keep form edge-on; the rect shape is retired (re-authored as slab lines). All 14 machines' props re-authored with depths and verified at eight orbit angles. The fixture snapshots move into the pipeline as render.py --fixtures and now cover orbit-presentation samples with resolved prop primitives for a spread of prop flavors; the in-app renderer resolves props in MotionSolver (lockstep with resolve_props) and the view just draws primitives. Claude-Session: https://claude.ai/code/session_01HJDQQDA9QdP8zByg43H5v3
This commit is contained in:
+34
-17
@@ -132,8 +132,8 @@ scale drawings of the machine.
|
||||
```json
|
||||
"props": [
|
||||
{"type": "scene", "shapes": [
|
||||
{"kind": "line", "pts": [[134, 123], [96, 36]], "w": 9},
|
||||
{"kind": "rect", "x": 54, "y": 104, "w": 40, "h": 8, "r": 3},
|
||||
{"kind": "line", "pts": [[134, 123], [96, 36]], "w": 9, "depth": 8},
|
||||
{"kind": "line", "pts": [[160, 64], [160, 120]], "w": 16, "z": -14},
|
||||
{"kind": "circle", "c": [142, 77], "r": 3.5, "fill": true, "color": "prop"}
|
||||
]},
|
||||
{"type": "cable", "from": [190, 8], "to": ["hand_r", "hand_l"]},
|
||||
@@ -143,23 +143,37 @@ scale drawings of the machine.
|
||||
]
|
||||
```
|
||||
|
||||
- **`scene`** — static shapes in canvas coordinates: `line` (polyline, stroke
|
||||
width `w`), `circle` (`fill: false` for an outline), `rect` (filled, corner
|
||||
radius `r`). A shape may set `"color": "prop"` to use the darker
|
||||
attached-item gray (e.g. a fixed handle the hands rest on). Scene shapes
|
||||
are view-locked billboards — they don't rotate with `--orbit`.
|
||||
- **`cable`** — a thin line from a fixed anchor `from` to a moving joint `to`;
|
||||
the machine's pulley line.
|
||||
Props are authored in the authored view but have **world-space 3D form**:
|
||||
under an orbiting camera the whole equipment layer rotates about the
|
||||
world-vertical axis through the root anchor, exactly like the figure and the
|
||||
mat. Everything resolves in the *authored* view — scene points, cable
|
||||
anchors, bar angles, pad perpendiculars, roller offsets — and the resolved
|
||||
constructs are then rotated; joint-attached items keep following the rotated
|
||||
figure's hands and feet, so equipment stays welded to the body. At the
|
||||
authored yaw nothing moves, so the authored look is exact.
|
||||
|
||||
- **`scene`** — static shapes: `line` (polyline, stroke width `w`) and
|
||||
`circle` (`fill: false` for an outline). Points are canvas `[x, y]` (or
|
||||
`[x, y, z]` where needed); a shape-level `"z"` sets its depth plane
|
||||
(positive toward the camera), and a line with `"depth"` is a **slab** —
|
||||
extruded that half-width through its plane, it stays a plain line edge-on
|
||||
and opens into a swept quad as the camera orbits (seats, backrests,
|
||||
platforms). A shape may set `"color": "prop"` to use the darker
|
||||
attached-item gray (e.g. a fixed handle the hands rest on).
|
||||
- **`cable`** — a thin line from a fixed anchor `from` (`[x, y]` or
|
||||
`[x, y, z]`) to a moving joint `to`; the machine's pulley line.
|
||||
- **`bar` / `dumbbell` / `pad`** — a segment centered on the joint(s) in
|
||||
`at` (a single joint, or the midpoint of a list). Joints are the extremities
|
||||
(`hand_r`, `foot_l`, …) plus the mid joints (`elbow_r`, `knee_l`, …), so a
|
||||
machine pad can ride a knee (`["knee_r", "knee_l"]`) or span a shin
|
||||
(`["knee_r", "foot_r"]`).
|
||||
`bar` lies at a fixed world `angle` (default 0 = horizontal — in side view a
|
||||
two-handed bar is drawn horizontal by convention); `dumbbell` and `pad`
|
||||
default to perpendicular to the lower bone (forearm/shin), or take an
|
||||
explicit `angle`. `plateR` puts filled discs on both ends (dumbbells default
|
||||
to 4.5). A prop whose limb is hidden that frame simply isn't drawn.
|
||||
`bar` lies at a fixed authored-view `angle` (default 0 = horizontal — in
|
||||
side view a two-handed bar is drawn horizontal by convention); `dumbbell`
|
||||
and `pad` default to perpendicular to the lower bone (forearm/shin), or
|
||||
take an explicit `angle`. Under orbit the segment rotates with the scene
|
||||
and foreshortens naturally. `plateR` puts filled discs on both ends
|
||||
(dumbbells default to 4.5). A prop whose limb is hidden that frame simply
|
||||
isn't drawn.
|
||||
- **`roller`** — a machine roller pad seen end-on: a filled disc riding the
|
||||
limb's lower bone near the joint in `at`, on the `side` (+1/−1) of the bone
|
||||
it presses — a leg extension's instep roller (`side: 1`), a leg curl's
|
||||
@@ -179,6 +193,7 @@ python3 render.py --figure=female # render with another skeleton profile
|
||||
python3 render.py --flip # view from the other side (camera + 180°)
|
||||
python3 render.py --strict # fail on any ROM violation, listing each
|
||||
python3 render.py --export # bake app resources into Workouts/Resources/ExerciseMotions
|
||||
python3 render.py --fixtures # regenerate WorkoutsTests/Fixtures/figure-fixtures.json
|
||||
```
|
||||
|
||||
`render.py` needs only Pillow (for GIFs/sheets; the SVGs have no dependency).
|
||||
@@ -192,6 +207,8 @@ the `--export` copies ship: `skeleton.json` plus uniquely-named
|
||||
and the exercise-library reference screen (`ExerciseInfo.swift` parses the
|
||||
info pages). The in-app solver is a line-for-line port of `kinematics.py`,
|
||||
held to it by `WorkoutsTests/Fixtures/figure-fixtures.json` — projected
|
||||
geometry snapshots the Swift solver must reproduce; regenerate them alongside
|
||||
any pipeline change. Re-run `python3 render.py --export` after editing any
|
||||
motion or info page; the library stays the source of truth.
|
||||
geometry snapshots (figure and prop primitives, including orbit-presentation
|
||||
samples) the Swift solver must reproduce; regenerate with
|
||||
`python3 render.py --fixtures` alongside any pipeline change. Re-run
|
||||
`python3 render.py --export` after editing any motion or info page; the
|
||||
library stays the source of truth.
|
||||
|
||||
Reference in New Issue
Block a user