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