Apply a camera profile's HueSatMap and LookTable after exposure
The second half of D20: a camera_profile scene operation at order 25 that converts working colour into linear ProPhoto, runs the DNG SDK's HSV lookup through the HueSatMap and then the LookTable, and converts back. Hue and saturation do not change under the uniform gains before it, so a 2.5-D HueSatMap gives the same answer as straight after the matrix, and the look sees the photographer's exposure as it does in the SDK. Two departures for scene-referred values: value is not clamped on the way out, and a colour outside ProPhoto passes through. The operation holds only the switch (on by default) and a look strength of 0-200 %. It is composed while the switch is on — a new Operation::composes() separates "does something" from "moved from the defaults", so an untouched raw renders through its profile and still writes nothing. The tables come from the source: dr-gpu uploads the ones DemosaicedImage carries into a storage buffer at @binding(8), whose two-entry header tells the fragment whether there is anything to apply, and binds a header of zeros for every other source. apply_reference is the lookup on the CPU. The GPU test holds the shader to it over 256 colours, through synthetic tables strong enough that a wrong index shows, and through the library's real Adobe Standard tables when the 6D DNG is present.
This commit is contained in:
+12
-10
@@ -95,13 +95,13 @@ that differed from the screen would be the result.
|
||||
|
||||
### 3.1 The two constants
|
||||
|
||||
`P = row-normalise(XYZ→sRGB · Bradford(D50→D65) · ProPhoto→XYZ(D50))` takes ProPhoto to the
|
||||
working space; the fragment uses `P⁻¹` going in and `P` coming out. These are the same constants
|
||||
`forward_to_srgb` composes for the forward-matrix route, so for a profile with forward matrices the
|
||||
round trip is exact: the working colour is `P · FM`-space colour and `P⁻¹` recovers the SDK's
|
||||
ProPhoto. Row normalisation keeps working-space white at ProPhoto white, so a neutral stays at
|
||||
`s = 0`. For the colour-matrix route, `P⁻¹` gives the ProPhoto rendering of the same colour, which
|
||||
is what the SDK derives too.
|
||||
`P⁻¹` is `ColourSpace::ProPhoto.from_linear_srgb()` — the conversion `dr-types` already derives
|
||||
from the two spaces' chromaticities, adapting D65 to D50 by Bradford, which the export path uses to
|
||||
write ProPhoto files — and `P` is its inverse. The fragment uses `P⁻¹` going in and `P` coming
|
||||
out. Each row of both is scaled to sum to one, so working-space white is ProPhoto white exactly and
|
||||
a neutral reaches the tables at `s = 0`. For a profile with forward matrices this recovers the
|
||||
SDK's ProPhoto colour to within the difference between that derivation and `forward_to_srgb`'s
|
||||
published Bradford constants, which is rounding.
|
||||
|
||||
## 4. Where a profile comes from
|
||||
|
||||
@@ -197,11 +197,13 @@ action sits on that line.
|
||||
- **The CPU reference matches the SDK's algorithm**: grey passes through; a table of
|
||||
`(0°, 1, 1)` everywhere is the identity to 1e-6; a uniform `satScale` of 1.2 scales HSV
|
||||
saturation by 1.2; hue interpolation wraps between the last and first column.
|
||||
- **The shader agrees with the CPU reference** within 1e-4 on a ramp across hue, saturation and
|
||||
values up to 16.0, on a device.
|
||||
- **The shader agrees with the CPU reference** on a device, within two 8-bit codes of the
|
||||
display-encoded readback (the only readback the adjust pass has), over 256 colours that tables
|
||||
of tens of degrees and ±30 % saturation move, and over the library's real Adobe Standard tables
|
||||
(`dr-gpu/tests/camera_profile.rs`).
|
||||
- **Scene-referred.** A value above 1.0 leaves the stage above 1.0 (`scene_referred_until_the_view`
|
||||
covers the operation).
|
||||
- **Neutral.** `apply` off, or no tables, composes a shader whose output equals today's to the bit.
|
||||
- **Neutral.** `apply` off renders to the bit what a source with no tables renders.
|
||||
- **Two illuminants.** A HueSatMap at blend weight 0 is Data1, at 1 is Data2.
|
||||
- **Matching.** An embedded profile beats a directory one; a DCP for "Canon EOS 6D" matches a CR2
|
||||
whose rawler make/model is "Canon"/"EOS 6D"; no match leaves the matrix.
|
||||
|
||||
@@ -459,7 +459,7 @@ FR-DEV-3j's default, for every body. ΔE2000 validation against ColorChecker ref
|
||||
once DCP support lands.
|
||||
For item 4: the lookup follows the DNG SDK's on `[0, 1]` and leaves values above 1.0 above it;
|
||||
grey and an identity table pass through unchanged; the shader agrees with the CPU reference; with
|
||||
the switch off, or no profile, the render is unchanged to the bit (camera-profiles.md §8).
|
||||
the switch off the render is to the bit the one with no profile (camera-profiles.md §8).
|
||||
|
||||
**FR-DEV-3f — Look emulation.** Support HaldCLUT import, which inherits the existing free film
|
||||
simulation ecosystem at near-zero implementation cost, plus reading the in-RAF film simulation tag
|
||||
|
||||
+29
-29
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user