first step for compute task

This commit is contained in:
zomseffen 2025-04-02 11:10:12 +02:00
parent 579820334d
commit c02522b6c2
16 changed files with 470 additions and 32 deletions

View file

@ -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");

View file

@ -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
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

Binary file not shown.

Binary file not shown.

27
shaders/rt_compute.comp Normal file
View file

@ -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];
}

View file

@ -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

View file

@ -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,

View file

@ -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],
);
}

View file

@ -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)

View file

@ -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(())
}

View file

@ -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;

View file

@ -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;

View file

@ -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)))
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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)
}
}