Noise, paint, the shutter, and the comp scene were still reaching the footprint key, so a finishing adjustment re-uploaded a full frame every frame. The key now uses EffectScope::Footprint and ignores that stack, while a moving mask still re-keys it.
#2410's dependency walk for a soloed 3D model was written before
reads_other_times took the effect count; it asks about all effects (None),
as the other walks do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Carry property, Font and Media Replacement overrides into the collapsed nested EvalCtx so nested layers render beyond the precomp frame instead of falling back to a clipped, flattened image. Key the layer cache on instance overrides to keep distinct collapsed instances isolated.
The referenced model's solo render goes through the comp camera: its
depth of field (focus, aperture, iris, highlights) blurs it, none of
which is in the projection matrix — the evaluated Dof is hashed in now
(CodeRabbit, review of #2410).
A model with an animation clip selected is posed at its layer time
(Animation Speed and Looping are static and hashed): the layer time is
folded into the key, so every time is its own entry. A model without a
clip keeps one key across times, as before.
An Environment light's image lights Advanced 3D models, and its source
can be any layer's render (or any environment layer) — too open-ended
to hash: while one is on, the read is not cached. Each is covered by a
render test.
CC Composite stays After Effects-pure: its Layer parameter is gone, so
parameter indices match AE again (scripts and expressions that address
parameters by index). The model reference lives in its own effect,
ec.3d.instance3d (3D Channel, CPU, one layer parameter), which replaces
the layer's pixels with the referenced layer's render — alpha included.
A referenced model's solo render is now hashed into the owner's cache key
instead of declining the entry (Bflat, review of #2410): the layer, its
animated values and transform, the mesh item, the comp camera and lights,
draft 3D, the renderer setting and the in/out gate. Covered by a render
test: the copy is cached, served on the second render, and re-rendered
when the camera pans or the model leaves its in/out range.
Layer > Create > Create 3D Layer Instance, as After Effects (public docs):
3D model layers take no masks or effects, so the command puts a comp-sized
solid at the top of the layer stack with CC Composite referencing the
selected model, and switches the model off (back on to keep its shadow) -
a 2D copy of its render, through the comp's camera, that 2D effects can be
applied to.
- CC Composite (ec.channel.cccomposite) gains an optional Layer parameter:
with a layer chosen it takes the original's place; In Front replaces the
solid's pixels, alpha included, the other Composite Original modes blend
with them. The GPU compositor runs such an instance on the CPU.
- FxHost serves a referenced model or primitive layer as After Effects
does - the layer rendered on its own through the comp's camera
(Renderer::solo_3d); the owner keeps no cache entry for it (it moves with
the camera and lights, without a trace in its own properties).
- layer.create {op: instance3d} skips layers that are not 3D model or
primitive layers (the ones that take no effects); one undo step, the copy
selected, the model's video off.
Tests: tests_instance3d.rs (behaviour, pixels, undo/redo, serde, 2D effects
on the copy), a CC Composite layer-parameter unit test; docs/effects.md
regenerated (3033 parameters).
The simulation checks its checkpoints against the Birth Rate history,
but a cached layer is returned before the effect runs. The layer key
sees the layer's keyframes and its current values, not what an
expression returned at earlier times: a Birth Rate expression reading
another layer could change the history while the current rate, 0, stayed
the same.
effects::reads_param_history names CC Particle World. The renderer
already declines to cache layers whose time effects (ec.time.*) meet
expressions. It now treats Particle World the same way, in the layer key,
the input key (only for the effects that input runs) and the dependency
walk.
A layer selected by another layer's effect (Displacement Map, Blend...) had
its structure, values, matrix and time hashed into the owner's key, but not
the comp camera/lights its own scene-reading effects (Caustics, CC Particle
World...) see. The owner's key included the scene only when the owner itself
ran such an effect, and a cached owner never runs the selected layer's
effects, so moving the camera or a light reused stale owner pixels.
Dependencies::layer now hashes comp_scene for every selected (or nested)
layer that reads it, with the same policy as owner keys.
Fixes#1252
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N9kwMcw2pYQ5fSjKa3ZPnh