fix(renderer): align mesher vertex placement with floor() block convention
This commit is contained in:
parent
213a113fc9
commit
7cc43ca05e
|
|
@ -167,9 +167,9 @@ pub fn generate_mesh(chunk: &Chunk, neighbors: &Neighbors) -> (Vec<Vertex>, Vec<
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|y, x0, z0, w, h| {
|
|y, x0, z0, w, h| {
|
||||||
let (xmin, xmax) = (coord(x0) - 0.5, coord(x0 + w) - 0.5);
|
let (xmin, xmax) = (coord(x0), coord(x0 + w));
|
||||||
let (zmin, zmax) = (coord(z0) - 0.5, coord(z0 + h) - 0.5);
|
let (zmin, zmax) = (coord(z0), coord(z0 + h));
|
||||||
let yp = coord(y) + 0.5;
|
let yp = coord(y + 1);
|
||||||
[
|
[
|
||||||
[xmin, yp, zmax],
|
[xmin, yp, zmax],
|
||||||
[xmax, yp, zmax],
|
[xmax, yp, zmax],
|
||||||
|
|
@ -194,9 +194,9 @@ pub fn generate_mesh(chunk: &Chunk, neighbors: &Neighbors) -> (Vec<Vertex>, Vec<
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|y, x0, z0, w, h| {
|
|y, x0, z0, w, h| {
|
||||||
let (xmin, xmax) = (coord(x0) - 0.5, coord(x0 + w) - 0.5);
|
let (xmin, xmax) = (coord(x0), coord(x0 + w));
|
||||||
let (zmin, zmax) = (coord(z0) - 0.5, coord(z0 + h) - 0.5);
|
let (zmin, zmax) = (coord(z0), coord(z0 + h));
|
||||||
let yp = coord(y) - 0.5;
|
let yp = coord(y);
|
||||||
[
|
[
|
||||||
[xmin, yp, zmin],
|
[xmin, yp, zmin],
|
||||||
[xmax, yp, zmin],
|
[xmax, yp, zmin],
|
||||||
|
|
@ -221,9 +221,9 @@ pub fn generate_mesh(chunk: &Chunk, neighbors: &Neighbors) -> (Vec<Vertex>, Vec<
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|x, z0, y0, w, h| {
|
|x, z0, y0, w, h| {
|
||||||
let (zmin, zmax) = (coord(z0) - 0.5, coord(z0 + w) - 0.5);
|
let (zmin, zmax) = (coord(z0), coord(z0 + w));
|
||||||
let (ymin, ymax) = (coord(y0) - 0.5, coord(y0 + h) - 0.5);
|
let (ymin, ymax) = (coord(y0), coord(y0 + h));
|
||||||
let xp = coord(x) + 0.5;
|
let xp = coord(x + 1);
|
||||||
[
|
[
|
||||||
[xp, ymin, zmax],
|
[xp, ymin, zmax],
|
||||||
[xp, ymin, zmin],
|
[xp, ymin, zmin],
|
||||||
|
|
@ -248,9 +248,9 @@ pub fn generate_mesh(chunk: &Chunk, neighbors: &Neighbors) -> (Vec<Vertex>, Vec<
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|x, z0, y0, w, h| {
|
|x, z0, y0, w, h| {
|
||||||
let (zmin, zmax) = (coord(z0) - 0.5, coord(z0 + w) - 0.5);
|
let (zmin, zmax) = (coord(z0), coord(z0 + w));
|
||||||
let (ymin, ymax) = (coord(y0) - 0.5, coord(y0 + h) - 0.5);
|
let (ymin, ymax) = (coord(y0), coord(y0 + h));
|
||||||
let xp = coord(x) - 0.5;
|
let xp = coord(x);
|
||||||
[
|
[
|
||||||
[xp, ymin, zmin],
|
[xp, ymin, zmin],
|
||||||
[xp, ymin, zmax],
|
[xp, ymin, zmax],
|
||||||
|
|
@ -275,9 +275,9 @@ pub fn generate_mesh(chunk: &Chunk, neighbors: &Neighbors) -> (Vec<Vertex>, Vec<
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|z, x0, y0, w, h| {
|
|z, x0, y0, w, h| {
|
||||||
let (xmin, xmax) = (coord(x0) - 0.5, coord(x0 + w) - 0.5);
|
let (xmin, xmax) = (coord(x0), coord(x0 + w));
|
||||||
let (ymin, ymax) = (coord(y0) - 0.5, coord(y0 + h) - 0.5);
|
let (ymin, ymax) = (coord(y0), coord(y0 + h));
|
||||||
let zp = coord(z) + 0.5;
|
let zp = coord(z + 1);
|
||||||
[
|
[
|
||||||
[xmin, ymin, zp],
|
[xmin, ymin, zp],
|
||||||
[xmax, ymin, zp],
|
[xmax, ymin, zp],
|
||||||
|
|
@ -302,9 +302,9 @@ pub fn generate_mesh(chunk: &Chunk, neighbors: &Neighbors) -> (Vec<Vertex>, Vec<
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|z, x0, y0, w, h| {
|
|z, x0, y0, w, h| {
|
||||||
let (xmin, xmax) = (coord(x0) - 0.5, coord(x0 + w) - 0.5);
|
let (xmin, xmax) = (coord(x0), coord(x0 + w));
|
||||||
let (ymin, ymax) = (coord(y0) - 0.5, coord(y0 + h) - 0.5);
|
let (ymin, ymax) = (coord(y0), coord(y0 + h));
|
||||||
let zp = coord(z) - 0.5;
|
let zp = coord(z);
|
||||||
[
|
[
|
||||||
[xmax, ymin, zp],
|
[xmax, ymin, zp],
|
||||||
[xmin, ymin, zp],
|
[xmin, ymin, zp],
|
||||||
|
|
|
||||||
|
|
@ -687,7 +687,7 @@ impl Renderer {
|
||||||
fn cull_to_frustum(&self, mvp: glam::Mat4) -> (Vec<&GpuMesh>, usize) {
|
fn cull_to_frustum(&self, mvp: glam::Mat4) -> (Vec<&GpuMesh>, usize) {
|
||||||
let frustum = Frustum::from_view_proj(mvp);
|
let frustum = Frustum::from_view_proj(mvp);
|
||||||
|
|
||||||
// A chunk spans CHUNK_SIZE blocks on each axis. The mesher centres block i on [i - 0.5, i + 0.5], so a chunk's box runs [offset - 0.5, offset + CHUNK_SIZE - 0.5]; the extent below is added to that shifted minimum corner.
|
// A chunk spans CHUNK_SIZE blocks on each axis. Block i spans [i, i+1), so a chunk's geometry runs [offset, offset + CHUNK_SIZE].
|
||||||
#[expect(
|
#[expect(
|
||||||
clippy::cast_precision_loss,
|
clippy::cast_precision_loss,
|
||||||
reason = "CHUNK_SIZE is 32, exactly representable as f32"
|
reason = "CHUNK_SIZE is 32, exactly representable as f32"
|
||||||
|
|
@ -700,7 +700,7 @@ impl Renderer {
|
||||||
.values()
|
.values()
|
||||||
.filter(|mesh| {
|
.filter(|mesh| {
|
||||||
// Reject the chunk when its world-space bounding box falls entirely outside the frustum.
|
// Reject the chunk when its world-space bounding box falls entirely outside the frustum.
|
||||||
let box_min = glam::Vec3::from(mesh.world_offset) - glam::Vec3::splat(0.5);
|
let box_min = glam::Vec3::from(mesh.world_offset);
|
||||||
let visible = frustum.intersects_aabb(box_min, box_min + chunk_extent);
|
let visible = frustum.intersects_aabb(box_min, box_min + chunk_extent);
|
||||||
if !visible {
|
if !visible {
|
||||||
culled += 1;
|
culled += 1;
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ fn single_block_quads_carry_their_own_face_normal() {
|
||||||
let (vertices, _) = generate_mesh(&chunk, &Neighbors::default());
|
let (vertices, _) = generate_mesh(&chunk, &Neighbors::default());
|
||||||
|
|
||||||
// The constant axis and plane coordinate of each face of a block at (5, 5, 5), indexed by packed normal. Deducing the expected direction from the geometry rather than from the emission order keeps the assertion valid if the passes are reordered.
|
// The constant axis and plane coordinate of each face of a block at (5, 5, 5), indexed by packed normal. Deducing the expected direction from the geometry rather than from the emission order keeps the assertion valid if the passes are reordered.
|
||||||
let expected: [(usize, f32); 6] = [(0, 5.5), (0, 4.5), (1, 5.5), (1, 4.5), (2, 5.5), (2, 4.5)];
|
let expected: [(usize, f32); 6] = [(0, 6.0), (0, 5.0), (1, 6.0), (1, 5.0), (2, 6.0), (2, 5.0)];
|
||||||
|
|
||||||
let mut seen = [false; 6];
|
let mut seen = [false; 6];
|
||||||
for quad in vertices.chunks_exact(4) {
|
for quad in vertices.chunks_exact(4) {
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ The half-scale voxel grid ([ADR-0002](adr/0002-half-scale-voxel-grid.md)) makes
|
||||||
|
|
||||||
### Vertex extents: a shared convention
|
### Vertex extents: a shared convention
|
||||||
|
|
||||||
The mesher centres block `i` on the interval `[i - 0.5, i + 0.5]`, hence the `± 0.5` offsets throughout the quad emitters. A chunk's geometry therefore spans `[offset - 0.5, offset + CHUNK_SIZE - 0.5]`, **not** `[offset, offset + CHUNK_SIZE]`.
|
The mesher places block `i` on the interval `[i, i + 1)`: its near face sits at `coord(i)` and its far face at `coord(i + 1)`. This matches the `floor()`-based coordinate-to-block mapping used by the rest of the engine (`position.floor()` yields the block index), so a raycast or cursor highlight that floors a hit point resolves to the same cell the mesher drew.
|
||||||
|
|
||||||
That half-block shift is duplicated in the frustum cull, which builds each chunk's bounding box from the same shifted minimum corner. Nothing in the type system ties the two together: if the mesher's extents ever change, the cull's box must change with them, or chunks will be culled while still partially on screen (or drawn while fully off it). The coupling is noted at both sites; treat it as an invariant of this file pair.
|
A chunk's geometry therefore spans `[offset, offset + CHUNK_SIZE]`. The frustum cull builds each chunk's bounding box from the same origin; if the mesher's extents ever change, the cull's box must change with them, or chunks will be culled while still partially on screen (or drawn while fully off it). The coupling is noted at both sites; treat it as an invariant of this file pair.
|
||||||
|
|
||||||
## Neighbour-aware boundary culling
|
## Neighbour-aware boundary culling
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue