diff --git a/build.rs b/build.rs index 0a3c430..d21056e 100644 --- a/build.rs +++ b/build.rs @@ -6,21 +6,15 @@ fn main() { println!("cargo::rerun-if-changed=shaders/cube.frag"); println!("cargo::rerun-if-changed=shaders/cube.geom"); println!("cargo::rerun-if-changed=shaders/cube.vert"); - println!("cargo::rerun-if-changed=shaders/compiled/geo_cube.spv"); - println!("cargo::rerun-if-changed=shaders/compiled/frag_cube.spv"); - println!("cargo::rerun-if-changed=shaders/compiled/vert_cube.spv"); println!("cargo::rerun-if-changed=shaders/cuboid.frag"); println!("cargo::rerun-if-changed=shaders/cuboid.geom"); println!("cargo::rerun-if-changed=shaders/cuboid.vert"); - println!("cargo::rerun-if-changed=shaders/compiled/geo_cuboid.spv"); - println!("cargo::rerun-if-changed=shaders/compiled/frag_cuboid.spv"); - println!("cargo::rerun-if-changed=shaders/compiled/vert_cuboid.spv"); println!("cargo::rerun-if-changed=shaders/rt_quad.vert"); - println!("cargo::rerun-if-changed=shaders/compiled/vert_rt_quad.spv"); println!("cargo::rerun-if-changed=shaders/rt_quad.frag"); - println!("cargo::rerun-if-changed=shaders/compiled/frag_rt_quad.spv"); + + println!("cargo::rerun-if-changed=shaders/rt_compute.comp"); #[allow(unused_must_use)] std::fs::remove_file("shaders/compiled/geo_cube.spv"); @@ -38,6 +32,8 @@ fn main() { std::fs::remove_file("shaders/compiled/vert_rt_quad.spv"); #[warn(unused_must_use)] std::fs::remove_file("shaders/compiled/frag_rt_quad.spv"); + #[warn(unused_must_use)] + std::fs::remove_file("shaders/compiled/rt_compute.spv"); if std::env::consts::OS == "windows" { let mut command = Command::new("./shaders/compile.bat"); diff --git a/shaders/compile.bat b/shaders/compile.bat index 9090ab5..400c217 100644 --- a/shaders/compile.bat +++ b/shaders/compile.bat @@ -7,4 +7,6 @@ C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cuboid.frag -o shaders/compiled/fra C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/cuboid.geom -o shaders/compiled/geo_cuboid.spv C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/rt_quad.vert -o shaders/compiled/vert_rt_quad.spv -C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/rt_quad.frag -o shaders/compiled/frag_rt_quad.spv \ No newline at end of file +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/rt_quad.frag -o shaders/compiled/frag_rt_quad.spv + +C:/VulkanSDK/1.3.280.0/Bin/glslc.exe shaders/rt_compute.comp -o shaders/compiled/rt_compute.spv \ No newline at end of file diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv index ae0bec7..5523307 100644 Binary files a/shaders/compiled/frag_rt_quad.spv and b/shaders/compiled/frag_rt_quad.spv differ diff --git a/shaders/compiled/rt_compute.spv b/shaders/compiled/rt_compute.spv new file mode 100644 index 0000000..f7b7067 Binary files /dev/null and b/shaders/compiled/rt_compute.spv differ diff --git a/shaders/rt_compute.comp b/shaders/rt_compute.comp new file mode 100644 index 0000000..2b33f9c --- /dev/null +++ b/shaders/rt_compute.comp @@ -0,0 +1,27 @@ +#version 450 + + +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 geom_rot; + mat4 view; + mat4 proj; + vec3 camera_pos; + bool[16] use_geom_shader; +} ubo; + +layout(binding = 3) readonly buffer SceneInfoBuffer { + uint gridsIn[]; +}; + +layout(binding = 4) buffer SceneInfoBuffer2 { + uint volumes[]; +}; + +layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in; + +void main() { + uint index = gl_GlobalInvocationID.x; + + volumes[index] = gridsIn[index]; +} \ No newline at end of file diff --git a/shaders/rt_quad.frag b/shaders/rt_quad.frag index 17c3861..378ccc8 100644 --- a/shaders/rt_quad.frag +++ b/shaders/rt_quad.frag @@ -24,9 +24,13 @@ layout(binding = 0) uniform UniformBufferObject { // 3 - diffuse raster size (float, needs to be decoded) // 4 - max recursive rays // 5 - diffuse rays per hit -layout(binding = 2) buffer SceneInfoBuffer{ +layout(binding = 2) readonly buffer SceneInfoBuffer{ uint infos[]; } scene_info; + +layout(binding = 4) buffer SceneInfoBuffer2 { + uint infos[]; +} scene_info2; uint max_num_lights = scene_info.infos[0]; uint max_iterations_per_light = scene_info.infos[1]; // diffuse raytracing using a quadratic raster of rays diff --git a/src/app_data.rs b/src/app_data.rs index f7e5b20..4c47c30 100644 --- a/src/app_data.rs +++ b/src/app_data.rs @@ -22,6 +22,9 @@ pub struct AppData { pub pipeline_cube: vk::Pipeline, pub pipeline_cuboid: vk::Pipeline, pub pipeline_quad: vk::Pipeline, + + pub pipeline_compute: vk::Pipeline, + pub framebuffers: Vec<vk::Framebuffer>, pub command_pool: vk::CommandPool, pub command_buffers: Vec<vk::CommandBuffer>, @@ -35,8 +38,14 @@ pub struct AppData { pub uniform_buffers: Vec<vk::Buffer>, pub uniform_buffers_memory: Vec<vk::DeviceMemory>, - pub storage_buffers: Vec<vk::Buffer>, - pub storage_buffers_memory: Vec<vk::DeviceMemory>, + pub render_storage_buffers: Vec<vk::Buffer>, + pub render_storage_buffers_memory: Vec<vk::DeviceMemory>, + + pub compute_in_storage_buffers: Vec<vk::Buffer>, + pub compute_in_storage_buffers_memory: Vec<vk::DeviceMemory>, + + pub compute_out_storage_buffers: Vec<vk::Buffer>, + pub compute_out_storage_buffers_memory: Vec<vk::DeviceMemory>, pub descriptor_pool: vk::DescriptorPool, pub descriptor_sets: Vec<vk::DescriptorSet>, @@ -60,6 +69,8 @@ pub struct AppData { pub topology: vk::PrimitiveTopology, pub scene_rt_memory_size: u64, + pub scene_rt_volumetric_size: u64, + pub compute_task_one_size: usize, // values passed to shader pub num_lights_per_volume: u32, pub min_light_weight: f32, diff --git a/src/buffer.rs b/src/buffer.rs index 13b0159..ae8d656 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -200,13 +200,25 @@ pub unsafe fn create_descriptor_set_layout( .descriptor_count(1) .stage_flags(vk::ShaderStageFlags::FRAGMENT); - let storage_binding = vk::DescriptorSetLayoutBinding::builder() + let storage_binding_render = vk::DescriptorSetLayoutBinding::builder() .binding(2) .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) .descriptor_count(1) .stage_flags(vk::ShaderStageFlags::FRAGMENT); + + let storage_binding_compute_in = vk::DescriptorSetLayoutBinding::builder() + .binding(3) + .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::COMPUTE); - let bindings = &[ubo_binding, sampler_binding, storage_binding]; + let storage_binding_compute_out = vk::DescriptorSetLayoutBinding::builder() + .binding(4) + .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::FRAGMENT | vk::ShaderStageFlags::COMPUTE); + + let bindings = &[ubo_binding, sampler_binding, storage_binding_render, storage_binding_compute_in, storage_binding_compute_out]; let info = vk::DescriptorSetLayoutCreateInfo::builder() .bindings(bindings); @@ -245,8 +257,13 @@ pub unsafe fn create_storage_buffers( device: &Device, data: &mut app_data::AppData, ) -> Result<()> { - data.storage_buffers.clear(); - data.storage_buffers_memory.clear(); + data.render_storage_buffers.clear(); + data.render_storage_buffers_memory.clear(); + + data.compute_in_storage_buffers.clear(); + data.compute_in_storage_buffers_memory.clear(); + data.compute_out_storage_buffers.clear(); + data.compute_out_storage_buffers_memory.clear(); for _ in 0..data.swapchain_images.len() { let (storage_buffer, storage_buffer_memory) = create_buffer( @@ -257,21 +274,45 @@ pub unsafe fn create_storage_buffers( vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::STORAGE_BUFFER, vk::MemoryPropertyFlags::DEVICE_LOCAL, )?; + data.render_storage_buffers.push(storage_buffer); + data.render_storage_buffers_memory.push(storage_buffer_memory); - data.storage_buffers.push(storage_buffer); - data.storage_buffers_memory.push(storage_buffer_memory); + let (storage_buffer, storage_buffer_memory) = create_buffer( + instance, + device, + data, + data.scene_rt_volumetric_size.max(1), + vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::STORAGE_BUFFER, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.compute_in_storage_buffers.push(storage_buffer); + data.compute_in_storage_buffers_memory.push(storage_buffer_memory); + + let (storage_buffer, storage_buffer_memory) = create_buffer( + instance, + device, + data, + data.scene_rt_memory_size.max(1), + vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::STORAGE_BUFFER, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.compute_out_storage_buffers.push(storage_buffer); + data.compute_out_storage_buffers_memory.push(storage_buffer_memory); } Ok(()) } -pub unsafe fn update_storage_buffer( +pub unsafe fn update_render_storage_buffer( instance: &Instance, device: &Device, data: &app_data::AppData, image_index: usize, scene_handler: &scene::Scene, ) -> Result<()> { + // rt scene buffer let (staging_buffer, staging_buffer_memory) = create_buffer( instance, device, @@ -292,11 +333,38 @@ pub unsafe fn update_storage_buffer( device.unmap_memory(staging_buffer_memory); - copy_buffer(device, data, staging_buffer, data.storage_buffers[image_index], data.scene_rt_memory_size)?; + copy_buffer(device, data, staging_buffer, data.render_storage_buffers[image_index], data.scene_rt_memory_size)?; device.destroy_buffer(staging_buffer, None); device.free_memory(staging_buffer_memory, None); + // rt compute buffer + if scene_handler.volumetrics.len() > 0 { + let (staging_buffer, staging_buffer_memory) = create_buffer( + instance, + device, + data, + data.scene_rt_volumetric_size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + let memory = device.map_memory( + staging_buffer_memory, + 0, + data.scene_rt_volumetric_size, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(scene_handler.volumetrics_memory.as_ptr(), memory.cast(), scene_handler.volumetrics_memory.len()); + + device.unmap_memory(staging_buffer_memory); + + copy_buffer(device, data, staging_buffer, data.compute_in_storage_buffers[image_index], data.scene_rt_volumetric_size)?; + + device.destroy_buffer(staging_buffer, None); + device.free_memory(staging_buffer_memory, None); + } Ok(()) } @@ -309,11 +377,19 @@ pub unsafe fn create_descriptor_pool(device: &Device, data: &mut app_data::AppDa .type_(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) .descriptor_count(data.swapchain_images.len() as u32); - let storage_size = vk::DescriptorPoolSize::builder() + let render_storage_size = vk::DescriptorPoolSize::builder() + .type_(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(data.swapchain_images.len() as u32); + + let compute_in_storage_size = vk::DescriptorPoolSize::builder() + .type_(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(data.swapchain_images.len() as u32); + + let compute_out_storage_size = vk::DescriptorPoolSize::builder() .type_(vk::DescriptorType::STORAGE_BUFFER) .descriptor_count(data.swapchain_images.len() as u32); - let pool_sizes = &[ubo_size, sampler_size, storage_size]; + let pool_sizes = &[ubo_size, sampler_size, render_storage_size, compute_in_storage_size, compute_out_storage_size]; let info = vk::DescriptorPoolCreateInfo::builder() .pool_sizes(pool_sizes) .max_sets(data.swapchain_images.len() as u32); @@ -357,20 +433,48 @@ pub unsafe fn create_descriptor_sets(device: &Device, data: &mut app_data::AppDa .image_info(image_info); let info = vk::DescriptorBufferInfo::builder() - .buffer(data.storage_buffers[i]) + .buffer(data.render_storage_buffers[i]) .offset(0) .range(data.scene_rt_memory_size); let storage_info = &[info]; - let storage_write = vk::WriteDescriptorSet::builder() + let storage_write_render = vk::WriteDescriptorSet::builder() .dst_set(data.descriptor_sets[i]) .dst_binding(2) .dst_array_element(0) .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) .buffer_info(storage_info); + + let info = vk::DescriptorBufferInfo::builder() + .buffer(data.compute_in_storage_buffers[i]) + .offset(0) + .range(data.scene_rt_volumetric_size.max(1)); + let storage_info = &[info]; + + let storage_write_compute_in = vk::WriteDescriptorSet::builder() + .dst_set(data.descriptor_sets[i]) + .dst_binding(3) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) + .buffer_info(storage_info); + + let info = vk::DescriptorBufferInfo::builder() + .buffer(data.compute_out_storage_buffers[i]) + .offset(0) + .range(data.scene_rt_memory_size); + let storage_info = &[info]; + + let storage_write_compute_out = vk::WriteDescriptorSet::builder() + .dst_set(data.descriptor_sets[i]) + .dst_binding(4) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) + .buffer_info(storage_info); + + device.update_descriptor_sets( - &[ubo_write, sampler_write, storage_write], + &[ubo_write, sampler_write, storage_write_render, storage_write_compute_in, storage_write_compute_out], &[] as &[vk::CopyDescriptorSet], ); } diff --git a/src/command_buffer.rs b/src/command_buffer.rs index 050e21c..e856f7c 100644 --- a/src/command_buffer.rs +++ b/src/command_buffer.rs @@ -57,6 +57,22 @@ pub unsafe fn create_command_buffers(device: &Device, data: &mut app_data::AppDa }, }; + // define the compute load before going into the render pass + if scene_handler.volumetrics.len() != 0 { + device.cmd_bind_pipeline( + *command_buffer, vk::PipelineBindPoint::COMPUTE, data.pipeline_compute); //todo build own pipeline + + device.cmd_bind_descriptor_sets( + *command_buffer, + vk::PipelineBindPoint::COMPUTE, + data.pipeline_layout, + 0, + &[data.descriptor_sets[i]], + &[]); + + device.cmd_dispatch(*command_buffer, (data.compute_task_one_size as f64 / 256.0).ceil() as u32, 1, 1); + } + // start render pass let clear_values = &[color_clear_value, depth_clear_value]; let info = vk::RenderPassBeginInfo::builder() .render_pass(data.render_pass) diff --git a/src/main.rs b/src/main.rs index eca7b28..4d7c060 100644 --- a/src/main.rs +++ b/src/main.rs @@ -280,14 +280,14 @@ impl App { self.update_uniform_buffer(image_index)?; let time = self.appstart.elapsed().as_secs_f32() / 1.0; - self.scene_handler.point_lights[0].borrow_mut().set_pos(cgmath::vec3((10.0 + 64.0) as f32 + time.sin(), (10.0 + 64.0) as f32 + time.cos(), 11.0)); + self.scene_handler.point_lights[0].borrow_mut().set_pos(cgmath::vec3((10.0 + 64.0) as f32 + time.sin() * 2.0, (10.0 + 64.0) as f32 + time.cos() * 2.0, 11.0)); self.synchronized = 0; if self.synchronized < MAX_FRAMES_IN_FLIGHT { if self.scene_handler.is_dirty() { self.scene_handler.update_memory(&mut self.data, true) } - buffer::update_storage_buffer(&self.instance, &self.device, &self.data, image_index, &self.scene_handler)?; + buffer::update_render_storage_buffer(&self.instance, &self.device, &self.data, image_index, &self.scene_handler)?; self.synchronized += 1 } @@ -404,10 +404,24 @@ impl App { self.data.uniform_buffers_memory .iter() .for_each(|m| self.device.free_memory(*m, None)); - self.data.storage_buffers + self.data.render_storage_buffers .iter() .for_each(|b| self.device.destroy_buffer(*b, None)); - self.data.storage_buffers_memory + self.data.render_storage_buffers_memory + .iter() + .for_each(|m| self.device.free_memory(*m, None)); + + self.data.compute_in_storage_buffers + .iter() + .for_each(|b| self.device.destroy_buffer(*b, None)); + self.data.compute_in_storage_buffers_memory + .iter() + .for_each(|m| self.device.free_memory(*m, None)); + + self.data.compute_out_storage_buffers + .iter() + .for_each(|b| self.device.destroy_buffer(*b, None)); + self.data.compute_out_storage_buffers_memory .iter() .for_each(|m| self.device.free_memory(*m, None)); @@ -418,6 +432,9 @@ impl App { self.device.destroy_pipeline(self.data.pipeline_cube, None); self.device.destroy_pipeline(self.data.pipeline_cuboid, None); self.device.destroy_pipeline(self.data.pipeline_quad, None); + + self.device.destroy_pipeline(self.data.pipeline_compute, None); + self.device.destroy_pipeline_layout(self.data.pipeline_layout, None); self.device.destroy_render_pass(self.data.render_pass, None); self.data.swapchain_image_views @@ -796,6 +813,17 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu let vertex_input_state_quad = vk::PipelineVertexInputStateCreateInfo::builder() .vertex_binding_descriptions(binding_descriptions_quad) .vertex_attribute_descriptions(&attribute_descriptions_quad); + + // set up compute shader + // load the byte data + let compute_bytes = include_bytes!("../shaders/compiled/rt_compute.spv"); + // create the shaders + let compute_shader_module = create_shader_module(device, &compute_bytes[..])?; + //create the shader stage for the compute shader + let compute_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::COMPUTE) + .module(compute_shader_module) + .name(b"main\0"); // define input assembly and object type. This is altered when using geometry shader let mut topology = vk::PrimitiveTopology::TRIANGLE_LIST; @@ -937,10 +965,18 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu // create the pipeline let pipelines = device.create_graphics_pipelines(vk::PipelineCache::null(), &[info_cube, info_cuboid, info_quad], None)?.0; + let info_compute = vk::ComputePipelineCreateInfo::builder() + .stage(compute_stage) + .layout(data.pipeline_layout); + + let compute_pipelines = device.create_compute_pipelines(vk::PipelineCache::null(), &[info_compute], None)?.0; + data.pipeline_cube = pipelines[0]; data.pipeline_cuboid = pipelines[1]; data.pipeline_quad = pipelines[2]; + data.pipeline_compute = compute_pipelines[0]; + device.destroy_shader_module(vert_shader_module_cube, None); device.destroy_shader_module(geo_shader_module_cube, None); device.destroy_shader_module(frag_shader_module_cube, None); @@ -952,6 +988,8 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu device.destroy_shader_module(vert_shader_module_quad, None); device.destroy_shader_module(frag_shader_module_quad, None); + device.destroy_shader_module(compute_shader_module, None); + Ok(()) } diff --git a/src/primitives/quad.rs b/src/primitives/quad.rs index a6926d1..990164c 100644 --- a/src/primitives/quad.rs +++ b/src/primitives/quad.rs @@ -1,5 +1,5 @@ use vulkanalia::prelude::v1_0::*; -use cgmath::{vec3, ElementWise, Vector2}; +use cgmath::{vec3, ElementWise}; use crate::vertex::{self, Facing}; use crate::scene::Scene; use crate::primitives::drawable::Drawable; diff --git a/src/queue_family_indices.rs b/src/queue_family_indices.rs index 2a62bda..9d56a58 100644 --- a/src/queue_family_indices.rs +++ b/src/queue_family_indices.rs @@ -25,7 +25,7 @@ impl QueueFamilyIndices { let graphics = properties .iter() - .position(|p| p.queue_flags.contains(vk::QueueFlags::GRAPHICS)) + .position(|p| p.queue_flags.contains(vk::QueueFlags::GRAPHICS) && p.queue_flags.contains(vk::QueueFlags::COMPUTE)) .map(|i| i as u32); let mut present = None; diff --git a/src/scene/generators.rs b/src/scene/generators.rs index 3527dd0..5395a62 100644 --- a/src/scene/generators.rs +++ b/src/scene/generators.rs @@ -4,6 +4,7 @@ use crate::primitives::cube::Cube; use crate::primitives::rec_cuboid::Cuboid; use crate::primitives::drawable::Drawable; use crate::app_data::AppData; +use super::volumetrics::{ShapeComposition, Sphere}; extern crate rand; use rand::Rng; @@ -117,6 +118,10 @@ pub fn generate_test_scene(scene: &mut Scene, data: &mut AppData) -> Result<(Poi let tree_ref_two = Rc::new(RefCell::new(oct_tree2.clone())); scene.oct_trees = vec![vec![vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_one.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()]], vec![vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_one.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()]]]; + let mut comp = ShapeComposition::new(64); + comp.included_shapes.push(Rc::new(RefCell::new(Sphere::new(Vector3 { x: 5.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 10.0 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, 2.5, Vector3 { x: 255, y: 0, z: 0 }, 64)))); + scene.volumetrics.push(Rc::new(RefCell::new(comp))); + Ok((cgmath::point3(5.0, 5.0, 10.0))) } diff --git a/src/scene/memorizable.rs b/src/scene/memorizable.rs index 2551a58..eac295c 100644 --- a/src/scene/memorizable.rs +++ b/src/scene/memorizable.rs @@ -9,4 +9,8 @@ pub trait Memorizable: core::fmt::Debug { fn insert_into_memory(&mut self, v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32>; fn get_memory_start(&self) -> usize; fn set_memory_start(&mut self, memory_start: usize); +} + +pub trait CompoundMemorizable: Memorizable { + fn get_compound_buffer_mem_size(&self, data: &AppData) -> u32; } \ No newline at end of file diff --git a/src/scene/mod.rs b/src/scene/mod.rs index fc72d62..25f6ce6 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -3,6 +3,7 @@ mod empty_volume; mod light; mod memorizable; pub mod generators; +pub mod volumetrics; use anyhow::Ok; use light::{DirectionalLight, LightSource, PointLight}; @@ -14,7 +15,7 @@ use cgmath::{vec2, vec3, Vector3}; use std::cell::RefCell; use std::rc::Rc; -use crate::scene::memorizable::Memorizable; +use crate::scene::memorizable::{Memorizable, CompoundMemorizable}; use crate::app_data::AppData; use crate::buffer; use crate::primitives::rec_cuboid::Cuboid; @@ -63,6 +64,10 @@ pub struct Scene { pub directional_lights: Vec<Rc<RefCell<DirectionalLight>>>, pub memorizables: Vec<Rc<RefCell<dyn Memorizable>>>, + + pub volumetrics: Vec<Rc<RefCell<volumetrics::ShapeComposition>>>, + + pub volumetrics_memory: Vec<u32>, } impl Scene { @@ -212,6 +217,24 @@ impl Scene { self.rt_memory = volume_vec; data.scene_rt_memory_size = (self.rt_memory.len() * 4) as u64; // size of the needed buffer size in bytes + + let mut data_len = 0; + for compound in &self.volumetrics { + compound.borrow_mut().set_memory_start(data_len); + data_len += compound.borrow().get_compound_buffer_mem_size(data) as usize; + } + let mut volumetrics_memory = vec![0; data_len]; + + let mut compute_task_one_size = 0; + for compound in &self.volumetrics { + volumetrics_memory = compound.borrow_mut().insert_into_memory(volumetrics_memory, data, &self); + compute_task_one_size += compound.borrow().size.pow(2) as usize; + } + + self.volumetrics_memory = volumetrics_memory; + data.scene_rt_volumetric_size = (self.volumetrics_memory.len() * 4) as u64; // size of the needed buffer size in bytes + data.compute_task_one_size = compute_task_one_size; + } pub unsafe fn destroy(&mut self, device: &vulkanalia::Device) { diff --git a/src/scene/volumetrics/mod.rs b/src/scene/volumetrics/mod.rs new file mode 100644 index 0000000..df61678 --- /dev/null +++ b/src/scene/volumetrics/mod.rs @@ -0,0 +1,208 @@ +use crate::app_data::AppData; + +use super::{memorizable::Memorizable, Scene, memorizable::CompoundMemorizable}; +use cgmath::Vector3; +use winit::dpi::Size; + +use std::cell::RefCell; +use std::rc::Rc; + +pub trait Volumetrics: Memorizable { + fn get_pos(&self) -> Vector3<f32>; + fn set_pos(&mut self, p: Vector3<f32>); + + fn get_rot(&self) -> Vector3<f32>; + fn set_rot(&mut self, p: Vector3<f32>); + + fn get_bbox(&self) -> (Vector3<f32>,Vector3<f32>); +} + +enum ShapeTypes { + SPHERE, +} + + +#[derive(Clone, Debug)] +pub struct ShapeComposition { + memory_start: usize, + prev_memory_size: u32, + pub size: u32, + pub included_shapes: Vec<Rc<RefCell<dyn Volumetrics>>>, + pub excluded_shapes: Vec<Rc<RefCell<dyn Volumetrics>>>, + dirty: bool, +} + +impl ShapeComposition { + pub fn new(size: u32) -> Self { + Self { memory_start: 0, prev_memory_size: 0, size: size, included_shapes: vec![], excluded_shapes: vec![], dirty: true } + } +} + +impl CompoundMemorizable for ShapeComposition { + fn get_compound_buffer_mem_size(&self, data: &AppData) -> u32 { + let mut size = self.get_buffer_mem_size(data); + for volumetric in &self.included_shapes { + size += volumetric.borrow().get_buffer_mem_size(data); + } + for volumetric in &self.excluded_shapes { + size += volumetric.borrow().get_buffer_mem_size(data); + } + + size + } +} + +impl Memorizable for ShapeComposition { + fn get_buffer_mem_size(&self, data: &AppData) -> u32 { + //size, scale, memory_end, num_included, num_excluded, pos, included_address, excluded_address + 1 + 1 + 1 + 1 + 1 + 3 + self.included_shapes.len() as u32 + self.excluded_shapes.len() as u32 + } + + fn get_prev_buffer_mem_size(&self) -> u32 { + self.prev_memory_size + } + + fn is_dirty(&self) -> bool { + self.dirty + } + + fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + v[self.memory_start] = self.size; + + let mut shapes_memory = 0; + let shapes_index = self.memory_start + self.get_buffer_mem_size(data) as usize; + let mut bbox_low = Vector3 {x: f32::INFINITY, y: f32::INFINITY, z: f32::INFINITY}; + let mut bbox_high = Vector3 {x: f32::NEG_INFINITY, y: f32::NEG_INFINITY, z: f32::NEG_INFINITY}; + + let mut element_offset = 8; + for volumetric in &self.included_shapes { + // create bbox for scale calculation. Only the included elements matter for the scale, as exclusion does not need to be fully included in the grid + let (l, h) = volumetric.borrow().get_bbox(); + bbox_low = Vector3 {x: bbox_low.x.min(l.x), y: bbox_low.y.min(l.y), z: bbox_low.z.min(l.z)}; + bbox_high = Vector3 {x: bbox_high.x.max(h.x), y: bbox_high.y.max(h.y), z: bbox_high.z.max(h.z)}; + + volumetric.borrow_mut().set_memory_start(shapes_index + shapes_memory); + shapes_memory += volumetric.borrow().get_buffer_mem_size(data) as usize; + + // write the volumetric to memory + v = volumetric.borrow_mut().insert_into_memory(v, data, scene); + // add the reference + v[self.memory_start + element_offset] = volumetric.borrow().get_memory_start() as u32; + element_offset += 1; + } + + for volumetric in &self.excluded_shapes { + volumetric.borrow_mut().set_memory_start(shapes_index + shapes_memory); + shapes_memory += volumetric.borrow().get_buffer_mem_size(data) as usize; + + // write the volumetric to memory + v = volumetric.borrow_mut().insert_into_memory(v, data, scene); + // add the reference + v[self.memory_start + element_offset] = volumetric.borrow().get_memory_start() as u32; + element_offset += 1; + } + + v[self.memory_start + 1] = u32::from_ne_bytes((bbox_high.x.max(bbox_high.y.max(bbox_high.z)) - bbox_low.x.min(bbox_low.y.min(bbox_low.z)) / (self.size as f32)).to_ne_bytes()); + v[self.memory_start + 2] = (shapes_index + shapes_memory) as u32; + v[self.memory_start + 3] = self.included_shapes.len() as u32; + v[self.memory_start + 4] = self.excluded_shapes.len() as u32; + v[self.memory_start + 5] = u32::from_ne_bytes(bbox_low.x.to_ne_bytes()); + v[self.memory_start + 6] = u32::from_ne_bytes(bbox_low.y.to_ne_bytes()); + v[self.memory_start + 7] = u32::from_ne_bytes(bbox_low.z.to_ne_bytes()); + + self.prev_memory_size = self.get_compound_buffer_mem_size(data); + self.dirty = false; + v + } + + fn get_memory_start(&self) -> usize { + self.memory_start + } + + fn set_memory_start(&mut self, memory_start: usize) { + self.memory_start = memory_start; + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Sphere { + pos: Vector3<f32>, + rot: Vector3<f32>, // rotation will only matter once textures are implemented, till then it is a holdover + radius: f32, + color: Vector3<u8>, // color, either as pure color or texture modifier + roughness: u8, + memory_start: usize, + dirty: bool +} + +impl Sphere { + pub fn new( + pos: Vector3<f32>, + rot: Vector3<f32>, + radius: f32, + color: Vector3<u8>, + roughness: u8) -> Self { + Self { pos: pos, rot: rot, radius: radius, color: color, roughness: roughness, memory_start: 0, dirty: true } + } +} + +impl Memorizable for Sphere { + fn get_buffer_mem_size(&self, data: &AppData) -> u32 { + // type, pos, rot, radius, (color + roughness) + 1 + 3 + 3 + 1 + 1 + } + + fn get_prev_buffer_mem_size(&self) -> u32 { + // constant memory size + 1 + 3 + 3 + 1 + 1 + } + fn is_dirty(&self) -> bool { + self.dirty + } + fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + v[self.memory_start] = ShapeTypes::SPHERE as u32; + v[self.memory_start + 1] = u32::from_ne_bytes(self.pos.x.to_ne_bytes()); + v[self.memory_start + 2] = u32::from_ne_bytes(self.pos.y.to_ne_bytes()); + v[self.memory_start + 3] = u32::from_ne_bytes(self.pos.z.to_ne_bytes()); + + v[self.memory_start + 4] = u32::from_ne_bytes(self.rot.x.to_ne_bytes()); + v[self.memory_start + 5] = u32::from_ne_bytes(self.rot.y.to_ne_bytes()); + v[self.memory_start + 6] = u32::from_ne_bytes(self.rot.z.to_ne_bytes()); + + v[self.memory_start + 7] = u32::from_ne_bytes(self.radius.to_ne_bytes()); + + v[self.memory_start + 8] = u32::from_ne_bytes([self.color.x, self.color.y, self.color.z, self.roughness]); + + v + } + + fn get_memory_start(&self) -> usize { + self.memory_start + } + fn set_memory_start(&mut self, memory_start: usize) { + self.memory_start = memory_start; + } +} + +impl Volumetrics for Sphere { + fn get_pos(&self) -> Vector3<f32> { + self.pos + } + + fn set_pos(&mut self, p: Vector3<f32>) { + self.pos = p; + } + + fn get_rot(&self) -> Vector3<f32> { + self.rot + } + + fn set_rot(&mut self, p: Vector3<f32>) { + self.rot = p; + } + + fn get_bbox(&self) -> (Vector3<f32>, Vector3<f32>) { + let rad_vec = Vector3 {x: self.radius, y: self.radius, z: self.radius}; + (self.pos - rad_vec, self.pos + rad_vec) + } +} \ No newline at end of file