# A hand-written node, and the first thing in `Attribute::Optics`. # # Written, tested and unreferenced until now: `src/ops/vignetting.rs` has # existed with a full descriptor and a working polynomial, and without an entry # here it was never in `chain()` — so it reached no photograph and no panel. # This file is the whole of what was missing, which is the point of `ops/` # being the one place the pipeline's order is written down. id: vignetting order: 5 attributes: [optics] rust: Vignetting why_rust: | It carries a lens profile's `pa` coefficients, which are not parameters: they come from the body and lens that took the photograph, not from the photographer, and no `uniforms:` expression could produce them. The one parameter that *is* theirs — the manual trim — is composed with `k1` in Rust, because the profile and the trim have to reach the shader as a single polynomial rather than as two the fragment would have to add up. placement: | First in the chain, ahead of white balance and exposure. Vignetting is what the lens did to the light before the sensor measured it, so undoing it belongs with reading the file rather than with editing the picture — everything downstream is then working on the frame the lens would have delivered had it been even. The ordering is load-bearing rather than tidy. Correcting a corner means *dividing* by an attenuation below one, which pushes those pixels up: a fast prime wide open needs about two stops there. Run after the tonal stages, that recovery happens once the highlights have already been rolled off and clipped, so it lifts values that no longer have anywhere to go and the corners posterise instead of brightening. Run here, the headroom to hold them still exists (ARCH §5.2). Before distortion and chromatic aberration in intent, though those are `lens::Warp`s rather than nodes and compose ahead of the fetch, so no `order:` relates the two.