Saturation and blooming

This commit is contained in:
connor committed 2026-10-16 16:31:53 -04:00
1 parent 3d0b129582
commit 7e1b64c186
17 files changed
+694 -71

No files matched your search

+49 -2
View File
@@ -362,7 +362,7 @@ Code: `camera.rs` (`Detector::dn`, `Detector::variance`); `gpu/sensor.rs`,
- **Full well.** The maximum number of electrons a pixel holds. Beyond it
the pixel saturates and reads its maximum value whatever the light.
Brighter scenes do not look brighter. In real sensors, excess charge can
also spill into neighboring pixels (blooming, not modeled yet).
also spill into neighboring pixels (blooming, below).
- **Gain.** Electrons per DN. With a gain of 5, every 5 electrons add 1 to
the output.
- **Bias.** A fixed offset added to every pixel, so that noise around zero
@@ -561,6 +561,54 @@ The pattern costs nothing measurable on an RTX 3060; on lavapipe it adds
about 2.3 ms at 1920 x 1080 and 6.3 ms at 3840 x 2160. A loaded pattern
takes 8 bytes per value, 199 MB at 3840 x 2160 in RGB.
### Blooming
Code: `Blooming`; `sensor.wgsl` (`BLOOMING`: `collect_charge`,
`bloom_columns`, `read_out`).
A saturated pixel's extra charge does not vanish. Where it goes depends on
the sensor, and matters whenever something in or near the frame is far past
the full well: the Sun at the example camera's 0.1 ms is about 26,000 full
wells at the center of its disk, and a sunlit specular part can be hundreds.
- **CCDs** move charge down columns to read it out, and the channels that
hold it are only walled off from each other across the columns. Excess
charge spills along the column, up and down, filling each pixel it
reaches before passing on: the familiar vertical streak through the Sun
or a glint, which can cross a whole frame and hide a target in it.
- **CMOS sensors** read each pixel on its own, and most have an
anti-blooming drain that carries excess charge away. What escapes it
spills into the pixels around.
From camera tier C1, `Detector::blooming` chooses: `None` (the default: the
pixel clips and the excess is lost), `Column { efficiency }` or
`Neighbors { efficiency }`, where the efficiency is the fraction of the
excess that spreads and the rest drains. Along a column, half goes up and
half down; each pixel it reaches takes what it has room for and passes the
rest on, until it runs out or leaves the frame. Into the neighbors, each of
the 8 takes an eighth, and what overfills them drains.
Blooming happens to the charge, so it comes after the shot noise (and the
fixed pattern) and before the read noise and the ADC. With blooming on, the
sensor pass works in three steps rather than one: it writes each value's
charge to a buffer, spreads it, and reads it out. Along columns the spread
is a walk up and down each column, one at a time; the first step marks the
columns that hold any excess, and the walk skips the rest, which in most
frames is all of them. The CPU reference in the tests does the same walk in
f64.
Measured, on the GPU and lavapipe: a single overfull pixel on an even
background fills the pixels it should along its column to the electron,
charge that leaves the frame is lost, and nothing else changes; the
neighbors share equally; below the full well, or at efficiency 0, blooming
changes no value. The Sun at 2e-5 efficiency, in a 256 x 256 frame of the
example optics, streaks 22 pixels each way from the middle of its disk,
matching the CPU column by column to 0 DN. Column blooming costs 0.23 ms per
1920 x 1080 frame on an RTX 3060 with nothing past the full well and 0.75 ms
with the Sun in the frame (1.0 and 2.2 ms at 3840 x 2160); into the
neighbors, 0.24 ms (1.0 ms). On lavapipe, about 3 ms and 10 to 12 ms at
1920 x 1080.
## How shapes become pixels
Two techniques turn 3D shapes into an image. The renderer uses one for the
@@ -1609,7 +1657,6 @@ is a run of the script with `--gaia 16`, at twice the size.
- Earthshine on the Moon's night side
- The diffraction pattern's rings, and a lens's measured point spread function
- Saturation spilling into neighbors (blooming)
- Non-Lambertian materials (BRDFs), glints, and the full Moon's edge as bright
as its center
- Clouds on Earth