Convert to the working space before the edits, not after
Every point operation ran in camera RGB and the camera matrix came after them all, against the order ARCH §5.2 draws. So `luminance()` applied Rec.709 weights to a body's own primaries, a band in the colour mixer was a different hue on every make of sensor, and the vibrance skin guard tested channel order in a space where skin does not have one. Operations now declare a `Stage`. White balance is the only camera-stage node — its multipliers scale the sensor's channels, and after a matrix that mixes them the same numbers are a different correction — and says so with `stage: camera` in its YAML, a key both the build-time generator and the load-time declared op read. The composer emits the camera nodes, then the matrix, then the rest, each group in graph order; an empty chain still gets the matrix. Film simulation stops converting out of camera space itself, since it is now handed working-space colour like every other scene node. The base curve stays where it was, after the operations, and so now acts on working-space colour; the next commit replaces it (D19).
This commit is contained in:
@@ -396,14 +396,10 @@ impl Operation for FilmSim {
|
||||
// sampler binding, and adding one to interpolate two lookups would
|
||||
// cost a binding in every shader whether or not a film is loaded.
|
||||
"\
|
||||
// Camera RGB to linear sRGB. The film's exposure matrix is defined against
|
||||
// sRGB primaries, and this node has taken over the conversion the composer
|
||||
// would otherwise have emitted at the end — see `Operation::renders`.
|
||||
let scene = vec3<f32>(
|
||||
dot(u.cam_to_srgb_0.rgb, c),
|
||||
dot(u.cam_to_srgb_1.rgb, c),
|
||||
dot(u.cam_to_srgb_2.rgb, c),
|
||||
);
|
||||
// Working-space colour, which is linear sRGB primaries — what the film's
|
||||
// exposure matrix is defined against. The composer converted out of camera
|
||||
// RGB before any scene-stage operation ran (D19).
|
||||
let scene = c;
|
||||
|
||||
// What each emulsion layer was exposed to. A matrix, exactly: the scene
|
||||
// spectrum reconstructed from an sRGB triple is linear in that triple, so the
|
||||
@@ -727,13 +723,15 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_fragment_converts_out_of_camera_space_itself() {
|
||||
// It has to: it has taken over the conversion the composer would
|
||||
// otherwise emit at the end.
|
||||
fn the_fragment_is_handed_working_space_colour() {
|
||||
// TRACES: FR-DEV-3f
|
||||
// D19: the composer leaves camera space before any scene-stage
|
||||
// operation, so a film converting again would apply the camera
|
||||
// matrix twice.
|
||||
let mut op = FilmSim::new();
|
||||
op.set_tables(Some(tables()));
|
||||
let wgsl = op.wgsl_body();
|
||||
assert!(wgsl.contains("cam_to_srgb_0"), "{wgsl}");
|
||||
assert!(!wgsl.contains("cam_to_srgb"), "{wgsl}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user