Merge pull request #11680 from kacpherek/fix/near-chunks-no-xray

🤖 Agent: near sections no longer dither over far terrain (fade() is 0 or lod::HELD), and the replaced tile still stays behind for lod::FADE through previous, so no hole opens; the test bound lowered to 1,000 matches the half that now come in whole.
This commit is contained in:
Ludovic Marie authored and GitHub committed 2026-11-07 11:01:47 +01:00
commit e86cb3276b
1 file changed
+25 -24
+25 -24
View File
@@ -471,9 +471,9 @@ struct SectionGpu {
/// while its instance carries a fade (`drawn_faded`), and GPU culling's
/// pass leaves it out.
gpu_fading: bool,
/// When it began to fade in over the far terrain it replaces, which
/// stays whole behind it until then: a section new where far tiles are
/// drawn. Meshed again, it stays as it was.
/// When it came in over the far terrain it replaces (drawn whole at once,
/// `fade`): a section new where far tiles are drawn, which skips vanilla's
/// fade-in. Meshed again, it stays as it was.
fading: Option<std::time::Instant>,
/// When it began to fade out, its column gone over far terrain that
/// stays behind it (`Renderer::leave_section`); released once it has.
@@ -495,17 +495,19 @@ pub(crate) fn collect_animated_layers(
}
impl SectionGpu {
/// Its fade code this frame (`lod::fade_code`), 0 once whole. `retiring`:
/// its column has left the render distance, far terrain is coming in
/// under it (`lod::HELD`).
fn fade(&self, now: std::time::Instant, retiring: bool) -> u32 {
match self.leaving {
Some(since) => lod::fade_out_code(since, 0, now),
None if retiring => lod::HELD,
None => self
.fading
.and_then(|since| lod::fade_code(Some(since), 0, now))
.unwrap_or(0),
/// Its fade code this frame: 0, drawn whole, or `lod::HELD` (whole, in
/// front of far terrain) while it leaves (`leaving`) or its column has left
/// the render distance and far terrain is coming in under it (`retiring`).
/// A near section never dithers over far terrain: the holes of its pattern
/// showed its own inside (cave walls, the stone under the grass), nearer
/// than the tile behind, an x-ray of each column coming in or going out.
/// It comes in whole over the tile it replaces, which stays behind it until
/// `fading` is `lod::FADE` old, and leaves whole after as long.
fn fade(&self, retiring: bool) -> u32 {
if self.leaving.is_some() || retiring {
lod::HELD
} else {
0
}
}
/// Its vertices in `arena`, and in `translucent_arena` when `split` (there
@@ -571,23 +573,21 @@ impl SectionGpu {
/// once false, this stays false until the section is meshed again, leaves,
/// is held (`lod_retiring`), or the chunk fade-in time changes.
fn drawn_faded(&self, key: SectionKey, f: FadeInputs<'_>) -> bool {
let fade = self.fade(f.now, f.retiring.contains(&key));
let fade = self.fade(f.retiring.contains(&key));
let visibility = section_visibility(f.uploaded.get(&key), f.fade_ms, f.now);
section_instance([0.0; 3], fade, visibility)[3].to_bits()
!= section_instance([0.0; 3], 0, 1.0)[3].to_bits()
}
/// When its fade is over at the latest (`drawn_faded`): the later of the
/// ends of its fade-in over far terrain (`fading` and `lod::FADE`, a few
/// milliseconds after `fade` reaches 0) and of vanilla's (its first upload
/// and `f.fade_ms`). None while it leaves or is held, which ends only when
/// it goes or is meshed again, and without either fade-in.
/// When its fade is over at the latest (`drawn_faded`): the end of
/// vanilla's fade-in (its first upload and `f.fade_ms`; one coming in over
/// far terrain is whole at once, `fade`). None while it leaves or is held,
/// which ends only when it goes or is meshed again, and without a fade-in.
fn fade_end(&self, key: SectionKey, f: FadeInputs<'_>) -> Option<Instant> {
if self.leaving.is_some() || f.retiring.contains(&key) {
return None;
}
let vanilla = f.uploaded.get(&key).filter(|_| f.fade_ms > 0);
let vanilla = vanilla.map(|&t| t + std::time::Duration::from_millis(f.fade_ms));
vanilla.max(self.fading.map(|t| t + lod::FADE))
vanilla.map(|&t| t + std::time::Duration::from_millis(f.fade_ms))
}
}
/// Which of a mesh's ranges `move_off_page` moves: what it holds in the section
@@ -8155,7 +8155,7 @@ impl Renderer {
let fading_over_lods = self.sections_fading_over_lods(now);
let fade_code = move |section: &SectionGpu, key: &SectionKey| {
if fading_over_lods {
section.fade(now, retiring.contains(key))
section.fade(retiring.contains(key))
} else {
0
}
@@ -13473,7 +13473,8 @@ mod tests {
last = now;
}
assert!(set_by.iter().all(|&n| n > 20), "flags set {set_by:?}");
assert!(handed_back > 2_000, "{handed_back} handed back");
// Over a thousand: the half of the uploads over far terrain come in whole.
assert!(handed_back > 1_000, "{handed_back} handed back");
// Switched off with sections still flagged: none keeps a record or a
// flag, and each is marked as while GPU culling is off.
assert!(sim.records.fading() > 0, "none flagged at the end");