Moon surface map

This commit is contained in:
connor committed 2026-10-15 10:04:13 -04:00
1 parent 0e8134aa59
commit f8b515e198
36 files changed
+1710 -222

No files matched your search

+141 -41
View File
@@ -60,8 +60,8 @@ Some quantities that follow from that:
IFOV.
Real lenses are not perfect pinholes. They bend straight lines slightly
(distortion, planned in M3) and spread each point into a small blur (the
point spread function, also M3). The pinhole model is the starting point
(distortion) and spread each point into a small blur (the point spread
function); neither is modeled yet. The pinhole model is the starting point
those effects are added to.
### Coordinate conventions
@@ -142,8 +142,8 @@ wavelengths. Earth's average albedo is about 0.3.
Real spacecraft surfaces are not Lambertian. Multilayer insulation (MLI)
and solar cells are partly mirror-like and produce bright glints at
particular angles. These are modeled by a BRDF, a function giving reflected
radiance for every pair of incoming and outgoing directions. That arrives
in M4.
radiance for every pair of incoming and outgoing directions. BRDFs are not
modeled yet.
## Wavelength: spectra, channels and photons
@@ -287,7 +287,7 @@ Code: `camera.rs` (`Detector::dn`); `gpu/sensor.rs`, `shaders/sensor.wgsl`.
- **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, M3).
also spill into neighboring pixels (blooming, not modeled yet).
- **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
@@ -297,7 +297,7 @@ Code: `camera.rs` (`Detector::dn`); `gpu/sensor.rs`, `shaders/sensor.wgsl`.
So DN = bias + min(electrons, full well) / gain, rounded and clipped to the
ADC range. The renderer does this on the GPU for every pixel and channel,
as the last step of a frame, and reads back only the resulting integers.
Noise (M3) will enter between the electrons and the gain.
Noise, not modeled yet, enters between the electrons and the gain.
Two consequences of these numbers show up in every image:
@@ -337,7 +337,7 @@ exactly, on the GPU and on lavapipe.
Picking the exposure time is the same trade a photographer makes. A longer
exposure saturates the sunlit target. A shorter one leaves the side of the
target lit only by Earthshine lost in noise once noise is modeled (M3).
target lit only by Earthshine lost in noise once noise is modeled.
## How shapes become pixels
@@ -367,7 +367,7 @@ their edges are what limb-based navigation measures. The target uses
rasterization, because a spacecraft model has no equation, only its mesh.
Both write into the same depth image, so they sort against each other
correctly. Ray casting a mesh is also possible, by testing rays against
its triangles. That is what M5's ray tracer does, because following rays
its triangles. A ray tracer, planned, does that, because following rays
gives exact shadows and light bouncing between surfaces. Rasterization can
only approximate those, for example with the shadow maps lighting L1 uses
(below).
@@ -391,7 +391,7 @@ navigation and pose estimation.
The usual fix is supersampling: shading several points inside each pixel
and averaging. The GPU's multisampling hardware does this cheaply for
rasterized edges. Sampling the bodies' limbs needs it in the ray casting
shader. The lens blur that comes with the point spread function (M3) also
shader. The lens blur of the point spread function, once modeled, also
spreads every edge over a few pixels.
## Earth, Moon and Sun
@@ -420,8 +420,9 @@ disk, which is the feature horizon-based navigation measures.
### Shading
Earth and the Moon are Lambertian, each with one reflectance spectrum over
the whole body, set by `Appearance`. The Moon's is a flat 0.12. Earth's
Earth and the Moon are Lambertian, at lighting L0 each with one reflectance
spectrum over the whole body, set by `Appearance`. The Moon's is a flat 0.12
(from L1 it comes from a map; see "The Moon's surface"). Earth's
default is a stand-in shaped like cloud-free ocean seen from space: about
0.3 in the blue falling to 0.07 in the red, then back up in the near
infrared. Most of that blue is sunlight scattered by the atmosphere above
@@ -450,17 +451,20 @@ lit) right. It misses some things that are visible in real images:
- Earth's oceans, land and clouds differ in brightness by a factor of
several. From lighting L1, Earth's surface comes from an image (next
section); clouds come in M4.
section); clouds are not modeled yet.
- The full Moon looks almost uniformly bright out to its edge. A Lambertian
sphere instead darkens toward the edge, because the light there arrives
and leaves at grazing angles. Lunar soil scatters light back toward its
source much more strongly than Lambert predicts, and a dedicated lunar
reflectance model (M4) fixes that. The Moon's maria (the dark plains of
source much more strongly than Lambert predicts, which is also why it
brightens so steeply toward full Moon. At lighting L1 the Moon's total
brightness is scaled to its measured phase curve ("The Moon's surface"),
but its edge still darkens; a dedicated lunar reflectance model would fix
that. The Moon's maria (the dark plains of
old basalt lava, the "seas" seen with the naked eye) and its bright
highlands also differ in albedo by about a factor of two (M2 albedo
map).
highlands also differ in albedo by about a factor of two, which from
lighting L1 the Moon's map shows.
- Earth's atmosphere softens the limb and adds a thin bright band around it
(M4). Here Earth's edge is a sharp line.
(not modeled yet). Here Earth's edge is a sharp line.
### Earth's surface
@@ -506,7 +510,7 @@ Two details matter for brightness:
dark, a few percent. From orbit the ocean looks bright blue because the air
above it scatters sunlight toward the camera: Rayleigh scattering, which
grows as 1 / wavelength^4, which is also why the sky is blue. Until the
atmosphere is modeled (M4), a stand-in adds a reflectance of that shape,
atmosphere is modeled, a stand-in adds a reflectance of that shape,
0.07 at 450 nm falling to 0.017 at 650 nm (`Appearance::earth_haze`). It
brightens and blues the whole lit disk evenly, where the real effect grows
toward the limb, where the line of sight crosses more air.
@@ -520,6 +524,104 @@ calibrated reflectance product itself, so its values are close but not exact
reflectances. A calibrated alternative (MODIS's albedo product) is a possible
later refinement.
### The Moon's surface
Code: `moon.rs`, `shaders/bodies.wgsl`; data from `scripts/fetch-moon.py`. From
lighting L1, with the map in `RendererOptions::moon_texture`.
At lighting L1 the Moon's reflectance comes from a map instead of one spectrum.
The map is the LRO Camera's Wide Angle Camera mosaic at 643 nm (red), built from
more than 100,000 images taken under every kind of lighting. The camera team
used a model of how each spot on the Moon reflects light at different angles
(Hapke's, fitted to the images; Sato et al. 2014) to work out what every spot
would look like under one standard geometry: the Sun 60 degrees from overhead,
seen straight down. The map's values are that reflectance, I/F, the ratio of
the surface's brightness to that of a perfect white surface facing the Sun.
Over 98 % of the Moon they lie between 0.019 in dark maria and 0.067 on the
brightest highlands and crater rays, and they average 0.042.
The map is 400 m per pixel and covers 70 degrees south to 70 degrees north;
the polar caps beyond are filled with the average, so they render as smooth
gray (6 % of the surface, seen only near the limb from Earth). It is resampled
to 16384 x 8192, 666 m per pixel, the largest texture lavapipe takes, and read
exactly as Earth's image is: by latitude and longitude in the Moon's own axes,
with mipmaps, and without a seam at 180 degrees.
The Moon's axes come from `Scene::moon_attitude`. The Moon keeps one face
toward Earth, but rocks back and forth by up to 8 degrees (libration), so
which features are near the limb changes from month to month. With an epoch,
the renderer uses the IAU's model of the Moon's rotation; it puts the point
facing Earth within 0.008 degrees (230 m) of JPL Horizons' high-precision
frame, under a third of a map pixel. Without one, `Scene::moon_facing_earth`
turns the Moon's prime meridian toward Earth and is off by the libration, up
to about 10 degrees.
Two choices turn the map into something the renderer can shade:
- **Brightness.** The renderer shades the Moon as Lambertian, starting
from the albedo that gives the map's reflectance at the map's geometry:
I/F / cos(60 degrees), on average 0.084. On its own that makes the Moon
far too dark at full: the real Moon is not Lambertian, and it brightens
steeply toward full Moon, as rough soil hides its own shadows when lit
from behind the viewer. A Lambert sphere with these albedos is about a
third as bright as the real full Moon, and slightly too bright past
quarter. So each point's albedo is multiplied by a phase factor, from the
phase angle between the Sun and the viewer seen from that point. The
factor is the whole Moon's measured brightness at that phase (Allen's
lunar phase curve, 0.026 g + 4e-9 g^4 magnitudes below full, g in
degrees) over a Lambert sphere's, scaled so that the map's full Moon has
the measured geometric albedo (the full Moon's brightness against a white
Lambertian disk of the same size), 0.121 in the V band. It is 2.8 at 4
degrees, 1.16 at 60, 0.89 at 90 and 0.75 at 120, and holds its 150 degree
value beyond. At 60 degrees it would be 1 if the map and the measured
curve agreed exactly; the 16 % between them is the Lambert shape's error
at that phase together with the two calibrations'.
Rendered whole in the example camera's green channel, the Moon is then
within 5 % of the measured curve from 2 to 30 degrees of phase, and
within 11 % out to 120 degrees. At the same phase, the side of the Moon
holding Oceanus Procellarum, the largest of the maria, is darker than the
other: 0.89 of the curve at 90 degrees against 1.06. The real Moon differs
between waxing and waning in the same way, which the curve averages out.
At 150 degrees it is 9-15 % bright.
Across the disk the light still falls off as Lambert's does, darkening
toward the edge, while the real full Moon looks nearly flat out to its
limb. A lunar reflectance model would fix that.
- **Color.** The map is one band. Its color comes from the Moon's average
spectrum across the WAC's seven bands, 321 to 689 nm, from the same mosaics
averaged over the whole Moon by area: relative to 643 nm, 0.42 at 321 nm, 0.61
at 415 nm, 0.87 at 566 nm and 1.08 at 689 nm. The Moon is distinctly red,
which is why it looks yellowish gray to the eye. Each pixel's
643 nm value scales that spectrum, which is folded into the camera's
channels once at setup: in the example camera the Moon's albedo in red,
green and blue is 0.96, 0.83 and 0.69 times its 643 nm value over cos 60.
Beyond 689 nm the spectrum continues the slope from 643 to 689 nm to 900 nm
(1.45) and holds there, roughly following real lunar soils, which flatten
into an absorption by iron-bearing minerals near 1000 nm; below 321 nm it
holds the 321 nm value. Real maria rich in titanium are up to about 10 %
bluer than this, and highlands slightly redder; the seven-band mosaic
could give each pixel its own color later. The real Moon also reddens
slightly with phase, which the phase factor leaves out.
Light the Moon sheds on targets (Moonshine) reads the same map, with the
phase factor for the angle between the Sun and the target.
Tests (`tests/moon_texture.rs`), with small synthetic maps, on the GPU and
lavapipe: the pixel under the camera reads the texel at its latitude and
longitude, and moves when the Moon's attitude does; the color is the spectrum's;
a uniform map draws exactly the Moon a flat albedo draws times the phase
factor, at every pixel; there
is no seam at 180 degrees; a far view averages a fine checker; Moonshine comes
from the part of the map that faces the target.
Cost: the map adds about 0.04 ms to the bodies pass on the RTX 3060, for working
out where to read it at every pixel (the read itself happens only where the
Moon is). On lavapipe the pass got faster, from 2.7 to 2.0 ms with the Moon
filling the view, because Earth's image is now also read only where Earth is.
Loading the map takes 0.5 s and uploading it 0.17 s; it occupies 360 MB on the
GPU.
### The Sun's disk
Code: `sun.rs`, `shaders/common.wgsl`, `shaders/bodies.wgsl`. From lighting
@@ -555,7 +657,7 @@ It matters in two places:
- **The Sun in an image.** A camera that looks at the Sun almost always
saturates, but not with a dark filter, a Sun sensor, or once the lens's
blur spreads the Sun's light into the pixels around it (M3).
blur, once modeled, spreads the Sun's light into the pixels around it.
- **Eclipses.** When Earth or the Moon covers part of the Sun, what counts is
how much light it hides, not how much of the disk's area. Near the umbra
only a sliver of the dim edge is left, so less light gets through than the
@@ -630,7 +732,7 @@ stepped spectrum, blue below 490 nm, green from 500 to 580 nm, and red above
camera. It is a poor one for a camera whose channels differ from the eye's,
or for anything in the near infrared, where the red value simply continues.
For absolute radiometry of a real spacecraft, give the important materials
measured reflectance spectra (M4 adds those, and BRDFs).
measured reflectance spectra (not supported yet).
Texture images are not used yet; each material renders with its base color
value alone. The loader removes textures before reading a glTF file, so a
@@ -739,7 +841,7 @@ Limitations:
shades (a few mm on Landsat 8) lets light through, because of the acne
margins above.
- **One sample per pixel.** Shadows are sampled at the pixel center, like
everything else, until M3's pixel-area sampling.
everything else, until pixel-area sampling is added.
- **Bodies.** Earth and the Moon do not use shadow maps. Their shadows on
the target are the eclipse factor below, applied to the whole target.
Light from Earth and the Moon (below) is not shadowed at all.
@@ -843,7 +945,7 @@ Limitations:
- **Earth's atmosphere.** It bends sunlight into the umbra, mostly red, so a
real eclipsed Moon glows a dim copper color instead of going black, and it
makes the umbra about 2 % larger. Both come with the atmosphere (M4).
makes the umbra about 2 % larger. Neither is modeled yet.
- **Smooth shapes.** Earth's shadow is cast by a sphere of its equatorial
radius, as for the target's eclipses; its flattening would move the
shadow's edge on the Moon by about 20 km. The Moon's mountains and valleys,
@@ -929,14 +1031,14 @@ Limitations:
the Moon. A panel facing Earth does not shade the bus behind it from
Earthshine, and the inside of a dish facing Earth is lit as if open to the
whole Earth. Earth fills too much of the sky for one shadow map to stand in
for it; the ray tracer (M5) handles this.
for it; a ray tracer would handle this.
- **One spectrum per channel.** Light from Earth is bluer than sunlight, but
the target's albedo in each channel was worked out under sunlight. This is
the shortcut described in "Folding spectra into per-channel constants",
and its error is largest for strongly colored surfaces.
- **Lambertian bodies.** Earth and the Moon reflect as Lambertian surfaces
here, as they do in the camera's view. The Moon's real reflection is
brighter toward the Sun (M4), and Earth has no clouds or atmosphere yet
here, as they do in the camera's view, with the Moon's map scaled by its
phase curve as seen from the target. Earth has no clouds or atmosphere yet
beyond the stand-in haze.
## Where the Sun and Moon appear
@@ -961,23 +1063,21 @@ A camera sees something slightly different, its apparent position:
100 microradians is about one pixel of the example camera, and 18 pixels of
the narrow 1 m focal length camera in the limb test. So the geometric
positions are close enough for M1, but not for precise navigation against
the Sun, Moon or stars. Rendering apparent positions needs the observer's
positions are close enough for most images, but not for precise navigation
against the Sun, Moon or stars. Rendering apparent positions needs the observer's
velocity as an input, which the scene does not carry yet.
## Not modeled yet
| Effect | Where |
|---|---|
| Earthshine on the Moon's night side | M4 |
| Pixel-area sampling (anti-aliasing): graded edges, thin parts | M3 |
| Lens distortion | M3 |
| Blur from diffraction and lens imperfections (point spread function) | M3 |
| Noise: photon shot noise, read noise, dark current, pixel-to-pixel variation | M3 |
| Saturation spilling into neighbors (blooming) | M3 |
| Non-Lambertian materials (BRDFs), glints, lunar backscatter | M4 |
| Moon albedo map | M2 |
| Clouds on Earth | M4 |
| Earth's atmosphere: scattering, the bright limb | M4 |
| Motion blur, rolling shutter, stray light | M6 |
| Apparent positions: light time and aberration | M3 |
- Earthshine on the Moon's night side
- Pixel-area sampling (anti-aliasing): graded edges, thin parts
- Lens distortion
- Blur from diffraction and lens imperfections (point spread function)
- Noise: photon shot noise, read noise, dark current, pixel-to-pixel variation
- Saturation spilling into neighbors (blooming)
- Non-Lambertian materials (BRDFs), glints, and the full Moon's edge as bright
as its center
- Clouds on Earth
- Earth's atmosphere: scattering, the bright limb
- Motion blur, rolling shutter, stray light
- Apparent positions: light time and aberration