From 52cf4e4a291273aa6e0bb2c98666567209be8d8a Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 15 Jul 2026 10:23:29 +0800 Subject: [PATCH] fix(stars): balance AA so it only softens edges, not size or count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the round-star fix, toggling "Anti-aliased stars" made stars look bigger and more numerous instead of just smoother. The AA path differed from the hard-edge path in three ways that each inflated the footprint: - radius: AA used 0.25 + b*0.4 (up to 0.65); hard path used fixed 0.5 - gain: AA used 4.0; hard path used 3.0 (+33% peak brightness) - falloff: AA Gaussian decayed slowly (36.8% at one radius, never 0); hard path smoothstep hit 0 at the radius The slow Gaussian tail was the main offender: it kept dim stars lit far past the hard path's cutoff, lifting many sub-threshold stars above the visibility floor — the apparent "more stars". Balance the two paths so the toggle is purely an edge-softness control: - both use radius = 0.25 + b*0.4 (same size, brightness-driven) - both use gain 3.0 (same peak brightness) - AA steepens the Gaussian to exp(-4.6*d²/r²) so it converges to ~1% near the same radius where smoothstep cuts to 0 — matched footprint, soft vs hard edge. Peak brightness is now identical across the toggle; effective lit area differs by <30% (the Gaussian is a cone, smoothstep a flatter dome) and the visibility radius matches, so dim stars no longer pop in and out as AA is toggled. Validated: naga type-checks; app runs 20s on Metal (M4) with no shader errors; cargo test (14 physics tests) passes. --- assets/shaders/black_hole.wgsl | 36 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/assets/shaders/black_hole.wgsl b/assets/shaders/black_hole.wgsl index b7cdf10..0433c96 100644 --- a/assets/shaders/black_hole.wgsl +++ b/assets/shaders/black_hole.wgsl @@ -108,30 +108,26 @@ fn star_color(dir: vec3, intensity: f32) -> vec3 { let center = cell + vec3(0.5); let dist = length(p - center); // Euclidean → round, never square let col = mix(vec3(0.6, 0.7, 1.0), vec3(1.0, 0.9, 0.7), b); - if (uniforms.star_aa != 0u) { - // Soft Gaussian glow. The neighborhood scan lets the falloff - // decay smoothly to ~0 at the cell boundary instead of being - // hard-clipped, so the star is a round anti-aliased disk. - let radius = 0.25 + b * 0.4; - let falloff = exp(-dist * dist / (radius * radius)); - let bright = b * falloff; - if (bright > best.x) { - best = vec4(bright, col.r, col.g, col.b); - } - } else { - // Tight round disk: smoothstep on Euclidean distance. - let radius = 0.5; - let falloff = smoothstep(radius, 0.0, dist); - let bright = b * falloff; - if (bright > best.x) { - best = vec4(bright, col.r, col.g, col.b); - } + // Both paths share the same brightness-driven radius and the + // same gain, so toggling AA only softens the edge — it does not + // change peak brightness or visible count. Before, the AA path + // used a larger radius (up to 0.65 vs 0.5), a heavier gain + // (4.0 vs 3.0), and a slow-decaying Gaussian whose long tail + // lifted many dim stars above the visibility floor — that's + // what made AA look like "bigger and more" stars. + let radius = 0.25 + b * 0.4; + let falloff = select( + smoothstep(radius, 0.0, dist), // hard edge + exp(-4.6 * dist * dist / (radius * radius)), // soft edge + uniforms.star_aa != 0u); + let bright = b * falloff; + if (bright > best.x) { + best = vec4(bright, col.r, col.g, col.b); } } } } - let gain = select(3.0, 4.0, uniforms.star_aa != 0u); - return best.yzw * best.x * gain * intensity; + return best.yzw * best.x * 3.0 * intensity; } // --- skybox ---