Add initial multi-brickmap support

This commit is contained in:
Jarrod Doyle 2023-04-25 12:23:55 +01:00
parent 1d126eba10
commit 1823d8b52c
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
3 changed files with 136 additions and 64 deletions

View File

@ -1,7 +1,8 @@
@group(0) @binding(0) var output: texture_storage_2d<rgba8unorm, write>;
@group(0) @binding(1) var<storage, read> brickmap: Brickmap;
@group(0) @binding(2) var<storage, read> shading_table: array<ShadingElement>;
@group(0) @binding(3) var<uniform> camera: Camera;
@group(0) @binding(1) var<uniform> world_state: WorldState;
@group(0) @binding(2) var<storage, read> brickmap_cache: array<Brickmap>;
@group(0) @binding(3) var<storage, read> shading_table: array<ShadingElement>;
@group(0) @binding(4) var<uniform> camera: Camera;
struct ShadingElement {
albedo: u32,
@ -20,6 +21,11 @@ struct Camera {
_pad: f32,
};
struct WorldState {
brickmap_cache_dims: vec3<u32>,
_pad: u32,
};
struct HitInfo {
hit: bool,
hit_pos: vec3<i32>,
@ -32,21 +38,37 @@ struct AabbHitInfo {
};
fn get_shading_offset(p: vec3<i32>) -> u32 {
let local_index = u32(p.x + p.y * 8 + p.z * 64);
// return 0u;
// What brickmap are we in?
let brickmap_index = (p.x / 8) + (p.y / 8) * 32 + (p.z / 8) * 1024;
let local_index = u32((p.x % 8) + (p.y % 8) * 8 + (p.z % 8) * 64);
let brickmap = &brickmap_cache[brickmap_index];
let bitmask_index = local_index / 32u;
var map_voxel_idx = 0u;
for (var i: i32 = 0; i < i32(bitmask_index); i++) {
map_voxel_idx += countOneBits(brickmap.bitmask[i]);
map_voxel_idx += countOneBits((*brickmap).bitmask[i]);
}
let extracted_bits = extractBits(brickmap.bitmask[bitmask_index], 0u, (local_index % 32u));
let extracted_bits = extractBits((*brickmap).bitmask[bitmask_index], 0u, (local_index % 32u));
map_voxel_idx += countOneBits(extracted_bits);
return brickmap.shading_table_offset + map_voxel_idx;
return (*brickmap).shading_table_offset + map_voxel_idx;
// let local_index = u32(p.x + p.y * 8 + p.z * 64);
// let bitmask_index = local_index / 32u;
// var map_voxel_idx = 0u;
// for (var i: i32 = 0; i < i32(bitmask_index); i++) {
// map_voxel_idx += countOneBits(brickmap.bitmask[i]);
// }
// let extracted_bits = extractBits(brickmap.bitmask[bitmask_index], 0u, (local_index % 32u));
// map_voxel_idx += countOneBits(extracted_bits);
// return brickmap.shading_table_offset + map_voxel_idx;
}
fn ray_intersect_aabb(ray_pos: vec3<f32>, ray_dir: vec3<f32>) -> AabbHitInfo {
let ray_dir_inv = 1.0 / ray_dir;
let t1 = (vec3<f32>(0.0) - ray_pos) * ray_dir_inv;
let t2 = (vec3<f32>(8.0) - ray_pos) * ray_dir_inv;
let t2 = ((vec3<f32>(8.0) * vec3<f32>(world_state.brickmap_cache_dims)) - ray_pos) * ray_dir_inv;
let t_min = min(t1, t2);
let t_max = max(t1, t2);
let tmin = max(max(t_min.x, 0.0), max(t_min.y, t_min.z));
@ -55,13 +77,15 @@ fn ray_intersect_aabb(ray_pos: vec3<f32>, ray_dir: vec3<f32>) -> AabbHitInfo {
}
fn point_inside_aabb(p: vec3<i32>) -> bool {
let clamped = clamp(p, vec3<i32>(0), vec3<i32>(8) - vec3<i32>(1));
let max = vec3<i32>(world_state.brickmap_cache_dims) * 8;
let clamped = clamp(p, vec3<i32>(0), max - vec3<i32>(1));
return clamped.x == p.x && clamped.y == p.y && clamped.z == p.z;
}
fn voxel_hit(p: vec3<i32>) -> bool {
let local_index = u32(p.x + p.y * 8 + p.z * 64);
return (brickmap.bitmask[local_index / 32u] >> (local_index % 32u) & 1u) != 0u;
let brickmap_index = (p.x / 8) + (p.y / 8) * 32 + (p.z / 8) * 1024;
let local_index = u32((p.x % 8) + (p.y % 8) * 8 + (p.z % 8) * 64);
return (brickmap_cache[brickmap_index].bitmask[local_index / 32u] >> (local_index % 32u) & 1u) != 0u;
}
fn cast_ray(orig_ray_pos: vec3<f32>, ray_dir: vec3<f32>) -> HitInfo {
@ -84,7 +108,7 @@ fn cast_ray(orig_ray_pos: vec3<f32>, ray_dir: vec3<f32>) -> HitInfo {
var side_dist = (sign(ray_dir) * (vec3<f32>(map_pos) - ray_pos) + (sign(ray_dir) * 0.5) + 0.5) * delta_dist;
// TODO: don't hardcode max ray depth
for (var i: i32 = 0; i < 64; i++) {
for (var i: i32 = 0; i < 2048; i++) {
if (side_dist.x < side_dist.y) {
if (side_dist.x < side_dist.z) {
side_dist.x += delta_dist.x;

View File

@ -1,18 +1,16 @@
use std::mem::size_of;
use wgpu::util::DeviceExt;
use crate::render;
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct BrickmapUniform {
#[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Brickmap {
pub bitmask: [u32; 16],
pub shading_table_offset: u32,
pub lod_color: u32,
}
impl BrickmapUniform {
impl Brickmap {
pub fn new() -> Self {
Self {
bitmask: [0; 16],
@ -22,53 +20,84 @@ impl BrickmapUniform {
}
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct WorldState {
brickmap_cache_dims: [u32; 3],
_pad: u32,
}
#[derive(Debug)]
pub struct BrickmapManager {
uniform: BrickmapUniform,
buffer: wgpu::Buffer,
state_uniform: WorldState,
state_buffer: wgpu::Buffer,
brickmap_cache: Vec<Brickmap>,
brickmap_buffer: wgpu::Buffer,
shading_table: Vec<u32>,
shading_table_buffer: wgpu::Buffer,
}
impl BrickmapManager {
pub fn new(context: &render::Context) -> Self {
let uniform = BrickmapUniform::new();
let buffer = context
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[uniform]),
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
});
let mut state_uniform = WorldState::default();
state_uniform.brickmap_cache_dims = [32, 32, 32];
let shading_table_buffer =
context
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: &[0; 25000000],
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
});
let mut brickmap_cache = Vec::<Brickmap>::with_capacity(32768);
brickmap_cache.resize(32768, Brickmap::default());
let shading_table = Vec::<u32>::new();
let device = &context.device;
let state_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[state_uniform]),
usage: wgpu::BufferUsages::UNIFORM,
});
let brickmap_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&brickmap_cache),
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
});
let shading_table_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[0u32; 25000000]),
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
});
let mut shading_table = Vec::<u32>::with_capacity(25000000);
shading_table.resize(shading_table.capacity(), 0);
Self {
uniform,
buffer,
state_uniform,
state_buffer,
brickmap_cache,
brickmap_buffer,
shading_table,
shading_table_buffer,
}
}
// TODO: Ideally this should take a generic voxel format and do the data mapping here
pub fn set_data(&mut self, data: &[u32; 16], colours: &[u32]) {
self.uniform.bitmask = *data;
self.shading_table = colours.to_vec();
pub fn set_data(&mut self, chunk_pos: glam::UVec3, data: &[u32; 16], colours: &[u32]) {
let idx: usize = (chunk_pos.x + chunk_pos.y * 32 + chunk_pos.z * 1024)
.try_into()
.unwrap();
let shading_idx = idx * 512;
self.brickmap_cache[idx].bitmask = *data;
self.brickmap_cache[idx].shading_table_offset = shading_idx as u32;
self.shading_table.splice(
shading_idx..(shading_idx + colours.len()),
colours.to_owned(),
);
}
pub fn update_buffer(&self, context: &render::Context) {
let queue = &context.queue;
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[self.uniform]));
queue.write_buffer(
&self.brickmap_buffer,
0,
bytemuck::cast_slice(&self.brickmap_cache),
);
queue.write_buffer(
&self.shading_table_buffer,
0,
@ -76,8 +105,12 @@ impl BrickmapManager {
);
}
pub fn get_buffer(&self) -> &wgpu::Buffer {
&self.buffer
pub fn get_worldstate_buffer(&self) -> &wgpu::Buffer {
&self.state_buffer
}
pub fn get_brickmap_buffer(&self) -> &wgpu::Buffer {
&self.brickmap_buffer
}
pub fn get_shading_buffer(&self) -> &wgpu::Buffer {

View File

@ -61,29 +61,34 @@ impl VoxelRenderer {
log::info!("Creating brickmap manager...");
let mut brickmap_manager = super::brickmap::BrickmapManager::new(context);
let mut bitmask_data = [0xFFFFFFFF as u32; 16];
let mut albedo_data = Vec::<u32>::new();
for z in 0..8 {
let mut entry = 0u64;
for y in 0..8 {
for x in 0..8 {
let idx = x + y * 8;
let pos = glam::vec3(x as f32, y as f32, z as f32) - glam::vec3(3.5, 3.5, 3.5);
if pos.length_squared() <= (u32::pow(4, 2) as f32) {
entry += 1 << idx;
let mut albedo = 0u32;
albedo += ((x + 1) * 32 - 1) << 24;
albedo += ((y + 1) * 32 - 1) << 16;
albedo += ((z + 1) * 32 - 1) << 8;
albedo += 255;
albedo_data.push(albedo);
let sphere_center = glam::vec3(3.5, 3.5, 3.5);
let sphere_r2 = u32::pow(4, 2) as f32;
for chunk_idx in 0..32768 {
let chunk_pos = glam::uvec3(chunk_idx % 32, (chunk_idx / 32) % 32, chunk_idx / 1024);
let mut bitmask_data = [0xFFFFFFFF as u32; 16];
let mut albedo_data = Vec::<u32>::new();
for z in 0..8 {
let mut entry = 0u64;
for y in 0..8 {
for x in 0..8 {
let idx = x + y * 8;
let pos = glam::vec3(x as f32, y as f32, z as f32);
if (pos - sphere_center).length_squared() <= sphere_r2 {
entry += 1 << idx;
let mut albedo = 0u32;
albedo += ((chunk_pos.x + 1) * 8 - 1) << 24;
albedo += ((chunk_pos.y + 1) * 8 - 1) << 16;
albedo += ((chunk_pos.z + 1) * 8 - 1) << 8;
albedo += 255;
albedo_data.push(albedo);
}
}
}
bitmask_data[2 * z as usize] = (entry & 0xFFFFFFFF).try_into().unwrap();
bitmask_data[2 * z as usize + 1] = ((entry >> 32) & 0xFFFFFFFF).try_into().unwrap();
}
bitmask_data[2 * z as usize] = (entry & 0xFFFFFFFF).try_into().unwrap();
bitmask_data[2 * z as usize + 1] = ((entry >> 32) & 0xFFFFFFFF).try_into().unwrap();
brickmap_manager.set_data(chunk_pos, &bitmask_data, &albedo_data);
}
brickmap_manager.set_data(&bitmask_data, &albedo_data);
brickmap_manager.update_buffer(context);
log::info!("Creating compute pipeline...");
@ -99,6 +104,15 @@ impl VoxelRenderer {
},
None,
)
.with_entry(
wgpu::ShaderStages::COMPUTE,
wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
None,
)
.with_entry(
wgpu::ShaderStages::COMPUTE,
wgpu::BindingType::Buffer {
@ -130,7 +144,8 @@ impl VoxelRenderer {
let compute_bind_group = render::BindGroupBuilder::new()
.with_layout(&compute_layout)
.with_entry(wgpu::BindingResource::TextureView(&render_texture.view))
.with_entry(brickmap_manager.get_buffer().as_entire_binding())
.with_entry(brickmap_manager.get_worldstate_buffer().as_entire_binding())
.with_entry(brickmap_manager.get_brickmap_buffer().as_entire_binding())
.with_entry(brickmap_manager.get_shading_buffer().as_entire_binding())
.with_entry(camera_controller.get_buffer().as_entire_binding())
.build(context);