diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv index 8b8614a..9e46dcc 100644 Binary files a/shaders/compiled/frag_rt_quad.spv and b/shaders/compiled/frag_rt_quad.spv differ diff --git a/shaders/rt_quad.frag b/shaders/rt_quad.frag index 7094bd4..aca2709 100644 --- a/shaders/rt_quad.frag +++ b/shaders/rt_quad.frag @@ -149,11 +149,11 @@ uvec4 sample_color_from_scene_info(uint volume_start, uvec2 raster_pos, uint f) } vec3 get_light_position(uint light_index) { - return vec3(uintBitsToFloat(scene_info.infos[light_index]), uintBitsToFloat(scene_info.infos[light_index + 1]), uintBitsToFloat(scene_info.infos[light_index + 2])); + return vec3(uintBitsToFloat(scene_info.infos[light_index + 1]), uintBitsToFloat(scene_info.infos[light_index + 2]), uintBitsToFloat(scene_info.infos[light_index + 3])); } vec3 get_light_color(uint light_index) { - return vec3(float(scene_info.infos[light_index + 3]) / 255.0, float(scene_info.infos[light_index + 4]) / 255.0, float(scene_info.infos[light_index + 5]) / 255.0); + return vec3(float(scene_info.infos[light_index + 4]) / 255.0, float(scene_info.infos[light_index + 5]) / 255.0, float(scene_info.infos[light_index + 6]) / 255.0); } vec3 normal_for_facing(uint facing) { @@ -377,7 +377,7 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa uint light_num = 0; // initialize color - vec3 color_sum = vec3(0.0, 0.0, 0.0) + (orig_color_sample.xyz * 0.01); + vec3 color_sum = vec3(0.0, 0.0, 0.0);// + (orig_color_sample.xyz * 0.01); uint max_iterations = max_num_lights * max_iterations_per_light; uint iteration = 0; @@ -388,10 +388,20 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa // abort if there is no new light break; } - vec3 light_direction = get_light_position(light_index) - starting_pos; + vec3 light_direction; + float max_factor; + if (scene_info.infos[light_index] == 0) { + //point light + light_direction = get_light_position(light_index) - starting_pos; + max_factor = 1.0; + } else if (scene_info.infos[light_index] == 1) { + // directional light + light_direction = -normalize(get_light_position(light_index)); + max_factor = pos_infinity; + } vec3 light_color = get_light_color(light_index); - Tracing result = trace_ray(volume_start, starting_pos, light_direction, 1.0, iteration, max_iterations, false); + Tracing result = trace_ray(volume_start, starting_pos, light_direction, max_factor, iteration, max_iterations, false); // add result, if there is a hit the null vector will be added color_sum += float(!result.has_hit) * result.color_mul * max(dot(normal, normalize(light_direction)), 0.0) * (orig_color_sample.xyz * light_color) / (length(light_direction) * length(light_direction)); diff --git a/src/main.rs b/src/main.rs index a81a664..93958e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -190,7 +190,7 @@ impl App { let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?; let mut data = app_data::AppData::default(); data.use_geometry_shader = false; - data.num_lights_per_volume = 2; + data.num_lights_per_volume = 5; data.max_iterations_per_light = 20; data.diffuse_raster_steps = 0; data.diffuse_raster_size = 0.01; @@ -218,9 +218,9 @@ impl App { create_framebuffers(&device, &mut data)?; - //image::create_texture_image(&instance, &device, &mut data)?; - //image::create_texture_image_view(&device, &mut data)?; - //image::create_texture_sampler(&device, &mut data)?; + image::create_texture_image(&instance, &device, &mut data)?; + image::create_texture_image_view(&device, &mut data)?; + image::create_texture_sampler(&device, &mut data)?; scene_handler.prepare_data(&instance, &device, &mut data)?; diff --git a/src/scene/empty_volume.rs b/src/scene/empty_volume.rs index 4c36e55..5277686 100644 --- a/src/scene/empty_volume.rs +++ b/src/scene/empty_volume.rs @@ -10,7 +10,12 @@ use crate::primitives::cube::Cube; use crate::primitives::quad::Quad; use crate::scene::oct_tree::OctTree; +use super::memorizable::Memorizable; +use super::light::LightSource; use super::light::PointLight; +use super::AppData; +use super::LightsIter; +use super::Scene; pub struct EmptyVolume { pub memory_start: usize, @@ -863,12 +868,37 @@ impl EmptyVolume { } quads } + + pub fn select_lights(&self, lights: LightsIter, light_number: u32) -> Vec<u32> { + let center = self.position + Vector3{x: self.size_x / 2, y: self.size_y / 2, z: self.size_z / 2}; + let mut weighted_indices = vec![]; + for light in lights { + let weight = light.borrow().weighted_distance(center); + weighted_indices.push((weight, light.borrow().get_memory_start())); + } + weighted_indices.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + + let mut out_index = vec![]; + for index in 0..weighted_indices.len() { + out_index.push(weighted_indices[weighted_indices.len() - (index + 1)].1 as u32); + if out_index.len() == light_number as usize { + break; + } + } + while out_index.len() < light_number as usize { + out_index.push(0); + } + out_index + } +} + +impl Memorizable for EmptyVolume { // MARK: Get Buffer Mem Size - pub fn get_buffer_mem_size(&self, light_number: u32) -> u32 { + fn get_buffer_mem_size(&self, data: &AppData) -> u32 { let mut mem_size: u32 = 0; mem_size += 3; //pos mem_size += 3; //max sizes - mem_size += light_number; // light references + mem_size += data.num_lights_per_volume; // light references mem_size += 12; //color/roughness buffer sizes, 2 values each mem_size += 12; //neighbor buffer sizes, 2 values each @@ -890,7 +920,7 @@ impl EmptyVolume { mem_size } // MARK: insert into Memory - pub fn insert_into_memory(&self, mut v: Vec<u32>, light_number: u32, lights: &Vec<PointLight>) -> Vec<u32> { + fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { let mut mem_index = self.memory_start; //pos v[mem_index] = self.position.x as u32; @@ -907,7 +937,7 @@ impl EmptyVolume { v[mem_index] = self.size_z as u32; mem_index += 1; //Todo: insert lights - let selected_lights = self.select_lights(lights, light_number); + let selected_lights = self.select_lights(scene.get_light_iter(), data.num_lights_per_volume); for light in selected_lights { v[mem_index] = light; mem_index += 1; @@ -1207,26 +1237,12 @@ impl EmptyVolume { v } - pub fn select_lights(&self, lights: &Vec<PointLight>, light_number: u32) -> Vec<u32> { - let center = self.position + Vector3{x: self.size_x / 2, y: self.size_y / 2, z: self.size_z / 2}; - let mut weighted_indices = vec![]; - for light in lights { - let weight = light.weighted_distance(center); - weighted_indices.push((weight, light.memory_start)); - } - weighted_indices.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + fn get_memory_start(&self) -> usize { + self.memory_start + } - let mut out_index = vec![]; - for index in 0..weighted_indices.len() { - out_index.push(weighted_indices[weighted_indices.len() - (index + 1)].1 as u32); - if out_index.len() == light_number as usize { - break; - } - } - while out_index.len() < light_number as usize { - out_index.push(0); - } - out_index + fn set_memory_start(&mut self, memory_start: usize) { + self.memory_start = memory_start; } } diff --git a/src/scene/light.rs b/src/scene/light.rs index 20a33ef..d6a4c82 100644 --- a/src/scene/light.rs +++ b/src/scene/light.rs @@ -1,6 +1,22 @@ use cgmath::{InnerSpace, MetricSpace, Vector3}; use crate::vertex; +use super::memorizable::Memorizable; +use super::AppData; +use super::Scene; + +pub enum LightType { + POINT, + DIRECTION +} + +pub trait Light { + fn get_light_type(&self) -> LightType; + fn weighted_distance(&self, center: Vector3<usize>) -> f32; +} + +pub trait LightSource: Light + Memorizable {} + #[derive(Clone, Debug, PartialEq)] pub struct PointLight{ @@ -9,26 +25,151 @@ pub struct PointLight{ pub memory_start: usize, } -impl PointLight { - pub fn get_buffer_mem_size(&self) -> u32 { - 3 + 3 +impl Memorizable for PointLight { + fn get_buffer_mem_size(&self, data: &AppData) -> u32 { + 1 + 3 + 3 } - pub fn insert_into_memory(&self, mut v: Vec<u32>) -> Vec<u32> { - v[self.memory_start] = u32::from_ne_bytes(self.pos.x.to_ne_bytes()); - v[self.memory_start + 1] = u32::from_ne_bytes(self.pos.y.to_ne_bytes()); - v[self.memory_start + 2] = u32::from_ne_bytes(self.pos.z.to_ne_bytes()); + fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + v[self.memory_start] = LightType::POINT as u32; - v[self.memory_start + 3] = (self.color.x * 255.0) as u32; - v[self.memory_start + 4] = (self.color.y * 255.0) as u32; - v[self.memory_start + 5] = (self.color.z * 255.0) 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] = (self.color.x * 255.0) as u32; + v[self.memory_start + 5] = (self.color.y * 255.0) as u32; + v[self.memory_start + 6] = (self.color.z * 255.0) as u32; v } - pub fn weighted_distance(&self, center: Vector3<usize>) -> f32 { + fn get_memory_start(&self) -> usize { + self.memory_start + } + + fn set_memory_start(&mut self, memory_start: usize) { + self.memory_start = memory_start; + } +} + +impl Light for PointLight { + fn get_light_type(&self) -> LightType { + LightType::POINT + } + + fn weighted_distance(&self, center: Vector3<usize>) -> f32 { let distance = self.pos.distance(vertex::Vec3{x: center.x as f32, y: center.y as f32, z: center.z as f32}); let light_intensity = self.color.magnitude(); light_intensity / distance.powf(2.0) } +} + +impl LightSource for PointLight {} + +#[derive(Clone, Debug, PartialEq)] +pub struct DirectionalLight{ + pub direction: vertex::Vec3, + pub color: vertex::Vec3, + pub memory_start: usize, +} + +impl Memorizable for DirectionalLight { + fn get_buffer_mem_size(&self, data: &AppData) -> u32 { + 1 + 3 + 3 + } + + fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + v[self.memory_start] = LightType::DIRECTION as u32; + + v[self.memory_start + 1] = u32::from_ne_bytes(self.direction.x.to_ne_bytes()); + v[self.memory_start + 2] = u32::from_ne_bytes(self.direction.y.to_ne_bytes()); + v[self.memory_start + 3] = u32::from_ne_bytes(self.direction.z.to_ne_bytes()); + + v[self.memory_start + 4] = (self.color.x * 255.0) as u32; + v[self.memory_start + 5] = (self.color.y * 255.0) as u32; + v[self.memory_start + 6] = (self.color.z * 255.0) as u32; + 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 Light for DirectionalLight { + fn get_light_type(&self) -> LightType { + LightType::DIRECTION + } + + fn weighted_distance(&self, center: Vector3<usize>) -> f32 { + let light_intensity = self.color.magnitude(); + + light_intensity + } +} + +impl LightSource for DirectionalLight {} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_memorizable() { + let p = PointLight {pos: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let data= AppData::default(); + let scene = Scene::default(); + + let mem_size = p.get_buffer_mem_size(&data); + assert!(mem_size == 7); + + let mut memory = vec![0; 7]; + p.insert_into_memory(memory, &data, &scene); + } + + #[test] + #[should_panic] + fn test_mem_size() { + let p = PointLight {pos: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let data= AppData::default(); + let scene = Scene::default(); + + let mem_size = p.get_buffer_mem_size(&data); + assert!(mem_size == 7); + + let mut memory = vec![0; 6]; + p.insert_into_memory(memory, &data, &scene); + } + + #[test] + fn test_memorizable_directional_light() { + let p = DirectionalLight {direction: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let data= AppData::default(); + let scene = Scene::default(); + + let mem_size = p.get_buffer_mem_size(&data); + assert!(mem_size == 7); + + let mut memory = vec![0; 7]; + p.insert_into_memory(memory, &data, &scene); + } + + #[test] + #[should_panic] + fn test_mem_size_directional_light() { + let p = DirectionalLight {direction: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let data= AppData::default(); + let scene = Scene::default(); + + let mem_size = p.get_buffer_mem_size(&data); + assert!(mem_size == 7); + + let mut memory = vec![0; 6]; + p.insert_into_memory(memory, &data, &scene); + } } \ No newline at end of file diff --git a/src/scene/memorizable.rs b/src/scene/memorizable.rs new file mode 100644 index 0000000..22d8519 --- /dev/null +++ b/src/scene/memorizable.rs @@ -0,0 +1,10 @@ +use super::light::LightSource; +use super::AppData; +use super::Scene; + +pub trait Memorizable { + fn get_buffer_mem_size(&self, data: &AppData) -> u32; + fn insert_into_memory(&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); +} \ No newline at end of file diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 6672fc2..e9d19e7 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -1,8 +1,10 @@ mod oct_tree; mod empty_volume; mod light; +mod memorizable; use anyhow::Ok; +use light::{DirectionalLight, LightSource}; use vulkanalia::prelude::v1_0::*; use anyhow::Result; @@ -11,6 +13,7 @@ use cgmath::{vec2, vec3, Vector3}; use std::cell::RefCell; use std::rc::Rc; +use crate::scene::memorizable::Memorizable; use crate::app_data::AppData; use crate::buffer; use crate::primitives::rec_cuboid::Cuboid; @@ -54,7 +57,8 @@ pub struct Scene { pub rt_memory: Vec<u32>, - pub point_lights: Vec<PointLight>, + point_lights: Vec<Rc<RefCell<PointLight>>>, + directional_lights: Vec<Rc<RefCell<DirectionalLight>>>, } impl Scene { @@ -99,8 +103,9 @@ impl Scene { }; oct_tree.set_cube(cube.clone()); - self.point_lights.push(PointLight { pos: vec3(11.0, 11.0, 11.0), color: vec3(1.0, 1.0, 1.0), memory_start: 0 }); - self.point_lights.push(PointLight { pos: vec3(9.0, 9.0, 11.0), color: vec3(0.5, 0.5, 0.5), memory_start: 0 }); + self.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(11.0, 11.0, 11.0), color: vec3(1.0, 1.0, 1.0), memory_start: 0 }))); + self.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(9.0, 9.0, 11.0), color: vec3(0.5, 0.5, 0.5), memory_start: 0 }))); + self.directional_lights.push(Rc::new(RefCell::new(DirectionalLight { direction: vec3(1.0, 1.0, -1.0), color: vec3(0.1, 0.1, 0.1), memory_start: 0 }))); let empty_volumes: Vec<Rc<RefCell<EmptyVolume>>>; (empty_volumes, _) = EmptyVolume::from_oct_tree(&oct_tree); @@ -156,14 +161,14 @@ impl Scene { // 3 - diffuse raster size // 4 - max recursive rays // 5 - diffuse rays per hit - for light in &mut self.point_lights { - light.memory_start = memory_index; - memory_index += light.get_buffer_mem_size() as usize; + for light in LightsIter::new(self) { + light.borrow_mut().set_memory_start(memory_index); + memory_index += light.borrow_mut().get_buffer_mem_size(data) as usize; } for volume in &empty_volumes { - volume.borrow_mut().memory_start = memory_index; - memory_index += volume.borrow().get_buffer_mem_size(data.num_lights_per_volume) as usize; + volume.borrow_mut().set_memory_start(memory_index); + memory_index += volume.borrow().get_buffer_mem_size(data) as usize; } for volume in &empty_volumes { @@ -181,10 +186,10 @@ impl Scene { volume_vec[5] = data.diffuse_rays_per_hit; for volume in &empty_volumes { - volume_vec = volume.borrow().insert_into_memory(volume_vec, data.num_lights_per_volume, &self.point_lights); + volume_vec = volume.borrow().insert_into_memory(volume_vec, data, &self); } - for light in &self.point_lights { - volume_vec = light.insert_into_memory(volume_vec); + for light in LightsIter::new(self) { + volume_vec = light.borrow().insert_into_memory(volume_vec, data, &self); } //println!("volume_vec print {:?}", volume_vec); @@ -229,4 +234,40 @@ impl Scene { device.destroy_buffer(self.vertex_buffer_quad, None); device.free_memory(self.vertex_buffer_memory_quad, None); } + + fn get_light_iter(&self) -> LightsIter { + LightsIter::new(self) + } +} + + +pub struct LightsIter<'a> { + light_index: usize, + scene: &'a Scene, +} + +impl<'a> LightsIter<'a> { + fn new(scene: &'a Scene) -> Self { + LightsIter {light_index: 0, scene: scene} + } +} + +impl<'a> Iterator for LightsIter<'a> { + type Item = Rc<RefCell<dyn LightSource>>; + + fn next(&mut self) -> Option<Self::Item> { + if self.light_index >= self.scene.point_lights.len() { + if self.light_index - self.scene.point_lights.len() >= self.scene.directional_lights.len() { + None + } else { + let result = self.scene.directional_lights[self.light_index - self.scene.point_lights.len()].clone(); + self.light_index += 1; + Some(result) + } + } else { + let result = self.scene.point_lights[self.light_index].clone(); + self.light_index += 1; + Some(result) + } + } } \ No newline at end of file diff --git a/src/scene/oct_tree.rs b/src/scene/oct_tree.rs index 7b8212d..c9f94fa 100644 --- a/src/scene/oct_tree.rs +++ b/src/scene/oct_tree.rs @@ -601,7 +601,7 @@ mod test { #[test] fn test_oct_tree(){ let mut test_tree: OctTree<Cube> = OctTree::create(512).unwrap(); - let test_cube = Cube{color: Vector3 { x: 1.0, y: 0.0, z: 0.0 }, pos: Vector3 { x: 5.0, y: 2.0, z: 10.0 }, tex_coord: Vector2{x: 0.0, y: 0.0}, transparent: false}; + let test_cube = Cube{color: Vector3 { x: 1.0, y: 0.0, z: 0.0 }, pos: Vector3 { x: 5.0, y: 2.0, z: 10.0 }, tex_coord: Vector2{x: 0.0, y: 0.0}, transparent: false, roughness: 128}; test_tree.set_cube(test_cube.clone());