From 9b618b0e3fbfeb4babceb5bc93352d23d168298b Mon Sep 17 00:00:00 2001 From: zomseffen <steffen@tom.bi> Date: Mon, 20 Jan 2025 10:18:28 +0100 Subject: [PATCH] shader refactoring and float pos for lights --- shaders/compiled/frag_rt_quad.spv | Bin 27676 -> 28684 bytes shaders/rt_quad.frag | 156 +++++++++++++++++------------- src/scene/light.rs | 6 +- 3 files changed, 92 insertions(+), 70 deletions(-) diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv index 70c2c6ae56ac85eb260c6364ec334c1f470bc6fe..c161614af1f3c7a74aac100e1e0b7072db833a5c 100644 GIT binary patch literal 28684 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 D6zj0a literal 27676 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 M5B}bO*xwuYKYtDv9{>OV diff --git a/shaders/rt_quad.frag b/shaders/rt_quad.frag index d075f61..bac8002 100644 --- a/shaders/rt_quad.frag +++ b/shaders/rt_quad.frag @@ -127,68 +127,71 @@ uvec4 sample_color_from_scene_info(uint volume_start, uvec2 raster_pos, uint f) } vec3 get_light_position(uint light_index) { - return vec3(float(scene_info.infos[light_index]), float(scene_info.infos[light_index + 1]), float(scene_info.infos[light_index + 2])); + return vec3(uintBitsToFloat(scene_info.infos[light_index]), uintBitsToFloat(scene_info.infos[light_index + 1]), uintBitsToFloat(scene_info.infos[light_index + 2])); } 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); } -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; +struct Tracing { + vec3 end_pos; + uvec4 end_color; + uint end_volume; + uint end_facing; + float end_factor; + uint end_cycle; + bool has_hit; +}; +Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 direction, float max_factor, uint start_cycle, uint max_cycle) { + uint cycle = start_cycle; // 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[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; - bool x_null = (light_direction.x == 0.0); - - bool y_pos = light_direction.y > 0.0; - bool y_null = (light_direction.y == 0.0); - bool z_pos = light_direction.z > 0.0; - bool z_null = (light_direction.z == 0.0); + bool x_pos = direction.x > 0.0; + bool x_null = (direction.x == 0.0); + + bool y_pos = direction.y > 0.0; + bool y_null = (direction.y == 0.0); - // initialize color - vec3 color_sum = vec3(0.0, 0.0, 0.0) + (orig_color_sample.xyz * 0.01); + bool z_pos = direction.z > 0.0; + bool z_null = (direction.z == 0.0); - uint max_iterations = max_light_num * scene_info.infos[1]; - for (int i = 0; i < max_iterations; i++) { + // default is max factor, that way we avoid collision when going parallel to an axis. The other directions will score a hit + float x_factor = max_factor; + float y_factor = max_factor; + float z_factor = max_factor; + + Tracing result; + + while (cycle < max_cycle) { + cycle ++; 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; float z_border = float(volume_pos_z + (scene_info.infos[volume_index + 5]) * uint(z_pos)) - 0.5; bool needs_next_light = false; - // 2 is way behind the light position and should result in no collision being detected - float x_factor = 2.0; - float y_factor = 2.0; - float z_factor = 2.0; if (!x_null) { - x_factor = (x_border - starting_pos.x) / light_direction.x; + x_factor = (x_border - starting_pos.x) / direction.x; } if (!y_null) { - y_factor = (y_border - starting_pos.y) / light_direction.y; + y_factor = (y_border - starting_pos.y) / direction.y; } if (!z_null) { - z_factor = (z_border - starting_pos.z) / light_direction.z; + z_factor = (z_border - starting_pos.z) / 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.01 * length(light_direction) * length(light_direction)) + 1.0); - needs_next_light = true; + if ((x_factor >= max_factor) && (y_factor >= max_factor) && (z_factor >= max_factor)) { + // no hit, finish tracking + result.has_hit = false; + break; } else { - // if there is a border hit before reaching the light + // if there is a border hit before reaching the end // change to the relevant next volume // Todo: look into removing ifs from this uint hit_facing = 0; @@ -200,9 +203,11 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa } else { hit_facing = 2; } - vec3 intersection_pos = starting_pos + x_factor * light_direction; + vec3 intersection_pos = starting_pos + x_factor * direction; u = uint(round(intersection_pos.y)) - volume_pos_y; v = uint(round(intersection_pos.z)) - volume_pos_z; + result.end_pos = intersection_pos; + result.end_facing = hit_facing; } if (y_factor <= x_factor && y_factor <= z_factor) { @@ -211,9 +216,11 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa } else { hit_facing = 4; } - vec3 intersection_pos = starting_pos + y_factor * light_direction; + vec3 intersection_pos = starting_pos + y_factor * direction; u = uint(round(intersection_pos.x)) - volume_pos_x; v = uint(round(intersection_pos.z)) - volume_pos_z; + result.end_pos = intersection_pos; + result.end_facing = hit_facing; } if (z_factor <= x_factor && z_factor <= y_factor) { @@ -222,9 +229,11 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa } else { hit_facing = 1; } - vec3 intersection_pos = starting_pos + z_factor * light_direction; + vec3 intersection_pos = starting_pos + z_factor * direction; u = uint(round(intersection_pos.x)) - volume_pos_x; v = uint(round(intersection_pos.y)) - volume_pos_y; + result.end_pos = intersection_pos; + result.end_facing = hit_facing; } uint next_neighbor = sample_neighbor_from_scene_info(volume_index, uvec2(u, v), hit_facing); uvec4 color_sample = sample_color_from_scene_info(volume_index, uvec2(u, v), hit_facing); @@ -237,43 +246,56 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa volume_pos_y = scene_info.infos[volume_index + 1]; volume_pos_z = scene_info.infos[volume_index + 2]; } else { - // neightbor miss, shouldn't happen with a light inside of a volume. Might happen with ambient light. For now move on to next light. - needs_next_light = true; + // neightbor miss + break; } } else { - // color hit, move on to next light (may change once transparents are implemnted) - needs_next_light = true; - } - } - if (needs_next_light) { - light_num += 1; - if (light_num >= max_light_num) { + // color hit, move on + result.end_color = color_sample; + result.has_hit = true; break; } - // set up the new light - 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) - starting_pos; - light_color = get_light_color(light_index); - - x_pos = light_direction.x > 0.0; - x_null = (light_direction.x == 0.0); - - y_pos = light_direction.y > 0.0; - y_null = (light_direction.y == 0.0); - - z_pos = light_direction.z > 0.0; - z_null = (light_direction.z == 0.0); - // reset volume info - 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]; } } + result.end_volume = volume_index; + result.end_factor = min(min(x_factor, y_factor), z_factor); + result.end_cycle = cycle; + + return result; +} + +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; + + // initialize color + vec3 color_sum = vec3(0.0, 0.0, 0.0) + (orig_color_sample.xyz * 0.01); + + uint max_iterations = max_light_num * scene_info.infos[1]; + uint iteration = 0; + while (iteration < max_iterations) { + // setup light info + uint light_index = scene_info.infos[volume_start + 6 + light_num]; + if (light_index == 0) { + // abort if there is no new light + break; + } + vec3 light_direction = get_light_position(light_index) - starting_pos; + vec3 light_color = get_light_color(light_index); + + Tracing result = trace_ray(volume_start, starting_pos, light_direction, 1.0, iteration, max_iterations); + if (!result.has_hit) { + // no hit, add light color result + color_sum += (orig_color_sample.xyz * light_color) / ((0.01 * length(light_direction) * length(light_direction)) + 1.0); + } + iteration = result.end_cycle; + + light_num += 1; + if (light_num >= max_light_num) { + break; + } + } + return color_sum; } diff --git a/src/scene/light.rs b/src/scene/light.rs index 4893dd3..20a33ef 100644 --- a/src/scene/light.rs +++ b/src/scene/light.rs @@ -15,9 +15,9 @@ impl PointLight { } pub fn insert_into_memory(&self, mut v: Vec<u32>) -> Vec<u32> { - v[self.memory_start] = self.pos.x as u32; - v[self.memory_start + 1] = self.pos.y as u32; - v[self.memory_start + 2] = self.pos.z as 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()); v[self.memory_start + 3] = (self.color.x * 255.0) as u32; v[self.memory_start + 4] = (self.color.y * 255.0) as u32;