basis() derived `right` from `forward × world_up`, which degenerated to
a zero vector when forward aligned with world-Y (pitch = ±π/2) — the
cross product vanished, normalization produced garbage, and crossing
the pole flipped the image 180°.
Right now depends on yaw alone: Vec3::new(cos yaw, 0, -sin yaw). It is
a unit vector in the y=0 plane for any yaw, so it never goes to zero
regardless of pitch. In the original upper hemisphere (cp > 0) this is
exactly the old value after normalization, so existing views are
unchanged; it additionally stays perfectly horizontal for all pitch,
fixing a subtle roll the cross-product form introduced below the equator.
With the singularity gone, pitch is unclamped from [0.05, π-0.05] to
[-π+0.05, π-0.05]: the camera can now cross both poles and reach below
the disk plane without flipping. The ±0.05 margin only avoids the exact
origin-axis points where forward = ∓Y and yaw becomes meaningless.
yaw is also wrapped to (-π, π] on each drag so it cannot drift out of
the UI slider range (which would snap the view when the slider is later
touched); cos/sin periodicity makes the wrap visually lossless.
The UI pitch slider range is widened to match. Stale "gimbal pole"
comments that described the old restriction are corrected.
basis() still returns (eye, forward, right, up), so the uniform bridge
in plugin.rs and both shaders are untouched.
Fixes clippy::approx_constant errors caused by using the hardcoded value 3.14
for camera yaw and accretion disk tilt sliders. Using std::f32::consts::PI
resolves the errors and uses the precise constant value.
The quad mesh was built once at startup with the initial aspect ratio, so
widening the window afterward left empty edges. Add a FullscreenQuad marker
component and a fit_quad_to_window system that rescales the quad's Transform
to the live aspect each frame (only mutating on change).
Also remove the misleading 'Render scale' slider — it isn't wired to a real
sub-resolution render target in Phase 1 (the full-screen quad always renders
at window resolution). Lowering Steps is the real perf lever. Documented in
a code comment for future work.