fix: the density's brightness ceiling is the fade's steady state, and the ramp is linear
A user looked at the display and reported "the colour fading is not applied, it looks white or full color, no opacity gradient" -- and the *numbers* were right: ink decayed, `step-time` was 1/e, `step-acquisitions` was 1 + 0.5 x 1. It was the mapping from a cell's value to a pixel. **Neither the shader nor the blend was wrong** (the answer to the question that was asked): the fragment write is already the weighted one (`vec4(u_color.rgb, u_color.a * ink)`) with the frame's straight-alpha blend, and a cell at half ink over a grid line rendered 160 where the arithmetic predicts 160. What was wrong was the **scale**: - `full_scale` defaulted to **1.0**, so the *newest* acquisition already sat at the ceiling and everything above it clamped to the same pixel -- a display of one sweep and a display of five were one white. It is now **1/(1 - 0.5) = 2.0**, the steady state of the default per-acquisition fade, so one sweep reads half ink and white is reached only where acquisitions agree. A caller whose fade settles elsewhere states its own sum (udpscope's is `1/(1 - factor)`, in its commit). - `gamma` defaulted to **0.45**, the value `Style::intensity_gamma` wants where the measure is a *dwell fraction*; on a *count* it spends most of the ramp on the last sweep (a quarter of the scale mapped to 0.54). It is now **1.0 -- linear in sweeps**, because half as many sweeps must read as half the ink. The case that would have caught this is a **framebuffer** reading, not the grid's, and `a_phosphor_density_is_drawn_under_the_traces` now makes it: it fades the grid to a quarter through the time rule (`dt = tau ln 4`, asserted at 0.25 off the ink) and reads the same pixel back, so the ramp is asserted where the eye sees it -- **`empty=21 full=83 quarter=54`** (red channel), against the 199 / 199 the ceiling and a single sweep both read at the old defaults. A full cell must be measurably above the background and above a quarter cell, and a quarter cell above the background: three assertions on pixels, none of which the grid's own numbers can make. Suite: **396 cases, 0 failed**, 4/4 ctest entries.
This commit is contained in:
1 parent
6a6915e64e
commit
738205293e
3 files changed
+68
-12
No files matched your search
@@ -56,17 +56,23 @@ struct DensityConfig {
|
||||
/// what a phosphor's afterglow looks like sweep to sweep: 1, 0.5, 0.25, 0.125 and by the
|
||||
/// seventh the layer is under 1 %.
|
||||
f32 per_acquisition = 0.5f;
|
||||
/// The cell value that reads as **full brightness**, in accumulated sweeps: one accumulation
|
||||
/// deposits 1.0 into every cell its traces cover, so the default of 1.0 draws a single
|
||||
/// acquisition at full ink and lets the ones behind it add on top (up to saturation). A caller
|
||||
/// that wants the newest sweep dimmer -- so that agreement between acquisitions is the only
|
||||
/// thing that reaches white -- passes 2.0 or more.
|
||||
f32 full_scale = 1.0f;
|
||||
/// The gamma applied to the normalised cell value before it becomes a luminance. Under 1 --
|
||||
/// 0.45, the same default `Style::intensity_gamma` uses -- lifts the faint end, which is what
|
||||
/// makes a ghost *readable* rather than merely present: without it a cell covered by one in
|
||||
/// eight sweeps is an eighth of the ink and looks like a smudge of the background.
|
||||
f32 gamma = 0.45f;
|
||||
/// The cell value that reads as **full brightness**, in accumulated sweeps. The default is the
|
||||
/// ink the **default fade settles at** -- `1/(1 - 0.5)`, the geometric sum of
|
||||
/// `PerAcquisition`'s factor -- and that is the rule worth keeping: a ceiling at *one* sweep
|
||||
/// puts the newest acquisition at full white and everything above it clamps to the same pixel,
|
||||
/// so a display of one sweep and a display of five read alike and the fade is invisible
|
||||
/// (measured: a cell at a quarter of the scale rendered 104 of 255 while one at the ceiling
|
||||
/// rendered 156, but with the ceiling at one sweep both were 199). A caller whose fade settles
|
||||
/// elsewhere wants its own sum here.
|
||||
f32 full_scale = 2.0f;
|
||||
/// The gamma applied to the normalised cell value before it becomes a luminance. **1.0 by
|
||||
/// default: linear in sweeps**, because that is what a count means -- a cell covered by half the
|
||||
/// acquisitions is half the ink. Under 1 lifts the faint end, and that is what
|
||||
/// `Style::intensity_gamma` is for where the value is a *dwell fraction* rather than a count;
|
||||
/// here it flattens the top instead (0.45 maps a quarter of the scale to 0.54 and the ceiling to
|
||||
/// 1.0, which is most of the ramp spent on the last sweep). Over 1 darkens the faint end for a
|
||||
/// caller that wants only the strong agreement visible.
|
||||
f32 gamma = 1.0f;
|
||||
};
|
||||
|
||||
/// The density's own image: **one `f32` cell per device pixel of the axes rect**, so its
|
||||
|
||||
Reference in new issue
Block a user