sunlight through atmosphere

This commit is contained in:
connor committed 2026-10-18 12:09:21 -04:00
1 parent 8c0a1439d7
commit 8e57375059
18 files changed
+1921 -134

No files matched your search

+76 -1
View File
@@ -3,7 +3,8 @@
two scenes with Earth, the Moon and a spacecraft together (below):
examples/scenes/earthrise.toml from lunar orbit and examples/scenes/moonrise.toml
from geostationary height, examples/scenes/sun-glare.toml with the Sun in the frame
of a camera whose CCD blooms (camera tier C1), and scenes for the stars of lighting
of a camera whose CCD blooms (camera tier C1), examples/scenes/sunset.toml with a
spacecraft lit by the Sun setting behind Earth's atmosphere, and scenes for the stars of lighting
tier L1: a star field, examples/scenes/stars-pleiades.toml, and a telescope on one
geostationary satellite imaging another along the arc,
examples/scenes/geo-telescope-*.toml.
@@ -531,6 +532,77 @@ attitude = {fmt(quaternion(attitude), 9)}
"""
# Sunset: Landsat 8 in its 705 km orbit seconds before it passes into Earth's shadow,
# lit by sunlight that crosses the atmosphere edge on, seen from an inspector looking
# across the Sun's direction at the limb, where the twilight glows.
SUNSET_PAST = -0.0015 # rad of orbit before the line to the Sun's center grazes the ground
SUNSET_AZIMUTH = 45.0 # degrees, the boresight's azimuth from the Sun's
SUNSET_EXPOSURE = 3e-3 # s, for the satellite in a few percent of sunlight
def sunset():
file, scale, center, radius, orbit = "landsat8.glb", 1.0, MODELS[0][3], MODELS[0][4], MODELS[0][5]
# The Sun along +X; the satellite in the XY plane, SUNSET_PAST short of where the
# straight line from it to the Sun's center touches the ground.
sun = [1.0, 0.0, 0.0]
alpha = math.pi - math.asin(RE / orbit) + SUNSET_PAST
look = [orbit * math.cos(alpha), orbit * math.sin(alpha), 0.0]
up = norm(look)
toward_sun = norm([sun[i] - dot(sun, up) * up[i] for i in range(3)])
a = math.radians(SUNSET_AZIMUTH)
across = [math.cos(a) * toward_sun[i] + math.sin(a) * x for i, x in enumerate(cross(up, toward_sun))]
# Earth's limb 2 degrees above the image center, as in the model scenes.
theta = math.asin(RE / orbit) - math.radians(2.0)
boresight = [-math.cos(theta) * up[i] + math.sin(theta) * across[i] for i in range(3)]
# The solar array's normal (body +X) halfway between the Sun and the camera, so it
# is lit and seen at the same slant, with body +Z across the view.
half = norm([sun[i] - boresight[i] for i in range(3)])
attitude = triad([1, 0, 0], [0, 0, 1], half, cross(up, half))
distance = radius / math.tan(math.radians(2.8))
camera = [look[i] - distance * boresight[i] for i in range(3)]
offset = mul(attitude, center)
position = [look[i] - offset[i] for i in range(3)]
fmt = lambda v, d=2: "[" + ", ".join(f"{x:.{d}f}" for x in v) + "]"
header = textwrap.fill(
"Sunset: Landsat 8 in its 705 km orbit, 1.4 s before the straight line to the "
"Sun's center touches the ground. Its sunlight crosses the lowest 25 km of the "
"atmosphere edge on: at lighting L1, 7.2 % of the Sun's red light reaches it, "
"4.8 % of its green and 4.4 % of its blue, and it is lit orange-pink. The solar "
f"array faces halfway between the Sun and the camera, an inspector {distance:.0f} m away "
f"looking {SUNSET_AZIMUTH:g} degrees across the Sun's direction at Earth's limb, where "
"the twilight glows orange under blue. At lighting L0, without the atmosphere, "
"71 % of the Sun is above Earth's bare edge, and the satellite saturates at this "
"exposure. Generated by scripts/make-example-scenes.py; the model comes from "
"scripts/fetch-models.sh.",
width=80, initial_indent="# ", subsequent_indent="# ", break_on_hyphens=False)
return f"""{header}
#
# resolved render --scene examples/scenes/sunset.toml --lighting L1 --camera C1 --pretty --preview sunset.png
sun = {fmt([AU * x for x in sun], 0)}
moon = [0, 0, -3.844e8]
[camera]
exposure = {SUNSET_EXPOSURE}
[observer]
position = {fmt(camera)}
look_at = {fmt(look)}
up = {fmt(up, 9)}
# At lighting L1, Earth's surface shows July (from scripts/fetch-earth.sh); here it is
# on the night side, dark.
[appearance]
earth_month = 7
[[target]]
model = "../models/nasa/{file}"
scale = {scale}
position = {fmt(position, 4)}
attitude = {fmt(quaternion(attitude), 9)}
"""
# For the long-exposure cameras, which leave the example camera's 1 in 10,000 hot.
CALIBRATED = """# Calibrated: hot pixels mapped out, all but 1 value in a million.
hot_pixels = [1e-6, 50]
@@ -662,6 +734,9 @@ print(f"wrote {path}")
path = out / "sun-glare.toml"
path.write_text(sun_glare())
print(f"wrote {path}")
path = out / "sunset.toml"
path.write_text(sunset())
print(f"wrote {path}")
path = out / "stars-pleiades.toml"
path.write_text(stars_pleiades())
print(f"wrote {path}")