From dc66ae4b3d4bd53291efc7443325e2075369fbdd Mon Sep 17 00:00:00 2001 From: zomseffen <steffen@tom.bi> Date: Wed, 5 Feb 2025 16:50:57 +0100 Subject: [PATCH] recursive reflection for nontransparnt elements --- shaders/compiled/frag_rt_quad.spv | Bin 36496 -> 41856 bytes shaders/rt_quad.frag | 232 ++++++++++++++++++------------ src/main.rs | 2 +- src/scene/empty_volume.rs | 15 +- src/scene/mod.rs | 14 +- 5 files changed, 162 insertions(+), 101 deletions(-) diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv index e1015268fbc4f88176fbdddd7c9e90d5e680638d..af2c27e9d9c348bc26a28660a63c8c01940739ef 100644 GIT binary patch literal 41856 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 literal 36496 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 b@3+8d+c@pH@9hM3UhJQKe&3|#J>dTUfWJJ9 diff --git a/shaders/rt_quad.frag b/shaders/rt_quad.frag index 806c1d3..9199c8f 100644 --- a/shaders/rt_quad.frag +++ b/shaders/rt_quad.frag @@ -25,6 +25,12 @@ layout(binding = 0) uniform UniformBufferObject { layout(binding = 2) buffer SceneInfoBuffer{ uint infos[]; } scene_info; +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 +int half_diffuse_raster_steps = int(scene_info.infos[2]); +float raster_distance = uintBitsToFloat(scene_info.infos[3]); +int raster_points = (2 * half_diffuse_raster_steps + 1) * (2 * half_diffuse_raster_steps + 1); uvec4 unpack_color(uint val) { // left most 8 bits first @@ -37,7 +43,7 @@ uvec4 unpack_color(uint val) { } uint sample_neighbor_from_scene_info(uint volume_start, uvec2 raster_pos, uint f) { - uint array_descr_start = volume_start + 6 + scene_info.infos[0]; + uint array_descr_start = volume_start + 6 + max_num_lights; uint color_array_start = array_descr_start + 24; uint top_color_size_u = scene_info.infos[array_descr_start]; @@ -103,7 +109,7 @@ uint sample_neighbor_from_scene_info(uint volume_start, uvec2 raster_pos, uint f } uvec4 sample_color_from_scene_info(uint volume_start, uvec2 raster_pos, uint f) { - uint array_descr_start = volume_start + 6 + scene_info.infos[0]; + uint array_descr_start = volume_start + 6 + max_num_lights; uint color_array_start = array_descr_start + 24; uint top_color_size_u = scene_info.infos[array_descr_start]; @@ -149,6 +155,34 @@ 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 normal_for_facing(uint facing) { + if (facing == 0) { + return vec3(0.0, 0.0, -1.0); + } + if (facing == 1) { + return vec3(0.0, 0.0, 1.0); + } + if (facing == 2) { + return vec3(1.0, 0.0, 0.0); + } + if (facing == 3) { + return vec3(-1.0, 0.0, 0.0); + } + if (facing == 4) { + return vec3(0.0, 1.0, 0.0); + } + if (facing == 5) { + return vec3(0.0, -1.0, 0.0); + } + + return vec3(0.0, 0.0, 0.0); +} + +vec3 reflect_vector(vec3 direction, uint facing) { + vec3 normal = normal_for_facing(facing); + return direction - 2.0 * dot(direction, normal) * normal; +} + struct Tracing { vec3 end_pos; uvec4 end_color; @@ -159,9 +193,14 @@ struct Tracing { bool has_hit; vec3 color_mul; uvec2 end_raster; + + bool has_transparent_hit; }; -Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 direction, float max_factor, uint start_cycle, uint max_cycle) { +Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, float start_max_factor, uint start_cycle, uint max_cycle, bool allow_reflect) { + vec3 direction = start_direction; + float max_factor = start_max_factor; + vec3 pos = starting_pos; uint cycle = start_cycle; // setup volume info uint volume_index = volume_start; @@ -184,8 +223,18 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 direction, float ma float z_factor = max_factor; Tracing result; + result.has_hit = false; + result.has_transparent_hit = false; result.color_mul = vec3(1.0, 1.0, 1.0); + // intermediate storage for transparent hit values + vec3 end_pos_transparent; + uvec4 end_color_transparent; + uint end_volume_transparent; + uint end_facing_transparent; + uvec2 end_raster_transparent; + vec3 color_mul_transparent; + while (cycle < max_cycle) { cycle ++; float x_border = float(volume_pos_x + (scene_info.infos[volume_index + 3]) * uint(x_pos)) - 0.5; @@ -195,18 +244,17 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 direction, float ma bool needs_next_light = false; if (!x_null) { - x_factor = (x_border - starting_pos.x) / direction.x; + x_factor = (x_border - pos.x) / direction.x; } if (!y_null) { - y_factor = (y_border - starting_pos.y) / direction.y; + y_factor = (y_border - pos.y) / direction.y; } if (!z_null) { - z_factor = (z_border - starting_pos.z) / direction.z; + z_factor = (z_border - pos.z) / direction.z; } 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 end @@ -215,44 +263,19 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 direction, float ma uint hit_facing = 0; uint u = 0; uint v = 0; - if (x_factor <= y_factor && x_factor <= z_factor) { - if (x_pos) { - hit_facing = 3; - } else { - hit_facing = 2; - } - 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) { - if (y_pos) { - hit_facing = 5; - } else { - hit_facing = 4; - } - 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; - } + bool is_x_smallest = x_factor < y_factor && x_factor < z_factor; + bool is_y_smallest = y_factor < x_factor && y_factor < z_factor; + bool is_z_smallest = z_factor <= x_factor && z_factor <= y_factor; + + hit_facing = uint(is_x_smallest) * (2 + uint(x_pos)) + uint(is_y_smallest) * (4 + uint(y_pos)) + uint(is_z_smallest && !z_pos); + float smallest_factor = min(min(x_factor, y_factor), z_factor); // maybe use multiplication instead? + vec3 intersection_pos = pos + smallest_factor * direction; + u = uint(is_x_smallest) * (uint(round(intersection_pos.y)) - volume_pos_y) + + uint(is_y_smallest || is_z_smallest) * (uint(round(intersection_pos.x)) - volume_pos_x); + v = uint(is_x_smallest || is_y_smallest) * (uint(round(intersection_pos.z)) - volume_pos_z) + + uint(is_z_smallest) * (uint(round(intersection_pos.y)) - volume_pos_y); - if (z_factor <= x_factor && z_factor <= y_factor) { - if (z_pos) { - hit_facing = 0; - } else { - hit_facing = 1; - } - 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); @@ -264,42 +287,95 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 direction, float ma volume_pos_y = scene_info.infos[volume_index + 1]; volume_pos_z = scene_info.infos[volume_index + 2]; } else { - // neightbor miss + // neighbor miss break; } } else { if (next_neighbor != 0) { // transparent hit, move on but change the color + end_volume_transparent = volume_index; + color_mul_transparent = result.color_mul; + volume_index = next_neighbor; 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.color_mul = result.color_mul * vec3(float(color_sample.x) / 255.0, float(color_sample.y) / 255.0, float(color_sample.z) / 255.0); + result.has_transparent_hit = true; + result.end_volume = volume_index; + + end_color_transparent = color_sample; + end_raster_transparent = uvec2(u, v); + end_pos_transparent = intersection_pos; + end_facing_transparent = hit_facing; + + // stop iterating if there is barely anything left to see + if (max(result.color_mul.x, max(result.color_mul.y, result.color_mul.z)) < 0.1) { + break; + } } else { - // color hit, move on + // color hit, either reflect or move on + result.end_pos = intersection_pos; + result.end_facing = hit_facing; result.end_color = color_sample; result.end_raster = uvec2(u, v); result.has_hit = true; - break; + result.end_volume = volume_index; + + float reflectivity = 1.0 - float(color_sample.w) / 255.0; + vec3 refltective_color_mul = result.color_mul * vec3(float(color_sample.x) / 255.0, float(color_sample.y) / 255.0, float(color_sample.z) / 255.0); + vec3 visibility_after_reflection = refltective_color_mul * reflectivity; + //break; + //max(visibility_after_reflection.x, max(visibility_after_reflection.y, visibility_after_reflection.z)) >= 0.1 && + if (allow_reflect) { + // do reflect + direction = reflect_vector(direction, hit_facing); + pos = intersection_pos; + //max_factor -= smallest_factor; + + x_pos = direction.x > 0.0; + x_null = (direction.x == 0.0); + + y_pos = direction.y > 0.0; + y_null = (direction.y == 0.0); + + z_pos = direction.z > 0.0; + z_null = (direction.z == 0.0); + } else { + break; + } } } } } - result.end_volume = volume_index; result.end_factor = min(min(x_factor, y_factor), z_factor); result.end_cycle = cycle; + // in case we have a transparent hit but no hit afterwards + if (!result.has_hit && result.has_transparent_hit) { + // did we stop because nothing could be seen through the object? + if (max(result.color_mul.x, max(result.color_mul.y, result.color_mul.z)) < 0.1) { + // if so count it as a hit + result.has_hit = true; + } + result.end_pos = end_pos_transparent; + result.end_color = end_color_transparent; + result.end_volume = end_volume_transparent; + result.end_facing = end_facing_transparent; + result.end_raster = end_raster_transparent; + result.color_mul = color_mul_transparent; + } + return result; } vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sample, vec3 normal) { - 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 max_iterations = max_num_lights * max_iterations_per_light; uint iteration = 0; while (iteration < max_iterations) { // setup light info @@ -311,15 +387,14 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa 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 += result.color_mul * max(dot(normal, normalize(light_direction)), 0.0) * (orig_color_sample.xyz * light_color) / (length(light_direction) * length(light_direction)); - } + Tracing result = trace_ray(volume_start, starting_pos, light_direction, 1.0, 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)); + iteration = result.end_cycle; light_num += 1; - if (light_num >= max_light_num) { + if (light_num >= max_num_lights) { break; } } @@ -327,42 +402,14 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa return color_sum; } -vec3 normal_for_facing(uint facing) { - if (facing == 0) { - return vec3(0.0, 0.0, -1.0); - } - if (facing == 1) { - return vec3(0.0, 0.0, 1.0); - } - if (facing == 2) { - return vec3(0.0, 1.0, 0.0); - } - if (facing == 3) { - return vec3(0.0, -1.0, 0.0); - } - if (facing == 4) { - return vec3(1.0, 0.0, 0.0); - } - if (facing == 5) { - return vec3(-1.0, 0.0, 0.0); - } - - return vec3(0.0, 0.0, 0.0); -} - vec3 diffuse_tracing(uint volume_start, uvec2 raster_pos, vec3 pos, uint f) { uvec4 color_roughness = sample_color_from_scene_info(volume_start, raster_pos, f); 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 normal = normal_for_facing(f); - // diffuse raytracing using a quadratic raster of rays - int raster_half_steps = int(scene_info.infos[2]); - float raster_distance = uintBitsToFloat(scene_info.infos[3]); - 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++) { + for (int u_offset = -half_diffuse_raster_steps; u_offset <= half_diffuse_raster_steps; u_offset++) { + for (int v_offset = -half_diffuse_raster_steps; v_offset <= half_diffuse_raster_steps; v_offset++) { float x_offset = raster_distance * float(u_offset) * float(f == 0 || f == 1 || f == 4 || f == 5); float y_offset = raster_distance * float(u_offset) * float(f == 2 || f == 3); y_offset += raster_distance * float(v_offset) * float(f == 0 || f == 1); @@ -400,12 +447,12 @@ void main() { vec3 color_sum; uint orig_neighbor = sample_neighbor_from_scene_info(fragVolumeStart, fragRasterPos, facing); + float pos_infinity = uintBitsToFloat(0x7F800000); if (orig_neighbor != 0) { - float pos_infinity = uintBitsToFloat(0x7F800000); - Tracing t = trace_ray(fragVolumeStart, ubo.camera_pos, clamped_pos - ubo.camera_pos, 100.0, 0, 20); + Tracing t = trace_ray(fragVolumeStart, ubo.camera_pos, clamped_pos - ubo.camera_pos, pos_infinity, 0, max_iterations_per_light, false); float opacity = float(color_roughness.w) / 255.0; if (t.has_hit) { - vec3 color_seen_through = diffuse_tracing(t.end_volume, t.end_raster, t.end_pos, t.end_facing) * orig_color_sample; + vec3 color_seen_through = diffuse_tracing(t.end_volume, t.end_raster, t.end_pos, t.end_facing) * orig_color_sample * t.color_mul; vec3 color_direct = diffuse_tracing(fragVolumeStart, fragRasterPos, clamped_pos, facing); color_sum = opacity * color_direct + (1.0 - opacity) * color_seen_through; } @@ -417,8 +464,15 @@ void main() { } else { color_sum = diffuse_tracing(fragVolumeStart, fragRasterPos, clamped_pos, facing); - } + vec3 reflection_direction = reflect_vector(normalize(clamped_pos - ubo.camera_pos), facing); + Tracing reflection_tracing = trace_ray(fragVolumeStart, clamped_pos, reflection_direction, pos_infinity, 0, max_iterations_per_light, true); + float reflectivity = 1.0 - float(color_roughness.w) / 255.0; + if (reflection_tracing.has_hit || reflection_tracing.has_transparent_hit) { + vec3 color_from_reflection = diffuse_tracing(reflection_tracing.end_volume, reflection_tracing.end_raster, reflection_tracing.end_pos, reflection_tracing.end_facing) * orig_color_sample; + color_sum = color_sum * (1.0 - reflectivity) + color_from_reflection * reflectivity; + } + } outColor = vec4(color_sum, 1.0); } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8da19cf..b5a7931 100644 --- a/src/main.rs +++ b/src/main.rs @@ -180,7 +180,7 @@ impl App { data.use_geometry_shader = false; data.num_lights_per_volume = 2; data.max_iterations_per_light = 20; - data.diffuse_raster_steps = 2; + data.diffuse_raster_steps = 0; data.diffuse_raster_size = 0.01; data.max_recursive_rays = 10; data.diffuse_rays_per_hit = 1; diff --git a/src/scene/empty_volume.rs b/src/scene/empty_volume.rs index 1357e0a..4c36e55 100644 --- a/src/scene/empty_volume.rs +++ b/src/scene/empty_volume.rs @@ -66,9 +66,12 @@ impl EmptyVolume { let start_time = Instant::now(); // iterate over all block positions in the oct tree let mut check_its = 0; - for x_index in 0..tree.size { - for y_index in 0..tree.size { - for z_index in 0..tree.size { + let mut x_index = 0; + while x_index < tree.size { + let mut y_index = 0; + while y_index < tree.size { + let mut z_index = 0; + while z_index < tree.size { // check if there is a block at that position let query_result = tree.test_element(x_index, y_index, z_index); let mut transparent = false; @@ -86,6 +89,7 @@ impl EmptyVolume { for volume in &volumes { if volume.borrow().contains(&Vector3{x: x_index, y: y_index, z: z_index}) { contained = true; + z_index = volume.borrow().size_z + volume.borrow().position.z; break; } } @@ -479,9 +483,12 @@ impl EmptyVolume { println!("new volume done"); //push to the list volumes.push(reference); - } + } + z_index += 1 } + y_index += 1; } + x_index += 1; } println!("Did {} oct tree checks!", check_its); println!("add the neighbor linkage for all the volumes of the oct tree"); diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 1927171..f5a70da 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -73,7 +73,7 @@ impl Scene { color: vec3(shade, 1.0, shade), tex_coord: vec2(0.0, 0.0), transparent: false, - roughness: 128, + roughness: 0, }; oct_tree.set_cube(cube.clone()); @@ -83,19 +83,19 @@ impl Scene { let shade = (rng.gen_range(0..25) as f32) / 100.0; let cube = Cube { pos: vec3(10.0, 10.0, 10.0), - color: vec3(1.0, 0.0, 0.0), + color: vec3(1.0, 1.0, 1.0), tex_coord: vec2(0.0, 0.0), - transparent: true, - roughness: 32, + transparent: false, + roughness: 0, }; oct_tree.set_cube(cube.clone()); let cube = Cube { pos: vec3(10.0, 10.0, 9.0), - color: vec3(1.0, 0.0, 0.0), + color: vec3(1.0, 1.0, 1.0), tex_coord: vec2(0.0, 0.0), - transparent: true, - roughness: 32, + transparent: false, + roughness: 0, }; oct_tree.set_cube(cube.clone());