pub struct EstNormCache { /* private fields */ }Expand description
Per-column solid/air bitset grid covering a 2D bounding region —
(x1 - x0 + 2*RAD) × (y1 - y0 + 2*RAD) columns. Decoding each
column to a bitset once turns the estnorm 5×5×5 neighbourhood query
into O(1) bit tests. A 448×448 bake (extending to 452×452 with
padding) needs about 6.4 MB.
Implementations§
Source§impl EstNormCache
impl EstNormCache
Sourcepub fn build(
world_data: &[u8],
column_offsets: &[u32],
vsid: u32,
x0: i32,
y0: i32,
x1: i32,
y1: i32,
) -> Self
pub fn build( world_data: &[u8], column_offsets: &[u32], vsid: u32, x0: i32, y0: i32, x1: i32, y1: i32, ) -> Self
Build the bit-grid cache covering the bounding region
[x0..x1) × [y0..y1) extended by ESTNORMRAD padding on
each side. Calling Self::estnorm for any (x, y) inside
the original [x0..x1) × [y0..y1) box is then a pure read.
Wraps Self::build_with_reader with a flat-table closure.
Sourcepub fn build_with_reader_z<'r>(
column_reader: impl Fn(i32, i32, i32) -> Option<&'r [u8]>,
x0: i32,
y0: i32,
x1: i32,
y1: i32,
) -> Self
pub fn build_with_reader_z<'r>( column_reader: impl Fn(i32, i32, i32) -> Option<&'r [u8]>, x0: i32, y0: i32, x1: i32, y1: i32, ) -> Self
Z-aware variant of Self::build_with_reader for stacked
grids. column_reader(x, y, chz_delta) returns the slab bytes
of the column at cache-XY (x, y) in the chunk chz_delta
layers away in z (0 = the target layer, -1 = the layer above
in world-z, +1 = below), or None for implicit-air / missing.
The chz_delta == 0 reads build the in-plane cache exactly like
Self::build_with_reader; the ±1 reads populate the
Self::z_below / Self::z_above overlays so Self::solid
— and therefore Self::ambient_occlusion / Self::estnorm —
see the neighbouring chunk’s voxels across the z-seam instead of
the implicit air-above / bedrock-below boundary. Where a z-
neighbour is absent the overlay falls back to that same boundary
(air above, solid below), so a topmost/bottommost chunk bakes
identically to the single-layer path.
Sourcepub fn build_with_reader<'r>(
column_reader: impl Fn(i32, i32) -> Option<&'r [u8]>,
x0: i32,
y0: i32,
x1: i32,
y1: i32,
) -> Self
pub fn build_with_reader<'r>( column_reader: impl Fn(i32, i32) -> Option<&'r [u8]>, x0: i32, y0: i32, x1: i32, y1: i32, ) -> Self
S4B.4.b: chunk-aware cache build. The closure
column_reader(x, y) returns the slab bytes of the column
at world-or-grid-local position (x, y), or None for an
implicit-air / out-of-grid column (matching build’s OOB
“treat as full air” semantics).
No vsid bound — the reader owns OOB handling. Per-chunk
bakes use a closure that resolves (x, y) to a neighbour
chunk via Grid::chunk(IVec3) so the 2-voxel padding
extends seamlessly across chunk boundaries.
The cache’s Self::vsid field is left at 0 for chunk-
aware builds — the field is dead-code anyway, preserved
only for inspection.
Sourcepub fn estnorm(&self, x: i32, y: i32, z: i32) -> [f32; 3]
pub fn estnorm(&self, x: i32, y: i32, z: i32) -> [f32; 3]
Estimate the surface orientation at solid voxel (x, y, z) as
the occupancy gradient of its 5×5×5 neighbourhood:
n = Σ_{solid neighbours} offset, normal = n / |n|(the sum runs over offset ∈ [-2, 2]³). n points toward the
denser (solid) side; the lighting formulas in update_lighting
are calibrated to that orientation. On a flat surface the solid
half-space cancels laterally and leaves n along the inward
axis. An all-solid or all-air neighbourhood gives n = 0 →
(0, 0, 0), which the lighting math treats as unlit.
(x, y) must lie inside the cache’s [x0..x1) × [y0..y1) region
(the padded border supplies the ±2 neighbours); z is
unconstrained.
Sourcepub fn ambient_occlusion(&self, x: i32, y: i32, z: i32, radius: i32) -> f32
pub fn ambient_occlusion(&self, x: i32, y: i32, z: i32, radius: i32) -> f32
AO.2 — ambient occlusion at solid voxel (x, y, z). Returns 0.0
(open, e.g. a flat floor under open sky, or a convex edge) … 1.0
(fully enclosed).
Per-exposed-face, normal-free: for each of the 6 axis faces whose
immediate neighbour is air (an exposed face), sample the ±AO_RAD
half-space in front of that face (offset · face_dir > 0) and
measure how much of it is solid (inverse-distance weighted). This only
fires at concave corners — a perpendicular solid sitting in front of
an exposed face. Flat faces and convex edges read 0 (the space in
front of every exposed face is air). Crucially it does not use the
estnorm gradient normal, which tilts near a convex edge and would make
a voxel’s own folded-over surface (e.g. a pillar’s top above its side
face) count as occlusion — the “pillow” border on every edge.
radius is the sampling reach (clamped to ESTNORMRAD, the cache’s
padding); 1 = a tight 1-voxel concave edge, 2 = a wider contact.
Auto Trait Implementations§
impl Freeze for EstNormCache
impl RefUnwindSafe for EstNormCache
impl Send for EstNormCache
impl Sync for EstNormCache
impl Unpin for EstNormCache
impl UnsafeUnpin for EstNormCache
impl UnwindSafe for EstNormCache
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more