From 6be2dd80547bd483bb9ac9acbd311baea6c4f7d0 Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Mon, 24 Apr 2023 17:17:56 +0100 Subject: [PATCH] Begin using basic brickmap. Doesn't include shading table --- assets/shaders/voxel_volume.wgsl | 45 +++++++++++++------------ src/core/camera.rs | 1 + src/voxel.rs | 1 + src/voxel/brickmap.rs | 56 ++++++++++++++++++++++++++++++++ src/voxel/voxel_renderer.rs | 55 +++++++++++++------------------ 5 files changed, 106 insertions(+), 52 deletions(-) create mode 100644 src/voxel/brickmap.rs diff --git a/assets/shaders/voxel_volume.wgsl b/assets/shaders/voxel_volume.wgsl index 04433a9..3c29155 100644 --- a/assets/shaders/voxel_volume.wgsl +++ b/assets/shaders/voxel_volume.wgsl @@ -1,7 +1,12 @@ @group(0) @binding(0) var output: texture_storage_2d; -@group(0) @binding(1) var camera: Camera; -@group(1) @binding(0) var voxels_t: texture_3d; -@group(1) @binding(1) var voxels_s: sampler; +@group(0) @binding(1) var brickmap: Brickmap; +@group(0) @binding(2) var camera: Camera; + +struct Brickmap { + bitmask: array, + shading_table_offset: u32, + lod_color: u32, +} struct Camera { projection: mat4x4, @@ -24,7 +29,7 @@ struct AabbHitInfo { fn ray_intersect_aabb(ray_pos: vec3, ray_dir: vec3) -> AabbHitInfo { let ray_dir_inv = 1.0 / ray_dir; let t1 = (vec3(0.0) - ray_pos) * ray_dir_inv; - let t2 = (vec3(textureDimensions(voxels_t)) - ray_pos) * ray_dir_inv; + let t2 = (vec3(8.0) - 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)); @@ -33,13 +38,13 @@ fn ray_intersect_aabb(ray_pos: vec3, ray_dir: vec3) -> AabbHitInfo { } fn point_inside_aabb(p: vec3) -> bool { - let clamped = clamp(p, vec3(0), textureDimensions(voxels_t) - vec3(1)); + let clamped = clamp(p, vec3(0), vec3(8) - vec3(1)); return clamped.x == p.x && clamped.y == p.y && clamped.z == p.z; } fn voxel_hit(p: vec3) -> bool { - let v = textureLoad(voxels_t, p, 0); - return length(v) != 0.0; + let local_index = u32(p.x + p.y * 8 + p.z * 64); + return (brickmap.bitmask[local_index / 32u] >> (local_index % 32u) & 1u) != 0u; } fn cast_ray(orig_ray_pos: vec3, ray_dir: vec3) -> HitInfo { @@ -125,19 +130,19 @@ fn compute(@builtin(global_invocation_id) global_id: vec3) { var hit_info = cast_ray(ray_pos, ray_dir); var color = vec4(0.0, 0.0, 0.0, 1.0); if (hit_info.hit){ - // if (hit_info.mask.x) { - // color.x = 1.0; - // } - // else if (hit_info.mask.y) { - // color.y = 1.0; - // } - // else if (hit_info.mask.z) { - // color.z = 1.0; - // } - // else { - // color = vec4(1.0); - // } - color = textureLoad(voxels_t, hit_info.hit_pos, 0); + if (hit_info.mask.x) { + color.x = 1.0; + } + else if (hit_info.mask.y) { + color.y = 1.0; + } + else if (hit_info.mask.z) { + color.z = 1.0; + } + else { + color = vec4(1.0); + } + // color = textureLoad(voxels_t, hit_info.hit_pos, 0); } textureStore(output, img_coord, color); diff --git a/src/core/camera.rs b/src/core/camera.rs index 852fbfd..716167c 100644 --- a/src/core/camera.rs +++ b/src/core/camera.rs @@ -4,6 +4,7 @@ use winit::event::{ElementState, KeyboardInput, VirtualKeyCode, WindowEvent}; use crate::render::Context; +// TODO: Implement Default rather than using new() #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct CameraUniform { diff --git a/src/voxel.rs b/src/voxel.rs index c4e5799..f861cef 100644 --- a/src/voxel.rs +++ b/src/voxel.rs @@ -1,3 +1,4 @@ +pub mod brickmap; mod voxel_renderer; pub use voxel_renderer::*; diff --git a/src/voxel/brickmap.rs b/src/voxel/brickmap.rs new file mode 100644 index 0000000..122166e --- /dev/null +++ b/src/voxel/brickmap.rs @@ -0,0 +1,56 @@ +use wgpu::util::DeviceExt; + +use crate::render; + +#[repr(C)] +#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct BrickmapUniform { + pub bitmask: [u32; 16], + pub shading_table_offset: u32, + pub lod_color: u32, +} + +impl BrickmapUniform { + pub fn new() -> Self { + Self { + bitmask: [0; 16], + shading_table_offset: 0, + lod_color: 0, + } + } +} + +#[derive(Debug)] +pub struct BrickmapManager { + uniform: BrickmapUniform, + 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, + }); + + Self { uniform, buffer } + } + + pub fn set_data(&mut self, data: &[u32; 16]) { + self.uniform.bitmask = *data; + } + + pub fn update_buffer(&self, context: &render::Context) { + context + .queue + .write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[self.uniform])); + } + + pub fn get_buffer(&self) -> &wgpu::Buffer { + &self.buffer + } +} diff --git a/src/voxel/voxel_renderer.rs b/src/voxel/voxel_renderer.rs index e563290..b8c10a0 100644 --- a/src/voxel/voxel_renderer.rs +++ b/src/voxel/voxel_renderer.rs @@ -7,7 +7,7 @@ pub struct VoxelRenderer { clear_color: wgpu::Color, render_texture: render::Texture, render_pipeline: wgpu::RenderPipeline, - voxel_texture: render::Texture, + brickmap_manager: super::brickmap::BrickmapManager, compute_pipeline: wgpu::ComputePipeline, compute_bind_group: wgpu::BindGroup, } @@ -59,40 +59,25 @@ impl VoxelRenderer { multiview: None, }); - log::info!("Creating voxel volume texture..."); - let voxel_texture = render::TextureBuilder::new() - .with_size(8, 8, 8) - .with_dimension(wgpu::TextureDimension::D3) - .with_format(wgpu::TextureFormat::Rgba8Unorm) - .with_usage( - wgpu::TextureUsages::TEXTURE_BINDING - | wgpu::TextureUsages::COPY_DST - | wgpu::TextureUsages::STORAGE_BINDING, - ) - .with_shader_visibility(wgpu::ShaderStages::COMPUTE) - .build(&context); - - let data_len = 8 * 8 * 8 * 4; - let mut data: Vec = Vec::with_capacity(data_len.try_into().unwrap()); + log::info!("Creating brickmap manager..."); + let mut brickmap_manager = super::brickmap::BrickmapManager::new(context); + let mut data = [0xFFFFFFFF as u32; 16]; 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) { - data.push(((x + 1) * 32 - 1) as u8); - data.push(((y + 1) * 32 - 1) as u8); - data.push(((z + 1) * 32 - 1) as u8); - data.push(255u8); - } else { - data.push(0u8); - data.push(0u8); - data.push(0u8); - data.push(0u8); + entry += 1 << idx; } } } + data[2 * z] = (entry & 0xFFFFFFFF).try_into().unwrap(); + data[2 * z + 1] = ((entry >> 32) & 0xFFFFFFFF).try_into().unwrap(); } - voxel_texture.update(&context, &data); + brickmap_manager.set_data(&data); + brickmap_manager.update_buffer(context); log::info!("Creating compute pipeline..."); let cs_descriptor = wgpu::include_wgsl!("../../assets/shaders/voxel_volume.wgsl"); @@ -107,6 +92,15 @@ impl VoxelRenderer { }, None, ) + .with_entry( + wgpu::ShaderStages::COMPUTE, + wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + None, + ) .with_entry( wgpu::ShaderStages::COMPUTE, wgpu::BindingType::Buffer { @@ -120,6 +114,7 @@ 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(camera_controller.get_buffer().as_entire_binding()) .build(context); let compute_pipeline = @@ -130,10 +125,7 @@ impl VoxelRenderer { layout: Some(&context.device.create_pipeline_layout( &wgpu::PipelineLayoutDescriptor { label: Some("compute"), - bind_group_layouts: &[ - &compute_layout, - &voxel_texture.bind_group_layout, - ], + bind_group_layouts: &[&compute_layout], push_constant_ranges: &[], }, )), @@ -145,7 +137,7 @@ impl VoxelRenderer { clear_color: wgpu::Color::BLACK, render_texture, render_pipeline, - voxel_texture, + brickmap_manager, compute_pipeline, compute_bind_group, } @@ -167,7 +159,6 @@ impl render::Renderer for VoxelRenderer { let mut compute_pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default()); compute_pass.set_pipeline(&self.compute_pipeline); compute_pass.set_bind_group(0, &self.compute_bind_group, &[]); - compute_pass.set_bind_group(1, &self.voxel_texture.bind_group, &[]); compute_pass.dispatch_workgroups(size.width / 8, size.height / 8, 1); drop(compute_pass);