feat: richer nebula sky and planet surface textures

Extend gen_nebula_sky.py with two more dust-lane layers at different
scales and subtle hue variation within the bright core. Add
gen_planet_surface.py (no prior generator existed) producing latitude
bands, storm vortices, and a lit/unlit terminator baked from the
planet mesh's actual UV convention against arena_02's directional
light, verified in-engine via screenshots.
This commit is contained in:
Josh Creek
2026-08-04 07:18:51 +01:00
parent 3257f5cbcc
commit 73fb83a0da
6 changed files with 223 additions and 1 deletions
+33
View File
@@ -61,6 +61,14 @@ haze = bilinear_sample(fft_field(3.0, seed=21), xx + warp_x * 1.3, yy + warp_y *
ridged = 1.0 - np.abs(2.0 * bilinear_sample(fft_field(1.6, seed=31), xx + warp_x * 0.8, yy + warp_y * 0.8) - 1.0)
dust = np.clip((ridged - 0.72) / 0.28, 0.0, 1.0) ** 1.5
# Two more dust-lane layers at scales straddling the primary one above, so the sky
# reads as several overlapping filament systems instead of one repeated pattern.
ridged_fine = 1.0 - np.abs(2.0 * bilinear_sample(fft_field(1.0, seed=41), xx + warp_x * 1.6, yy + warp_y * 1.6) - 1.0)
dust_fine = np.clip((ridged_fine - 0.78) / 0.22, 0.0, 1.0) ** 1.2 # delicate, sparse filaments
ridged_wide = 1.0 - np.abs(2.0 * bilinear_sample(fft_field(2.2, seed=51), xx + warp_x * 0.4, yy + warp_y * 0.4) - 1.0)
dust_wide = np.clip((ridged_wide - 0.65) / 0.35, 0.0, 1.0) ** 1.5 # broad, soft secondary lane
# Confine the bright nebula body to an off-center round-ish region (like the reference's
# bright core), fading into the darker starfield toward the poles/edges.
cx, cy = W * 0.42, H * 0.46
@@ -104,6 +112,22 @@ def ramp(t):
color = ramp(density)
print("adding core color variation...")
# Real emission nebulae mix H-alpha (magenta/red) and OIII (faint teal/cyan) regions
# rather than being one flat hue at a given brightness -- nudge hue in slow-varying
# patches, confined to the bright body, on top of the brightness-only ramp above.
hue_field = bilinear_sample(fft_field(2.4, seed=61), xx + warp_x * 0.9, yy + warp_y * 0.9)
hue_field = (hue_field - 0.5) * 2.0 # -1..1
warm_tint = np.array([0.25, 0.02, -0.05])
cool_tint = np.array([-0.12, 0.10, 0.06])
hue_variation = np.where(
hue_field[..., None] > 0,
hue_field[..., None] * warm_tint[None, None, :],
-hue_field[..., None] * cool_tint[None, None, :],
)
core_variation_strength = (mask ** 0.8) * 0.22
color = np.clip(color + hue_variation * core_variation_strength[..., None], 0.0, 1.0)
# Blue-violet outer haze wash, additive, strongest away from the bright core.
haze_color = np.array([0.10, 0.11, 0.30])
haze_amount = (haze * 0.5 + 0.5) * (1.0 - mask) * 0.35
@@ -113,6 +137,15 @@ color += haze_amount[..., None] * haze_color[None, None, :]
dust_strength = (dust * mask * 0.85)[..., None]
color *= (1.0 - dust_strength * 0.9)
# Two more dust-lane layers at different scales, weaker than the primary lane. The
# wide lane is allowed to bleed slightly past the core edge (mask relaxed) since real
# dust lanes don't stop precisely at a nebula's bright-body boundary.
dust_fine_strength = (dust_fine * mask * 0.55)[..., None]
color *= (1.0 - dust_fine_strength * 0.55)
dust_wide_strength = (dust_wide * (mask * 0.7 + 0.15) * 0.5)[..., None]
color *= (1.0 - dust_wide_strength * 0.45)
color = np.clip(color, 0.0, 1.0)
print("adding stars...")