Consider neighbouring brickmaps when doing non-surface voxel culling

This commit is contained in:
Jarrod Doyle 2023-07-28 11:03:32 +01:00
parent ea84b43158
commit 42fdf48660
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
1 changed files with 81 additions and 25 deletions

View File

@ -236,16 +236,34 @@ impl BrickmapManager {
glam::uvec3(grid_dims[0], grid_dims[1], grid_dims[2]), glam::uvec3(grid_dims[0], grid_dims[1], grid_dims[2]),
); );
// The CPU side World uses different terminology and coordinate system // Get block + neighbour blocks
// We need to convert between Brickmap and World pos and get the relevant // Cull based on that
// World voxels let grid_pos = grid_pos.as_ivec3();
let (chunk_pos, block_pos) = Self::grid_pos_to_world_pos(world, grid_pos.as_ivec3()); let center_pos = Self::grid_pos_to_world_pos(world, grid_pos);
let block = world.get_block(chunk_pos, block_pos); let forward_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(1, 0, 0));
let backward_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(-1, 0, 0));
let left_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 0, -1));
let right_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 0, 1));
let up_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, 1, 0));
let down_pos = Self::grid_pos_to_world_pos(world, grid_pos + glam::ivec3(0, -1, 0));
// The World gives us the full voxel data for the requested block of voxels. let center_block = world.get_block(center_pos.0, center_pos.1);
// For Brickmap raytracing we only care about the visible surface voxels, so let forward_block = world.get_block(forward_pos.0, forward_pos.1);
// we need to cull any interior voxels. let backward_block = world.get_block(backward_pos.0, backward_pos.1);
let (bitmask_data, albedo_data) = Self::cull_interior_voxels(&block); let left_block = world.get_block(left_pos.0, left_pos.1);
let right_block = world.get_block(right_pos.0, right_pos.1);
let up_block = world.get_block(up_pos.0, up_pos.1);
let down_block = world.get_block(down_pos.0, down_pos.1);
let (bitmask_data, albedo_data) = Self::cull_interior_voxels(
&center_block,
&forward_block,
&backward_block,
&left_block,
&right_block,
&up_block,
&down_block,
);
// If there's no voxel colour data post-culling it means the brickmap is // If there's no voxel colour data post-culling it means the brickmap is
// empty. We don't need to upload it, just mark the relevant brickgrid entry. // empty. We don't need to upload it, just mark the relevant brickgrid entry.
@ -399,9 +417,23 @@ impl BrickmapManager {
} }
} }
fn cull_interior_voxels(block: &[super::world::Voxel]) -> ([u32; 16], Vec<u32>) { // TODO: Account for neighbours in other blocks
// - We should operate on a halo block
// - The world should be responsible for providing a halo perhaps
// - Or rather, perhaps we should just be able to request a range of voxels from the world
// and it will just work out which "blocks" it needs to give us them
fn cull_interior_voxels(
center_block: &[super::world::Voxel],
forward_block: &[super::world::Voxel],
backward_block: &[super::world::Voxel],
left_block: &[super::world::Voxel],
right_block: &[super::world::Voxel],
up_block: &[super::world::Voxel],
down_block: &[super::world::Voxel],
) -> ([u32; 16], Vec<u32>) {
let mut bitmask_data = [0xFFFFFFFF_u32; 16]; let mut bitmask_data = [0xFFFFFFFF_u32; 16];
let mut albedo_data = Vec::<u32>::new(); let mut albedo_data = Vec::<u32>::new();
let mut neighbours = [false; 6];
for z in 0..8 { for z in 0..8 {
// Each z level contains two bitmask segments of voxels // Each z level contains two bitmask segments of voxels
let mut entry = 0u64; let mut entry = 0u64;
@ -411,25 +443,49 @@ impl BrickmapManager {
let idx = x + y * 8 + z * 8 * 8; let idx = x + y * 8 + z * 8 * 8;
let empty_voxel = super::world::Voxel::Empty; let empty_voxel = super::world::Voxel::Empty;
match block[idx] { match center_block[idx] {
super::world::Voxel::Empty => continue, super::world::Voxel::Empty => continue,
super::world::Voxel::Color(r, g, b) => { super::world::Voxel::Color(r, g, b) => {
// A voxel is on the surface if at least one of it's // A voxel is on the surface if at least one of it's
// cardinal neighbours is non-solid. Also for simplicity // cardinal neighbours is non-solid.
// if it's on the edge of the chunk neighbours[0] = if x == 7 {
// TODO: Account for neighbours in other blocks forward_block[idx - 7] == empty_voxel
let surface_voxel =
if x == 0 || x == 7 || y == 0 || y == 7 || z == 0 || z == 7 {
true
} else { } else {
center_block[idx + 1] == empty_voxel center_block[idx + 1] == empty_voxel
|| center_block[idx - 1] == empty_voxel
|| center_block[idx + 8] == empty_voxel
|| center_block[idx - 8] == empty_voxel
|| center_block[idx + 64] == empty_voxel
|| center_block[idx - 64] == empty_voxel
}; };
neighbours[1] = if x == 0 {
backward_block[idx + 7] == empty_voxel
} else {
center_block[idx - 1] == empty_voxel
};
neighbours[2] = if z == 7 {
right_block[idx - 448] == empty_voxel
} else {
center_block[idx + 64] == empty_voxel
};
neighbours[3] = if z == 0 {
left_block[idx + 448] == empty_voxel
} else {
center_block[idx - 64] == empty_voxel
};
neighbours[4] = if y == 7 {
up_block[idx - 56] == empty_voxel
} else {
center_block[idx + 8] == empty_voxel
};
neighbours[5] = if y == 0 {
down_block[idx + 56] == empty_voxel
} else {
center_block[idx - 8] == empty_voxel
};
let surface_voxel = neighbours.iter().any(|v| *v);
// Set the appropriate bit in the z entry and add the // Set the appropriate bit in the z entry and add the
// shading data // shading data
if surface_voxel { if surface_voxel {