12 Commits

Author SHA1 Message Date
xfy
33ce1061ba fix(render): resolve validation crash from egui camera + brightpass uniform
Two runtime validation errors crashed the app on startup:

1. BrightPassMaterial used #[uniform(0)] threshold: f32 (bare f32 = 4-byte
   binding), but the WGSL BrightPassUniform struct is 16 bytes (threshold +
   3 pads). The pipeline-layout mismatch ("Buffer structure size 16...
   greater than min_binding_size, which is 4") killed the opaque_mesh2d
   pipeline. Fix: wrap threshold in a BrightPassUniform struct matching the
   WGSL layout, same pattern as BlurUniform/CompositeUniform.

2. bevy_egui 0.41's auto-context assigns PrimaryEguiContext to the FIRST
   Added<Camera> — with the 7-camera bloom pipeline, that's the offscreen
   camera (renders to Rgba16Float Image). egui's pipeline expects the
   window's Rgba8UnormSrgb surface → format mismatch crash. Fix: disable
   auto_create_primary_context (PreStartup system) and explicitly tag the
   composite (window) camera with PrimaryEguiContext.

Both fixes verified: the app now runs without validation errors for 8+
seconds. Physics tests (20/20) unaffected.
2026-07-15 09:42:19 +08:00
xfy
a7490c0c2f render: composite + ACES tone-map (bloom stage [5]), replaces upscale
Adds CompositeMaterial + composite.wgsl: combines the HDR scene with the
bloom pyramid output, applies ACES (Narkowicz) tone mapping, and writes
LDR to the window. Removes UpscaleMaterial + upscale.wgsl.

mirror_params now updates composite (bloom_strength, exposure) and
brightpass (threshold) uniforms each frame. resize_offscreen rebuilds
the full bloom pyramid targets on window resize.
2026-07-15 00:14:03 +08:00
xfy
ed6639738f render: blur pyramid (bloom stages [3]/[4]) — down then up
Adds BlurMaterial + blur.wgsl with a 13-tap weighted Gaussian kernel
(var<private> arrays — naga rejects dynamic indexing of const arrays),
run in downsample then upsample passes. For the 3-level pyramid:
bloom_0 (half, from brightpass) → bloom_1 (quarter) → bloom_2 (eighth),
then upsample to bloom_final (half). Camera orders -18/-17/-16/-15.

The bloom output is not yet composited (Task 6); this commit only wires
the passes and confirms they run in sequence without crashing.
2026-07-15 00:07:09 +08:00
xfy
6ccd0a173b render: bright-pass material + camera (bloom stage [2])
Adds BrightPassMaterial + brightpass.wgsl: extracts luminance above a
soft-knee threshold from the HDR offscreen into a half-res Rgba16Float
target (bloom_0). Camera order -19 (after offscreen at -20). The brightpass
output is not yet composited (Task 6); this commit only adds the pass and
confirms it runs without crashing.
2026-07-15 00:01:31 +08:00
xfy
0f33d80fd3 shader: gaussian-speck stars + star_aa toggle + bloom/exposure uniforms
star_color's smoothstep(0.5,0.0,d) with scale=80 produced blocky rectangles
at low render_scale. Replace with a gaussian speck: distance to cell center
with exp(-d²/r²) falloff, producing a round 2-3 pixel anti-aliased disk.
star_aa uniform toggles between the gaussian path (desktop default) and the
old square-cell fast path (web default).

Also adds bloom_threshold/bloom_strength/exposure uniform fields to
BlackHoleUniforms (used by later bloom tasks) with safe defaults.
2026-07-14 23:55:17 +08:00
xfy
e7c45804a4 tweak: lower default disk_tilt from 1.318 to 0.45
At 1.318 rad (~75.5 deg) the disk is nearly vertical: its normal points
almost along +Z while the camera yaw axis is world-Y, so the two axes
sit ~75 deg apart. Orbiting via yaw (a horizontal circle around world-Y)
therefore shears the disk through view -- full circle, squashed ellipse,
edge-on sliver, back circle -- which reads as the disk swinging or the
scene rolling.

0.45 rad (~25.8 deg) brings the disk near-horizontal (normal approx
(0, 0.90, 0.43)), shrinking the yaw-axis / disk-normal misalignment
from ~75 deg to ~26 deg. The swing is correspondingly muted; orbiting
feels like turning around the hole rather than shearing across a wall.

Both defaults are updated in lockstep: BlackHoleParams (the live runtime
default) and BlackHoleUniforms (the bootstrap uniform filled before the
first mirror_params frame).
2026-07-14 17:06:21 +08:00
xfy
17fbbf98e1 render: derive Default for BlackHoleMaterial
Clippy warned that the manual Default implementation for BlackHoleMaterial
could be derived (clippy::derivable_impls). We now derive Default directly
on the struct and remove the manual implementation block.
2026-07-14 15:09:38 +08:00
xfy
61edcfabd2 feat: plumb spin parameter into GPU uniform 2026-07-14 14:12:31 +08:00
xfy
e158c8c668 feat: wire render_scale via offscreen render-to-texture + upscale 2026-07-14 14:09:39 +08:00
xfy
4556376b4a fix: make the black hole actually render (was stuck on grey clear color)
The app showed only the camera clear color (grey srgb 43,44,47) — the
fullscreen quad's fragment shader produced no output. Two issues; the
second was the real blocker.

1. render/material.rs: skybox.wgsl declared binding 1 as texture_cube<f32>
   but the material's #[texture(1)] defaulted to D2. The mismatched
   bind-group layout vs. shader caused the pipeline to fail to specialize.
   Fix: dimension = "cube" on the texture attribute so the layout matches.

2. SHADER COMPOSITION (the actual blocker): the shader was split across
   naga_oil modules (ray_gen, geodesic, stars, disk, planets, grid, skybox)
   pulled in via #import singularity::... This compiled and validated with
   zero errors, but at runtime calling ANY cross-module-imported function
   made the fragment output nothing (only the clear color showed). Local
   functions were fine. Confirmed by bisecting a minimal repro with the
   user watching the screen: local fn -> renders; imported fn (even pure
   math) -> grey.

   Rather than chase the naga_oil 0.22 / Bevy 0.19 composition bug, inline
   every function into black_hole.wgsl and drop the #import singularity::*
   lines. The 7 standalone module files are removed. Rendering now works.

Also fixes scene/planets.rs: upload_planets was allocating a fresh
ShaderBuffer (new handle) every frame, which re-triggered the
AsBindGroup RetryNextUpdate that the previous commit's startup pre-fill
was meant to eliminate. Now mutates the existing buffer asset in place
via set_data, keeping the handle stable.
2026-07-13 16:43:01 +08:00
xfy
265ec9925d feat: BlackHoleUniforms + camera/params mirror system 2026-07-10 10:33:10 +08:00
xfy
a45d42c07a feat: full-screen quad + BlackHoleMaterial pipeline 2026-07-10 10:20:38 +08:00