Added earth surface texture

This commit is contained in:
connor committed 2026-10-14 20:12:49 -04:00
1 parent 5b802b4455
commit e77d68d0a6
27 files changed
+1284 -93

No files matched your search

+37 -11
View File
@@ -5,9 +5,15 @@ 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
Earth's limb crossing the image 2 degrees above center, Earth below and space
above. The camera distance makes the model's bounding sphere span about 5.6
degrees, half the example camera's width. The Sun direction is the one, on a
3-degree grid, that best lights the three visible body faces and Earth near the
limb, without putting the spacecraft in Earth's shadow.
degrees, half the example camera's width.
Earth is turned so the ground behind the spacecraft, at the image center, is
25 N 33 E (Egypt, the Nile and the Red Sea), with the camera looking north
toward the Mediterranean on the limb. The Sun is the direction, on a 2-degree
grid, that puts it at least 58 degrees above that ground (cos i >= 0.85) and
best lights the spacecraft's three visible faces, without putting the
spacecraft in Earth's shadow. With the Sun that high over the ground, one face
is lit at a slant.
Model centers and radii were measured from the decoded files at the listed
scales (the bounding box of every vertex); remeasure if a model changes.
@@ -18,6 +24,10 @@ import pathlib
import textwrap
RE = 6378137.0
# The ground at the image center, geocentric latitude and longitude in degrees.
GROUND = (25.0, 33.0)
# The least cos(incidence) the Sun may have on that ground.
GROUND_SUN = 0.85
AU = 1.495978707e11
LEO = 7.0e6
GEO = 42_164_000.0
@@ -105,20 +115,29 @@ def scene(name, file, scale, center, radius, orbit, description):
offset = mul(attitude, center)
position = [look[i] - offset[i] for i in range(3)]
to_limb = [-math.cos(limb), math.sin(limb), 0.0]
reach = math.sqrt(orbit * orbit - RE * RE)
limb_normal = norm([look[i] + reach * to_limb[i] for i in range(3)])
# The ground behind the spacecraft at the image center: where the boresight,
# continued past the spacecraft, meets Earth.
b = dot(look, boresight)
reach = -b - math.sqrt(b * b - (dot(look, look) - RE * RE))
ground = norm([look[i] + reach * boresight[i] for i in range(3)])
# Turn Earth so GROUND is there, with north along the camera's view across it.
lat, lon = (math.radians(x) for x in GROUND)
fixed = [math.cos(lat) * math.cos(lon), math.cos(lat) * math.sin(lon), math.sin(lat)]
north = norm([boresight[i] - dot(boresight, ground) * ground[i] for i in range(3)])
earth = triad(fixed, [0, 0, 1], ground, north)
best = None
for az in range(0, 360, 3):
for el in range(-87, 90, 3):
for az in range(0, 360, 2):
for el in range(-88, 90, 2):
a, e = math.radians(az), math.radians(el)
sun = [math.cos(e) * math.cos(a), math.cos(e) * math.sin(a), math.sin(e)]
if dot(sun, [-1.0, 0.0, 0.0]) > math.cos(limb):
continue # behind Earth: the spacecraft would be in shadow
if dot(ground, sun) < GROUND_SUN:
continue
faces = [dot(mul(attitude, n), sun) for n in ([1, 0, 0], [0, 1, 0], [0, 0, 1])]
score = min(min(faces), dot(limb_normal, sun))
if best is None or score > best[0]:
best = (score, sun)
if best is None or min(faces) > best[0]:
best = (min(faces), sun)
sun = best[1]
fmt = lambda v, d=2: "[" + ", ".join(f"{x:.{d}f}" for x in v) + "]"
@@ -131,15 +150,22 @@ def scene(name, file, scale, center, radius, orbit, description):
return f"""{header}
#
# resolved render --scene examples/scenes/{name}.toml --preview {name}.png
# resolved render --scene examples/scenes/{name}.toml --lighting L1 --preview {name}.png
sun = {fmt([AU * x for x in sun], 0)}
moon = [0, 0, -3.844e8]
# Earth-fixed to inertial: 25 N 33 E behind the spacecraft, looking north.
earth_attitude = {fmt(quaternion(earth), 9)}
[observer]
position = {fmt(camera)}
look_at = {fmt(look)}
up = [1, 0, 0]
# At lighting L1, Earth's surface shows July (from scripts/fetch-earth.sh).
[appearance]
earth_month = 7
[[target]]
model = "../models/nasa/{file}"
scale = {scale}