mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-31 13:37:37 -06:00
Effects: effect points on shape layers start at the layer centre (#227)
Shape and text layers have comp-sized effect bounds centred on their origin, but effects measured positions from the origin: a point at its default "layer centre" sat at the comp's bottom-right corner, so Twirl on a centred shape changed nothing and Bulge only its bottom-right quarter. As in After Effects, effects now work in effect space, measured from the top-left of the layer's effect bounds. The renderer moves the layer buffer into effect space for the whole stack (Buf::rebase, CPU and GPU alike) and hands effects everything else in it: masks, other layers' pixels for layer parameters (each in its own effect space, so Set Matte and displacement maps see a whole shape layer), the layer's own frames (layer_input, also what Puppet, Roto Brush and the Layer panel read) and the comp camera (CompScene::rebased). Layer bounds are now right for every effect, so pin_rect and EffectEnv::bounds_origin go and layer_rect serves edge pinning too. Adjustment layers still run on the comp below as it is. effect_bounds / EvalCtx::effect_to_comp replace the repeated "comp size when there is no source" code; the viewer's effect point handles and eyedroppers, Puppet pins, the Layer panel (paint, Roto Brush) and the tracker's Corner Pin output use them. Project schema 2: opening a schema 1 project moves positions held by effects on shape and text layers by half the comp size, so set points keep their place (point parameters with keyframes, Paint paths and clone positions, Puppet seeds and pins, Liquify and Roto Brush strokes). Points still at their default become the layer centre; expression controls, adjustment layers and expressions are left as they are (docs/architecture.md). The disk cache's render version is bumped. Tests: default_effect_points_sit_at_the_centre_of_a_shape_layer and layer_parameters_see_a_whole_shape_layer (render, both fail before), effect_points_on_a_shape_layer (GPU vs CPU), opening_a_schema_1_project_moves_shape_layer_effect_points_into_effect_space (engine), and the effects migration tests. Part of #227 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
52ab38fcff
commit
940bea3ba7
+11
-2
@@ -174,6 +174,15 @@ build real projects through these interfaces; they are worked examples of everyt
|
||||
Save / Don't Save / Cancel prompt (`ui_click` on `dialog.unsaved.save` / `dontSave` / `cancel`;
|
||||
`dialog.unsaved.revert` for Revert); the control channel's `app.quit {"force": true}` skips it.
|
||||
|
||||
### Effect positions
|
||||
|
||||
Effect points, Puppet pins (`puppet.addPin`, `puppet.recordPin`), Paint, Liquify and Roto Brush
|
||||
strokes and `effect.pickColor` are in **effect space**: layer pixels from the top-left of the
|
||||
layer's effect bounds. For footage, solids and precomps that is the layer's own pixel grid. Shape
|
||||
and text layers have comp-sized bounds centred on their content's origin, so in a `w` × `h` comp
|
||||
the point `[w / 2, h / 2]` is that origin (a new effect's default point). `prop.get` / `prop.set`
|
||||
read and write these values as they are.
|
||||
|
||||
### Motion tracking
|
||||
|
||||
Trackers live on the tracked layer (`Motion Trackers ▸ Tracker n ▸ Track Point n`) and are driven
|
||||
@@ -304,7 +313,7 @@ effectcraft-cli run shot.ecproj camera.createFromSolve '{"kind":"solid","points"
|
||||
|
||||
The Roto Brush tool (Alt+W cycles Roto Brush / Refine Edge) paints in the Layer panel; agents use
|
||||
`roto.stroke {layer, kind: fg|bg|refine|refineErase, points: [[x, y], …], frame?, radius?}`
|
||||
(layer pixels, layer frames). The first foreground stroke applies the Roto Brush & Refine Edge
|
||||
(effect space, layer frames). The first foreground stroke applies the Roto Brush & Refine Edge
|
||||
effect and sets the base frame with a span of 20 frames each side. `roto.propagate {layer,
|
||||
direction?: forward|backward|both, to?, wait?}` segments the span (in the background unless
|
||||
`wait`); strokes on any other frame correct it and propagation restarts from there.
|
||||
@@ -409,7 +418,7 @@ that closes the dialog). File ▸ Scripts: `file.scripts.list`, `file.runScript
|
||||
states as a branch); `edit.history.goto {"index": n}` (or `id`, or `steps`) jumps to any of
|
||||
them. MCP: the `history` tool.
|
||||
* `puppet.recordPin {"layer": "#1", "pin": "Puppet Pin 1", "samples": [[t, x, y]…]}` records a
|
||||
drag (t = seconds since it began, layer space) into Position keys at the comp frame rate from the
|
||||
drag (t = seconds since it began, effect space) into Position keys at the comp frame rate from the
|
||||
current time; `puppet.recordOptions {speed, smoothing, useDraftDeformation, showMesh}`.
|
||||
* `puppet.selectPins {"layer": "#1", "pins": ["Puppet Pin 1"], "add"?, "toggle"?}` selects pins
|
||||
like the viewer's click / Shift-click (`pins: []` deselects); Edit ▸ Clear (Delete) then removes
|
||||
|
||||
+34
-1
@@ -82,13 +82,46 @@ a file that a newer EffectCraft saved shows a warning: fields this version doesn
|
||||
dropped if it saves the project. Save, Save As, Save a Copy and Increment and Save keep the
|
||||
file's format (`.ecprojx` stays XML).
|
||||
|
||||
`schema` changes when a saved value changes meaning; a project from an older schema is converted
|
||||
when it is opened (`effectcraft_engine::upgrade_effects`, which also refreshes effect instances
|
||||
from the registry) and saved with the current one, which older versions refuse to open rather than
|
||||
render wrongly. Schema 2 put effect positions on shape and text layers in effect space (§4,
|
||||
#227). Opening a schema 1 project moves what an effect on a shape or text layer (not an adjustment
|
||||
layer, whose effects see the comp below as before) holds as a position by half the comp size,
|
||||
so points that were set keep their place in the comp: point parameters with their keyframes, Paint
|
||||
stroke paths and clone positions, Puppet mesh seeds, pin rest points and positions, and Liquify
|
||||
and Roto Brush strokes. A point parameter still at its default and not animated is left alone:
|
||||
the old default sat at the comp's bottom-right corner, where most effects did nothing, and the
|
||||
same value is now the layer centre, as in After Effects. Expression controls (Point Control…)
|
||||
keep their values, because their meaning is up to the expressions that read them, and expressions
|
||||
are not rewritten, so an expression that computes an effect point on a shape or text layer from
|
||||
other values may need `+ [thisComp.width / 2, thisComp.height / 2]`. Effects that use the layer
|
||||
bounds (edge pinning, wipes, Offset, generators) now cover the whole comp-sized bounds instead of
|
||||
their bottom-right quarter. Tracking data of effects that analyse footage (Warp Stabilizer, 3D
|
||||
Camera Tracker, Mocha shape) is left as it is: footage has a source rectangle, whose effect space
|
||||
did not change.
|
||||
|
||||
## 4. Rendering
|
||||
|
||||
`Renderer::comp_frame(comp, t)` walks the layers bottom to top. For each visible layer it renders
|
||||
the **source** (solid, footage frame, text, shape contents, or a nested comp), applies **masks**,
|
||||
then **effects** in order, then **layer styles**, then the **transform** into comp space (with motion blur sub-samples
|
||||
when enabled), the **track matte**, and finally **blends** into the accumulator. Adjustment layers
|
||||
apply their effects to the accumulator. Runs of 3D layers are composited per pixel through the
|
||||
apply their effects to the accumulator.
|
||||
|
||||
Effects run in **effect space** (`effectcraft_render::effect_bounds`): layer pixels measured from
|
||||
the top-left of the layer's effect bounds, which are the source rectangle, or for layers without
|
||||
one (shape, text) a comp-sized rectangle centred on the layer's origin that their content
|
||||
surrounds. A shape layer's default effect point (the bounds' centre) is therefore its content's
|
||||
origin, as in After Effects. The renderer moves the layer buffer into effect space for the whole
|
||||
stack (`Buf::rebase`, on the CPU and the GPU alike) and hands effects everything else in it too:
|
||||
masks, other layers' pixels for layer parameters (each in its own effect space), the layer's own
|
||||
frames at other times (`Renderer::layer_input`, also what Puppet, Roto Brush and the Layer panel
|
||||
read) and the comp camera. Effect point handles, Puppet pins and the Layer panel map effect space
|
||||
to the comp with `EvalCtx::effect_to_comp`. Adjustment layers run their effects on the comp below
|
||||
as it is.
|
||||
|
||||
Runs of 3D layers are composited per pixel through the
|
||||
active camera, with lights, shadows and depth of field (Classic 3D), or rasterised as meshes by
|
||||
the Advanced 3D renderer (below).
|
||||
|
||||
|
||||
@@ -108,6 +108,15 @@ The most important missing piece: it turns every other estimate here into a meas
|
||||
- Regression evidence for the Turbulent Displace, Wave Warp and Bulge pinning of #227:
|
||||
`edge_pinning_displaces_all_of_a_centred_shape_layer` (render) and
|
||||
`edge_pinning_on_a_shape_layer` (GPU against CPU).
|
||||
- Regression evidence for the effect points of #227 (shape and text layers measure effect points
|
||||
from the top-left of their comp-sized bounds, so Twirl, Bulge, CC Lens, Ripple and Turbulent
|
||||
Displace's Offset default to the layer centre): `default_effect_points_sit_at_the_centre_of_a_shape_layer`
|
||||
and `layer_parameters_see_a_whole_shape_layer` (render), `effect_points_on_a_shape_layer` (GPU
|
||||
against CPU), and the schema 1 → 2 conversion in
|
||||
`opening_a_schema_1_project_moves_shape_layer_effect_points_into_effect_space` (engine) and
|
||||
`effect_points_move_into_effect_space_unless_left_at_their_default` /
|
||||
`puppet_paint_liquify_and_roto_data_move_into_effect_space` (effects); see
|
||||
[architecture.md](architecture.md) §3 for what the conversion keeps.
|
||||
- Regression evidence for the interface items of [#227](https://github.com/storytold/effectcraft/issues/227),
|
||||
checked headlessly on Windows: `spacebar_taps_preview_and_held_spacebar_pans_the_viewer` and
|
||||
`spacebar_drag_scrolls_the_time_graph` (Spacebar previews on its release, held it is the Hand
|
||||
|
||||
+1
-1
@@ -549,7 +549,7 @@ Since (M5.16): Key Light (After Effects' Keylight 1.2) is checked end to end on
|
||||
plate with an uneven screen, spill and soft edges (`effect.apply "Keylight (1.2)"`, pick, Clip
|
||||
Black / White, render). The colour eyedroppers of Keying effects sample the effect's input
|
||||
rather than the keyed frame (Ctrl/Cmd+click averages 5 × 5 pixels); agents do the same with
|
||||
`effect.pickColor {effect, param, x, y, average?}` (layer pixels). Searching "keylight" in
|
||||
`effect.pickColor {effect, param, x, y, average?}` (effect space). Searching "keylight" in
|
||||
Effects & Presets, or `list_effects`, finds it.
|
||||
|
||||
## Update: M4.9–M4.11 nested comps and motion blur
|
||||
|
||||
Reference in New Issue
Block a user