diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv index e101526..af2c27e 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 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());