Added stars at L1

This commit is contained in:
connor committed 2026-10-16 14:43:50 -04:00
1 parent e0381ccdd7
commit 970551b4e1
26 files changed
+2118 -55

No files matched your search

+140 -2
View File
@@ -1,8 +1,10 @@
#!/usr/bin/env python3
"""Writes examples/scenes/<model>.toml for the NASA models fetch-models.sh downloads,
and two scenes with Earth, the Moon and a spacecraft together (below):
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.
from geostationary height, and scenes for the stars of camera tier C1: 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.
Every scene has the same composition: the spacecraft in an isometric view (the
camera looks along its body (+1, +1, +1) diagonal, body +Z toward image up) with
@@ -447,6 +449,135 @@ attitude = {fmt(quaternion(attitude), 9)}
"""
# Earth's orbital speed, m/s, and the geostationary orbital speed.
EARTH_SPEED = 29.78e3
GEO_SPEED = 3074.7
# The telescope's longitude on the geostationary arc, degrees: looking along the arc
# from here points at right ascension 103 degrees, where the Milky Way crosses the
# equator in Monoceros, the densest stretch of the equator (190 stars per square degree
# to V 12, against 50 where it crosses in Aquila, behind the dust of the Aquila Rift).
GEO_LONGITUDE = 13.0
# The ecliptic's north pole in the inertial (equatorial J2000) frame.
ECLIPTIC_POLE = [0.0, -math.sin(math.radians(23.4393)), math.cos(math.radians(23.4393))]
def earth_velocity(sun):
"""Earth's velocity around the Sun when the Sun is in direction `sun`: along the
ecliptic, a quarter turn ahead of the Sun's direction from Earth."""
return [EARTH_SPEED * x for x in norm(cross(ECLIPTIC_POLE, [-x for x in sun]))]
def stars_pleiades():
# The Pleiades, right ascension 56.75 and declination 24.12 degrees, from
# geostationary orbit, with the Sun behind the camera.
ra, dec = math.radians(56.75), math.radians(24.12)
look = [math.cos(dec) * math.cos(ra), math.cos(dec) * math.sin(ra), math.sin(dec)]
camera = [GEO, 0.0, 0.0]
sun = [-x for x in look]
fmt = lambda v, d=2: "[" + ", ".join(f"{x:.{d}f}" for x in v) + "]"
return f"""# A star field: the Pleiades through the example camera (12 by 7 degrees), from
# geostationary orbit, long-exposed at 5 s. Stars are drawn at lighting L1 with camera
# C1, from the catalog scripts/fetch-stars.py writes. Alcyone, the brightest at V 2.9,
# gives about 200,000 electrons, ten times the full well; a V 8 star about 2,000 and a
# V 11 star about 130. Generated by scripts/make-example-scenes.py.
#
# resolved render --scene examples/scenes/stars-pleiades.toml --lighting L1 --camera C1 --pretty --preview pleiades.png
sun = {fmt([AU * x for x in sun], 0)}
moon = [0, -384400000, 0]
earth_velocity = {fmt(earth_velocity(sun))}
[camera]
exposure = 5
[observer]
position = {fmt(camera)}
look_at = {fmt([camera[i] + 1e9 * look[i] for i in range(3)])}
up = [0, 0, 1]
velocity = [0.00, {GEO_SPEED:.2f}, 0.00]
# At lighting L1, Earth's surface shows July (from scripts/fetch-earth.sh).
[appearance]
earth_month = 7
"""
def geo_telescope(range_m, phase_deg, f_number, exposure, description):
# The camera at GEO_LONGITUDE on the geostationary arc, the target ahead along it.
file, scale, center = "ssl1300.glb", 0.1, MODELS[3][3]
lon = math.radians(GEO_LONGITUDE)
camera = [GEO * math.cos(lon), GEO * math.sin(lon), 0.0]
angle = lon + range_m / GEO
spot = [GEO * math.cos(angle), GEO * math.sin(angle), 0.0]
velocity = [-GEO_SPEED * math.sin(lon), GEO_SPEED * math.cos(lon), 0.0]
look = norm([spot[i] - camera[i] for i in range(3)])
image_up = [0.0, 0.0, 1.0]
attitude = triad([1, 1, 1], [0, 0, 1], [-x for x in look], image_up)
offset = mul(attitude, center)
position = [spot[i] - offset[i] for i in range(3)]
# The Sun `phase_deg` from the camera's direction as the target sees it, turned
# about the image's up, 10 degrees out of the equator so the target is not shadowed
# by Earth at any phase.
back = [-x for x in look]
side = cross(image_up, back)
p, t = math.radians(phase_deg), math.radians(10.0)
sun = norm([
math.cos(t) * (math.cos(p) * back[i] + math.sin(p) * side[i]) + math.sin(t) * image_up[i]
for i in range(3)
])
fmt = lambda v, d=2: "[" + ", ".join(f"{x:.{d}f}" for x in v) + "]"
heading = textwrap.fill(description, 86, initial_indent="# ", subsequent_indent="# ")
return f"""{heading}
# A 1 m, f/{f_number:.0f} telescope ({100 / f_number:g} cm aperture, 5.5 urad per pixel, 0.6 by 0.34
# degrees) on one geostationary satellite, imaging an SSL-1300 {range_m / 1000:.0f} km ahead along
# the arc, lit at a phase of {phase_deg} degrees, against the stars toward the Milky Way in
# Monoceros. Stars are drawn at lighting L1 with camera C1 (scripts/fetch-stars.py).
# Generated by scripts/make-example-scenes.py; the model comes from
# scripts/fetch-models.sh.
#
# resolved render --scene <this file> --lighting L1 --camera C1 --pretty --preview geo.png
sun = {fmt([AU * x for x in sun], 0)}
moon = [0, -384400000, 0]
earth_velocity = {fmt(earth_velocity(sun))}
[camera]
focal_length = 1.0
f_number = {f_number:.1f}
exposure = {exposure}
[observer]
position = {fmt(camera)}
look_at = {fmt(spot)}
up = [0, 0, 1]
velocity = {fmt(velocity)}
# At lighting L1, Earth's surface shows July (from scripts/fetch-earth.sh), and lights
# the target's Earth-facing side.
[appearance]
earth_month = 7
[[target]]
model = "../models/nasa/{file}"
scale = {scale}
position = {fmt(position, 4)}
attitude = {fmt(quaternion(attitude), 9)}
"""
GEO_TELESCOPE = [
("geo-telescope-100km", 100e3, 30, 8.0, 6e-4,
"GEO to GEO at 100 km: the target about 55 px across, lit nearly face on, exposed "
"short of saturating it, with only the brighter stars behind it."),
("geo-telescope-100km-side", 100e3, 90, 8.0, 6e-4,
"GEO to GEO at 100 km, lit from the side: half the target in shadow."),
("geo-telescope-1000km", 1000e3, 30, 4.0, 0.2,
"GEO to GEO at 1000 km, exposed 0.2 s at f/4 as a surveillance camera would: the "
"target a few pixels across and far past saturation, in a field of stars to the "
"catalog's limit, about V 15, which gives a few DN."),
]
out = pathlib.Path(__file__).resolve().parent.parent / "examples" / "scenes"
for model in MODELS:
path = out / f"{model[0]}.toml"
@@ -458,3 +589,10 @@ print(f"wrote {path}")
path = out / "moonrise.toml"
path.write_text(moonrise())
print(f"wrote {path}")
path = out / "stars-pleiades.toml"
path.write_text(stars_pleiades())
print(f"wrote {path}")
for name, range_m, phase, f_number, exposure, description in GEO_TELESCOPE:
path = out / f"{name}.toml"
path.write_text(geo_telescope(range_m, phase, f_number, exposure, description))
print(f"wrote {path}")