MONKEY (fix-sky): day-long f64 sky clock; twinkle rates whole cycles per wrap

Review B2: the f32 clock wrapped hourly and every star's twinkle jumped at the
wrap. It now accumulates in f64 and wraps at 86400 s; the shader rounds each
twinkle rate to whole cycles per wrap, so the stars are seamless. The High
cloud detail drift still re-patterns once per 24 h (noted).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
pkuzic
2026-09-25 16:57:20 +01:00
co-authored by Claude Opus 5.5
parent 499fdd935f
commit 474b641499
2 changed files with 25 additions and 4 deletions
+11 -1
View File
@@ -7,6 +7,15 @@
#define_import_path benilla_world::sky_fx
const TAU: f32 = 6.2831853;
// MONKEY (fix-sky): the sky clock's wrap (`sky_fx::SKY_CLOCK_WRAP_S`, a day). Twinkle rates are
// whole cycles per wrap, so the stars never jump at the wrap.
const SKY_WRAP: f32 = 86400.0;
// The phase of a `rate` rad/s oscillator, rounded to whole cycles per wrap.
fn wrap_phase(t: f32, rate: f32) -> f32 {
let cycles = round(rate * SKY_WRAP / TAU);
return fract(cycles * (t / SKY_WRAP)) * TAU;
}
fn srgb_to_linear(c: vec3<f32>) -> vec3<f32> {
let lo = c / 12.92;
@@ -201,7 +210,8 @@ fn star_field(dir: vec3<f32>, t: f32, px: f32, band: f32) -> vec3<f32> {
let sigma = px * (0.55 + 0.7 * mag);
let spot = exp(-d * d / (2.0 * sigma * sigma));
let tw_amp = 0.18 + 0.3 * (1.0 - clamp(dir.y, 0.0, 1.0));
let tw = 1.0 + tw_amp * sin(t * (1.3 + 3.1 * j.x) + TAU * j.y) * sin(t * (0.6 + 1.7 * j.z) + TAU * h.z);
let tw = 1.0 + tw_amp * sin(wrap_phase(t, 1.3 + 3.1 * j.x) + TAU * j.y)
* sin(wrap_phase(t, 0.6 + 1.7 * j.z) + TAU * h.z);
// Star colour: mostly white, a few warm and a few blue-white.
let tint = mix(vec3<f32>(0.78, 0.86, 1.0), vec3<f32>(1.0, 0.88, 0.72), h.z);
acc += tint * (b * spot * tw);
+14 -3
View File
@@ -36,14 +36,23 @@ impl SkyQuality {
}
}
/// The sky's own animation clock (star twinkle, cloud detail drift), seconds wrapped to an hour so
/// the shader's `sin` keeps its precision. Frozen in capture mode, at `$WOW_CAPTURE_SKY_T` or 0.
/// The sky's own animation clock (star twinkle, cloud detail drift), seconds wrapped to a day.
/// Frozen in capture mode, at `$WOW_CAPTURE_SKY_T` or 0.
///
/// MONKEY (fix-sky): it wrapped hourly in f32, and every star's twinkle jumped at the wrap. Now it
/// accumulates in f64 and wraps at [`SKY_CLOCK_WRAP_S`]; the shader's twinkle rates are whole
/// cycles per wrap (seamless). The High cloud-detail drift still re-patterns at the wrap, once
/// per 24 h of continuous play.
#[derive(Resource, Default)]
pub struct SkyClock {
pub secs: f32,
acc: f64,
frozen: Option<f32>,
}
/// The sky clock's wrap in seconds; `sky_fx.wgsl`'s `SKY_WRAP` must match.
pub const SKY_CLOCK_WRAP_S: f64 = 86_400.0;
/// How strongly the glow shows: a broad halo at `GLOW_GAIN` × the sun colour at the sun itself.
pub(crate) const GLOW_GAIN: f32 = 0.22;
@@ -77,6 +86,7 @@ impl Plugin for SkyFxPlugin {
});
app.insert_resource(SkyClock {
secs: frozen.unwrap_or(0.0),
acc: 0.0,
frozen,
});
let quality = SkyQuality(SkyQuality::env_override().unwrap_or(0));
@@ -92,7 +102,8 @@ fn tick_sky_clock(time: Res<Time>, mut clock: ResMut<SkyClock>) {
}
return;
}
clock.secs = (clock.secs + time.delta_secs()) % 3600.0;
clock.acc = (clock.acc + time.delta_secs_f64()) % SKY_CLOCK_WRAP_S;
clock.secs = clock.acc as f32;
}
#[cfg(test)]