feat/atmospheric-scattering #97

Merged
akadmin merged 3 commits from feat/atmospheric-scattering into main 2026-07-06 11:32:28 +00:00
Owner

closes #20

closes #20
Implements issue #20: raymarched Rayleigh + Mie sky as a second
fullscreen-triangle pipeline on the skybox template, driven by the
scene's directional light.

- atmosphere_fragment.glsl: single-scattering Nishita march (16
  primary / 8 secondary samples), Rayleigh + Cornette-Shanks Mie
  phase (forward peak = sun glow), planet-surface camera with
  horizon clamping, same Reinhard+gamma as the rest of the pipeline.
  Shares skybox_vertex.glsl (reversed-Z unprojection) unchanged.
- Push-constants only: vertex inv_view_proj 0..64 + hand-packed
  AtmospherePush 64..128 (sun, beta coefficients, radii, scale
  heights, mie g, eye height) - exactly the 128-byte minimum, no
  descriptor sets. AtmosphereParams (Earth defaults) lives on Scene.
- SkyMode { Atmosphere (default) | Environment }: new
  render_offscreen parameter; editor exposes a viewport dropdown and
  auto-switches to Environment when an HDR loads; the runtime binary
  always renders Atmosphere (environments aren't serialized).
- Aerial fog: LightsData gains a fog_color_density vec4 (UBO 464 ->
  480 bytes, mirrored in fragment/depth/unlit shaders); fragment.glsl
  mixes toward a sun-elevation-derived horizon color on view distance
  before tonemap. Density 0 under Environment keeps HDR scenes
  untouched.
- CPU helpers (sun_direction with noon fallback = NaN guard,
  fog_color_from_sun, push packing) unit-tested; 10 new tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reworks the sky selection from ADR-0032's first cut (editor-state
dropdown) into scene data, addressing three gaps: the sky showed by
default, a loaded HDR could never be changed or removed, and it
wasn't part of the scene.

- New Sky component (kind: Atmosphere | Hdr, hdr_asset:
  Option<AssetId>): lowest-index Sky entity drives the frame's sky
  (frame::gather_sky); no Sky entity renders no sky at all. Rides
  EntityFile, so it saves/loads, exports, snapshots for Play, and
  survives delete/undo.
- HDR environments are asset references now: editable in the
  inspector (kind toggle + browse), removable by deleting the
  entity, rotatable — the entity's rotation rotates the environment
  (inverse rotation pushed to the skybox shader at offset 64) to
  align off-axis HDRs with the world grid.
- EditorLayer::sync_environment reconciles the GPU IBL with the
  component each frame: changed asset -> background precompute; removed
  -> reset to the neutral default via a constant-grey precompute
  (also reverts ambient lighting). File -> Load Environment… now
  imports the asset and creates/updates the Sky entity through
  undo-able commands (SpawnSky/SetSky/AddSky).
- Runtime binary precomputes the scene's HDR environment once at
  startup, so exported games get HDR skies.
- Editing the sky in the material editor (Blender-style World
  target) considered and deferred — recorded in ADR-0032.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(renderer): straighten the sky horizon — interpolate homogeneous ray points
All checks were successful
CI / build (pull_request) Successful in 3m15s
b1d2091686
The sky vertex shader unprojected the view ray per-vertex (after the
perspective divide) and let the rasterizer interpolate the result.
Post-divide points are not linear in screen space, and the fullscreen
triangle is asymmetric ((-1,-1),(3,-1),(-1,3)), so the interpolation
error warped the direction field asymmetrically — a visibly tilted
horizon, present since the ADR-0015 skybox but made obvious by the
atmosphere's crisp horizon line.

skybox_vertex.glsl now outputs the pre-divide homogeneous unprojected
near/far points (IVP * (ndc, z, 1) is linear in ndc, so interpolation
is exact); both sky fragment shaders (skybox, atmosphere) perform the
perspective divide and derive the ray per fragment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
akadmin deleted branch feat/atmospheric-scattering 2026-07-06 11:32:28 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
akadmin/NemesisEngine!97
No description provided.