From 86135cb2ce48bfd52797223a73d80894e78a4d2a Mon Sep 17 00:00:00 2001
From: zomseffen <steffen@tom.bi>
Date: Fri, 17 Jan 2025 11:10:39 +0100
Subject: [PATCH] diffuse raytracing

---
 shaders/compiled/frag_rt_quad.spv | Bin 24048 -> 27676 bytes
 shaders/rt_quad.frag              |  69 +++++++++++++++++++++---------
 src/app_data.rs                   |   1 +
 src/main.rs                       |   3 +-
 src/scene/mod.rs                  |   6 ++-
 src/scene/oct_tree.rs             |   2 +-
 6 files changed, 57 insertions(+), 24 deletions(-)

diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv
index 32ca9f02830832efa29626333a924d7786d65827..70c2c6ae56ac85eb260c6364ec334c1f470bc6fe 100644
GIT binary patch
literal 27676
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
M5B}bO*xwuYKYtDv9{>OV

literal 24048
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
Bkw^dl

diff --git a/shaders/rt_quad.frag b/shaders/rt_quad.frag
index b6ce9aa..d075f61 100644
--- a/shaders/rt_quad.frag
+++ b/shaders/rt_quad.frag
@@ -134,24 +134,19 @@ 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);
 }
 
-void main() {
-    uint max_length = scene_info.infos[0];
-    uint last = scene_info.infos[max_length];
-    
-    uvec4 color_roughness = sample_color_from_scene_info(fragVolumeStart, fragRasterPos, facing);
-    vec4 orig_color_sample = vec4(float(color_roughness.x) / 255.0, float(color_roughness.y) / 255.0, float(color_roughness.z) / 255.0, 1);
-    
+vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sample) {
     uint max_light_num = scene_info.infos[0];
     uint light_num = 0;
-    uint volume_index = fragVolumeStart;
 
+    // setup volume info
+    uint volume_index = volume_start;
     uint volume_pos_x = scene_info.infos[volume_index + 0]; 
     uint volume_pos_y = scene_info.infos[volume_index + 1]; 
     uint volume_pos_z = scene_info.infos[volume_index + 2]; 
     
     // setup light info
-    uint light_index = scene_info.infos[fragVolumeStart + 6 + light_num];
-    vec3 light_direction = get_light_position(light_index) - origPosition;
+    uint light_index = scene_info.infos[volume_start + 6 + light_num];
+    vec3 light_direction = get_light_position(light_index) - starting_pos;
     vec3 light_color = get_light_color(light_index);
     
     bool x_pos = light_direction.x > 0.0;
@@ -166,7 +161,7 @@ void main() {
     // initialize color
     vec3 color_sum = vec3(0.0, 0.0, 0.0) + (orig_color_sample.xyz * 0.01);
 
-    uint max_iterations = max_light_num * 20;
+    uint max_iterations = max_light_num * scene_info.infos[1];
     for (int i = 0; i < max_iterations; i++) {
         float x_border = float(volume_pos_x + (scene_info.infos[volume_index + 3]) * uint(x_pos)) - 0.5;
         float y_border = float(volume_pos_y + (scene_info.infos[volume_index + 4]) * uint(y_pos)) - 0.5;
@@ -179,18 +174,18 @@ void main() {
         float y_factor = 2.0;
         float z_factor = 2.0;
         if (!x_null) {
-            x_factor = (x_border - origPosition.x) / light_direction.x;
+            x_factor = (x_border - starting_pos.x) / light_direction.x;
         }
         if (!y_null) {
-            y_factor = (y_border - origPosition.y) / light_direction.y;
+            y_factor = (y_border - starting_pos.y) / light_direction.y;
         }
         if (!z_null) {
-            z_factor = (z_border - origPosition.z) / light_direction.z;
+            z_factor = (z_border - starting_pos.z) / light_direction.z;
         }
 
         if ((x_factor >= 1.0) && (y_factor >= 1.0) && (z_factor >= 1.0)) {
             // no hit, add light color result
-            color_sum += (orig_color_sample.xyz * light_color) / ((0.1 * light_direction.length() * light_direction.length()) + 1.0);
+            color_sum += (orig_color_sample.xyz * light_color) / ((0.01 * length(light_direction) * length(light_direction)) + 1.0);
             needs_next_light = true;
         } else {
             // if there is a border hit before reaching the light
@@ -205,7 +200,7 @@ void main() {
                 } else {
                     hit_facing = 2;
                 }
-                vec3 intersection_pos = origPosition + x_factor * light_direction;
+                vec3 intersection_pos = starting_pos + x_factor * light_direction;
                 u = uint(round(intersection_pos.y)) - volume_pos_y;
                 v = uint(round(intersection_pos.z)) - volume_pos_z;
             }
@@ -216,7 +211,7 @@ void main() {
                 } else {
                     hit_facing = 4;
                 }
-                vec3 intersection_pos = origPosition + y_factor * light_direction;
+                vec3 intersection_pos = starting_pos + y_factor * light_direction;
                 u = uint(round(intersection_pos.x)) - volume_pos_x;
                 v = uint(round(intersection_pos.z)) - volume_pos_z;
             }
@@ -227,7 +222,7 @@ void main() {
                 } else {
                     hit_facing = 1;
                 }
-                vec3 intersection_pos = origPosition + z_factor * light_direction;
+                vec3 intersection_pos = starting_pos + z_factor * light_direction;
                 u = uint(round(intersection_pos.x)) - volume_pos_x;
                 v = uint(round(intersection_pos.y)) - volume_pos_y;
             }
@@ -256,12 +251,12 @@ void main() {
                 break;
             }
             // set up the new light
-            light_index = scene_info.infos[fragVolumeStart + 6 + light_num];
+            light_index = scene_info.infos[volume_start + 6 + light_num];
             if (light_index == 0) {
                 // abort if there is no new light
                 break;
             }
-            light_direction = get_light_position(light_index) - origPosition;
+            light_direction = get_light_position(light_index) - starting_pos;
             light_color = get_light_color(light_index);
             
             x_pos = light_direction.x > 0.0;
@@ -273,11 +268,43 @@ void main() {
             z_pos = light_direction.z > 0.0;
             z_null = (light_direction.z == 0.0);
             // reset volume info
-            volume_index = fragVolumeStart;
+            volume_index = volume_start;
             volume_pos_x = scene_info.infos[volume_index + 0]; 
             volume_pos_y = scene_info.infos[volume_index + 1]; 
             volume_pos_z = scene_info.infos[volume_index + 2]; 
         }
     }
+    return color_sum;
+}
+
+void main() {
+    uint max_length = scene_info.infos[0];
+    uint last = scene_info.infos[max_length];
+    
+    uvec4 color_roughness = sample_color_from_scene_info(fragVolumeStart, fragRasterPos, facing);
+    vec4 orig_color_sample = vec4(float(color_roughness.x) / 255.0, float(color_roughness.y) / 255.0, float(color_roughness.z) / 255.0, 1);
+
+    // singular raytracing
+    //vec3 color_sum = get_lighting_color(fragVolumeStart, origPosition, orig_color_sample);
+
+    // diffuse raytracing using a quadratic raster of rays
+    int raster_half_steps = 0;
+    float raster_distance = 0.01;
+    int raster_points = (2 * raster_half_steps + 1) * (2 * raster_half_steps + 1);
+
+    vec3 color_sum = vec3(0.0, 0.0, 0.0);
+    for (int u_offset = -raster_half_steps; u_offset <= raster_half_steps; u_offset++) {
+        for (int v_offset = -raster_half_steps; v_offset <= raster_half_steps; v_offset++) {
+            float x_offset = raster_distance * float(u_offset) * float(facing == 0 || facing == 1 || facing == 4 || facing == 5);
+            float y_offset = raster_distance * float(u_offset) * float(facing == 2 || facing == 3);
+            y_offset += raster_distance * float(v_offset) * float(facing == 0 || facing == 1);
+            float z_offset = raster_distance * float(v_offset) * float(facing == 4 || facing == 5 || facing == 2 || facing == 3);
+
+            vec3 offset = vec3(x_offset, y_offset, z_offset);
+
+            color_sum += get_lighting_color(fragVolumeStart, origPosition + offset, orig_color_sample) / float(raster_points);
+        }
+    }
+
     outColor = vec4(color_sum, 1.0);
 }
\ No newline at end of file
diff --git a/src/app_data.rs b/src/app_data.rs
index 9a6e5c6..91d507a 100644
--- a/src/app_data.rs
+++ b/src/app_data.rs
@@ -61,4 +61,5 @@ pub struct AppData {
 
     pub scene_rt_memory_size: u64,
     pub num_lights_per_volume: u32,
+    pub max_iterations_per_light: u32,
 }
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 5c6dc6b..bda1050 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -58,7 +58,7 @@ const DEVICE_EXTENSIONS: &[vk::ExtensionName] = &[
     vk::KHR_SWAPCHAIN_EXTENSION.name
 ];
 
-const MAX_FRAMES_IN_FLIGHT: usize = 2;
+const MAX_FRAMES_IN_FLIGHT: usize = 3;
 
 fn main() -> Result<()> {
     pretty_env_logger::init();
@@ -179,6 +179,7 @@ impl App {
         let mut data = app_data::AppData::default();
         data.use_geometry_shader = false;
         data.num_lights_per_volume = 2;
+        data.max_iterations_per_light = 20;
         let mut scene_handler = scene::Scene::default();
         
         //load_model::load_model(&mut data)?;
diff --git a/src/scene/mod.rs b/src/scene/mod.rs
index 2006ece..160636a 100644
--- a/src/scene/mod.rs
+++ b/src/scene/mod.rs
@@ -138,7 +138,9 @@ impl Scene {
         let index = self.sized_vertices.len();
         cube.draw(&data.topology, index, self);
         
-        let mut memory_index = 1; // zero should be the location for the overall length (also will be the invalid memory allocation for pointing to a nonexistant neighbor)
+        let mut memory_index = 2; 
+        // 0 - location for the maximum number of lights referenced per chunk (also will be the invalid memory allocation for pointing to a nonexistant neighbor)
+        // 1 - location for the max iterations per light
         for light in &mut self.point_lights {
             light.memory_start = memory_index;
             memory_index += light.get_buffer_mem_size() as usize;
@@ -157,6 +159,8 @@ impl Scene {
         }
         println!("Memory size is {} kB, max indes is {}", memory_index * 32 / 8 /1024 + 1, memory_index);
         let mut volume_vec = vec![data.num_lights_per_volume; memory_index];
+        volume_vec[1] = data.max_iterations_per_light;
+        
         for volume in &empty_volumes {
             volume_vec = volume.borrow().insert_into_memory(volume_vec, data.num_lights_per_volume, &self.point_lights);
         }
diff --git a/src/scene/oct_tree.rs b/src/scene/oct_tree.rs
index 006d16d..7f6a3ba 100644
--- a/src/scene/oct_tree.rs
+++ b/src/scene/oct_tree.rs
@@ -9,7 +9,7 @@ extern crate rand;
 
 pub const CHUNK_SIZE_EXPONENT: u32 = 4;
 pub const CHUNK_SIZE: usize = (2 as usize).pow(CHUNK_SIZE_EXPONENT);
-pub const MAX_TREE_DEPTH: usize = 2;
+pub const MAX_TREE_DEPTH: usize = CHUNK_SIZE_EXPONENT as usize - 2;
 pub const MIN_CHUNK_SIZE: usize = CHUNK_SIZE / (2 as usize).pow(MAX_TREE_DEPTH as u32);
 
 #[derive(Clone, Debug)]