fix(stars): balance AA so it only softens edges, not size or count
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.
This commit is contained in:
parent
f4e937f35b
commit
52cf4e4a29
@ -108,20 +108,18 @@ fn star_color(dir: vec3<f32>, intensity: f32) -> vec3<f32> {
|
|||||||
let center = cell + vec3<f32>(0.5);
|
let center = cell + vec3<f32>(0.5);
|
||||||
let dist = length(p - center); // Euclidean → round, never square
|
let dist = length(p - center); // Euclidean → round, never square
|
||||||
let col = mix(vec3<f32>(0.6, 0.7, 1.0), vec3<f32>(1.0, 0.9, 0.7), b);
|
let col = mix(vec3<f32>(0.6, 0.7, 1.0), vec3<f32>(1.0, 0.9, 0.7), b);
|
||||||
if (uniforms.star_aa != 0u) {
|
// Both paths share the same brightness-driven radius and the
|
||||||
// Soft Gaussian glow. The neighborhood scan lets the falloff
|
// same gain, so toggling AA only softens the edge — it does not
|
||||||
// decay smoothly to ~0 at the cell boundary instead of being
|
// change peak brightness or visible count. Before, the AA path
|
||||||
// hard-clipped, so the star is a round anti-aliased disk.
|
// 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 radius = 0.25 + b * 0.4;
|
||||||
let falloff = exp(-dist * dist / (radius * radius));
|
let falloff = select(
|
||||||
let bright = b * falloff;
|
smoothstep(radius, 0.0, dist), // hard edge
|
||||||
if (bright > best.x) {
|
exp(-4.6 * dist * dist / (radius * radius)), // soft edge
|
||||||
best = vec4<f32>(bright, col.r, col.g, col.b);
|
uniforms.star_aa != 0u);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Tight round disk: smoothstep on Euclidean distance.
|
|
||||||
let radius = 0.5;
|
|
||||||
let falloff = smoothstep(radius, 0.0, dist);
|
|
||||||
let bright = b * falloff;
|
let bright = b * falloff;
|
||||||
if (bright > best.x) {
|
if (bright > best.x) {
|
||||||
best = vec4<f32>(bright, col.r, col.g, col.b);
|
best = vec4<f32>(bright, col.r, col.g, col.b);
|
||||||
@ -129,9 +127,7 @@ fn star_color(dir: vec3<f32>, intensity: f32) -> vec3<f32> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return best.yzw * best.x * 3.0 * intensity;
|
||||||
let gain = select(3.0, 4.0, uniforms.star_aa != 0u);
|
|
||||||
return best.yzw * best.x * gain * intensity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- skybox ---
|
// --- skybox ---
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user