Develop the film last, in the view transform's place

A film stock ran at order 25, after white balance and exposure, and
everything after it — contrast, the curves, the colour mixer, the
grading, every mask layer's tone — acted on the film's display-referred
output, as though the frame had been scanned and then worked on. That
was a display-referred rendering in the middle of the chain, which D19
removes (FR-DEV-3f, FR-DEV-3j).

`film_sim` is now in `Stage::View` beside `view_transform`. While a
stock is loaded the composer emits it in the view transform's place and
not the sigmoid; otherwise the sigmoid. So every edit is a decision
about the exposure the negative receives, and the film is the last
thing that happens to the picture — after the detail stage too, in the
view pass, which already binds the film's tables, the mask array and
the grain's source position. Its per-layer settings blend there as they
did in the fused pass.

`op_renders` goes: a rendering is chosen, not suppressed, and the only
render with no view transform is the camera-space tap. The YAML order
moves to 190 so the panel reads in pipeline order; the stage, not the
number, is what places it.

Existing edits that combine a stock with tone or colour operations now
render differently: those operations used to act on the print, and now
act on the scene.
This commit is contained in:
2026-09-27 16:52:55 -04:00
parent c07f81edcb
commit 657f8f19ff
7 changed files with 123 additions and 74 deletions
+9 -10
View File
@@ -240,17 +240,16 @@ coefficients that are not parameters.
`Operation::renders`, and it is worth knowing why before writing a second one.
Every other node *adjusts* a picture. That one *makes* it: a film stock's
characteristic curve does the camera profile's base curve's job, from
measurements rather than from a curve somebody drew. Running both renders the
scene twice — the camera's rendering, and then a film's rendering of *that* —
which looks like neither and reads as a colour-management bug with no
colour-management bug to find.
characteristic curve does the view transform's job, from measurements rather
than from a curve somebody chose. Running both renders the scene twice — the
default rendering, and then a film's rendering of *that* — which looks like
neither and reads as a colour-management bug with no colour-management bug to
find.
So a node declaring `renders` hands back display-referred linear sRGB, and in
exchange the composer does not emit the base curve. It is handed working-space
colour like every other node: the conversion out of camera space is no longer
the rendering's to take over, because since D19 it runs before every node but
white balance (see "Stages" below). `distortion` and
So `film_sim` is in `Stage::View` beside `view_transform`, and while a stock
is loaded the composer emits it in the view transform's place, last, after the
detail stage, and not the sigmoid (D19). It is handed working-space colour and
hands back display-referred linear sRGB for the output transform. `distortion` and
`aberration` are `Warp`s rather than operations: they rewrite coordinates
before sampling rather than transforming a colour after it.
+10 -8
View File
@@ -1,5 +1,5 @@
id: film_sim
order: 25
order: 190
# What this node is *about* is not written here, and cannot be: a `rust:` node
# publishes its own descriptor, so `attributes:` in this file would be read,
# validated and then ignored. See `Attribute::Effect` on `FilmSim`'s descriptor
@@ -15,11 +15,13 @@ why_rust: |
and the conversion out of camera space on its behalf.
placement: |
After white balance and exposure, and before everything else.
Last, in the view transform's place (D19, FR-DEV-3j), after every other
operation and after the detail stage.
Those two are what the camera did — interpreting the sensor, and correcting
the amount of light that reached it — and they are only meaningful on
scene-linear values, which is what a film has to be handed. Everything below
is a decision about the picture, and a decision about the picture belongs
after the film has rendered it, exactly as it does when you scan a frame and
then work on the scan.
Before D19 it sat at order 25, after white balance and exposure, and every
decision below it acted on the film's output, as though the frame had been
scanned and then worked on. That put a display-referred rendering in the
middle of the chain, which is what D19 removes: every operation is now handed
the scene, and the film is the last thing that happens to the picture — an
edit is a decision about the exposure the negative receives. `Stage::View`
is what puts it there; this number only places it in the panel's order.