# TRACES: FR-DEV-3a | FR-DEV-3c id: exposure label: op.exposure order: 20 attributes: [tone] doc: | Exposure — a linear gain, expressed in stops. The simplest operation in the pipeline and the one that most justifies working in linear light: a stop is a doubling, so exposure is a single multiply. Applied to gamma-encoded data it would be neither a doubling nor reversible, which is why this stage sits where it does (ARCH §5.2). placement: | A correction to how the scene was captured, so it precedes every operation that interprets tone. params: exposure: label: param.exposure kind: stops min: -5 max: 5 doc: | ±5 stops. Wider than most edits need, but recovering a badly underexposed frame is a real use and raw data often supports it. uniforms: gain: value: exp2(exposure) doc: The linear gain for the current setting. wgsl: | c = c * gain; tests: - name: one_stop_is_a_doubling why: | The definition of a stop. If this is wrong, every exposure adjustment is subtly off and no test of "looks right" would catch it. set: { exposure: 1 } expect: { gain: 2.0 } - name: one_stop_down_is_a_halving set: { exposure: -1 } expect: { gain: 0.5 } - name: stops_compose_additively why: +2 stops must equal +1 applied twice. set: { exposure: 2 } expect: { gain: 4.0 } - name: neutral_is_unity_gain why: | An unedited image must be the image, not an interpretation of it. expect: { gain: 1.0 } expect_active: false