diff --git a/shaders/compiled/frag_rt_quad.spv b/shaders/compiled/frag_rt_quad.spv index 2cb5167..ed483a0 100644 Binary files a/shaders/compiled/frag_rt_quad.spv and b/shaders/compiled/frag_rt_quad.spv differ diff --git a/shaders/rt_lib.frag b/shaders/rt_lib.frag index bc293db..e2acfd1 100644 --- a/shaders/rt_lib.frag +++ b/shaders/rt_lib.frag @@ -36,7 +36,8 @@ float pos_infinity = uintBitsToFloat(0x7F800000); // set limit for maximal iterations uint max_iterations = max_num_lights * max_iterations_per_light * raster_points; uint iteration_num = 0; -uint max_num_compounds = scene_info.infos[6]; +const uint absolute_max_compounds = 10; +uint max_num_compounds = min(scene_info.infos[6], absolute_max_compounds); uvec4 unpack_color(uint val) { // left most 8 bits first @@ -311,20 +312,39 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl vec3 color_mul_transparent; uint next_volumetric_index = 0; - uint[5] done_volumetrics; - for (int i=0; i < 5; i++) { + uint[absolute_max_compounds] done_volumetrics; + for (int i=0; i < max_num_compounds; i++) { done_volumetrics[i] = 0; } + uint[absolute_max_compounds] compound_starts; + float[absolute_max_compounds] hit_factors; + bool[absolute_max_compounds] is_x_hits; + bool[absolute_max_compounds] is_y_hits; + bool[absolute_max_compounds] is_z_hits; + bool[absolute_max_compounds] hits_inside; + while (iteration_num < max_iterations) { iteration_num ++; + for (int i=0; i < max_num_compounds; i++) { + compound_starts[i] = 0; + hit_factors[i] = 0.0; + is_x_hits[i] = false; + is_y_hits[i] = false; + is_z_hits[i] = false; + hits_inside[i] = false; + } + uint compound_num = 0; + // go over the borders by this amount + float overstep = 0.00001 / length(direction); + uint hits = 0; while (scene_info.infos[volume_index + 6 + max_num_lights + compound_num] != 0 && compound_num < max_num_compounds && iteration_num < max_iterations && !result.has_hit) { uint compound_start = scene_info.infos[volume_index + 6 + max_num_lights + compound_num]; bool already_checked = false; - for (int i=0; i < 5; i++) { + for (int i=0; i < max_num_compounds; i++) { if (compound_start == done_volumetrics[i]) { already_checked = true; break; @@ -334,8 +354,6 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl compound_num += 1; continue; } - done_volumetrics[next_volumetric_index] = compound_start; - next_volumetric_index = (next_volumetric_index + 1) % 5; //iteration_num ++; uint oct_tree_index = compounds[compound_start + 8]; @@ -347,9 +365,6 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl float y_border = compound_pos.y + float((compound_grid_size) * uint(!y_pos)) * compound_scale; float z_border = compound_pos.z + float((compound_grid_size) * uint(!z_pos)) * compound_scale; - // go over the borders by this amount - float overstep = 0.00001 / length(direction); - if (!x_null) { x_factor = (x_border - pos.x) / direction.x; } else { @@ -369,15 +384,18 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl y_factor += overstep; z_factor += overstep; - vec3 intersection_pos = pos; + vec3 intersection_pos = pos + 10.0 * overstep * direction; bool is_x_hit = false; bool is_y_hit = false; bool is_z_hit = false; bool hit_inside = false; + float hit_factor; + // check that either the hit is in range or we are inside of the compound from the start if ((compound_pos.x <= intersection_pos.x && intersection_pos.x <= compound_pos.x + float(compound_grid_size) * compound_scale) && (compound_pos.y <= intersection_pos.y && intersection_pos.y <= compound_pos.y + float(compound_grid_size) * compound_scale) && (compound_pos.z <= intersection_pos.z && intersection_pos.z <= compound_pos.z + float(compound_grid_size) * compound_scale)){ - //hit_inside = true; + hit_inside = true; + hit_factor = 10.0 * overstep; } else { vec3 intersection_pos_x = pos + x_factor * direction; vec3 intersection_pos_y = pos + y_factor * direction; @@ -388,6 +406,7 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl hit_inside = true; is_x_hit = true; intersection_pos = intersection_pos_x; + hit_factor = x_factor; } if ((compound_pos.x <= intersection_pos_y.x && intersection_pos_y.x <= compound_pos.x + float(compound_grid_size) * compound_scale) && @@ -396,6 +415,7 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl hit_inside = true; is_y_hit = true; intersection_pos = intersection_pos_y; + hit_factor = y_factor; } if ((compound_pos.x <= intersection_pos_z.x && intersection_pos_z.x <= compound_pos.x + float(compound_grid_size) * compound_scale) && @@ -404,149 +424,185 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl hit_inside = true; is_z_hit = true; intersection_pos = intersection_pos_z; + hit_factor = z_factor; } } - // check that either the hit is in range or we are inside of the compound from the start - if (hit_inside) { - vec3 oct_tree_pos = vec3(compound_pos); - uint current_size = compound_grid_size; - vec3 mid_point = oct_tree_pos + float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale); - bool children_open[8] = {true, true, true, true, true, true, true, true}; - uint oct_tree_address = oct_tree_index; - // iterate through the oct_tree - uint check_it = 0; - uint max_check_it = 60; - uint prev_child = 0; - uint prev_prev_child = 0; + compound_starts[hits] = compound_start; + hit_factors[hits] = hit_factor; + is_x_hits[hits] = is_x_hit; + is_y_hits[hits] = is_y_hit; + is_z_hits[hits] = is_z_hit; + hits_inside[hits] = hit_inside; + hits += 1 * uint(hit_inside); - uvec3 grid_pos = uvec3(0, 0, 0); - uvec3 parent_pos = uvec3(0, 0, 0); - - bool has_moved = false; - while (!result.has_hit && check_it < max_check_it) { - // failsafe to get out in case has_moved runs into an accuracy issue - check_it ++; - oct_tree_pos = vec3(grid_pos) * compound_scale + compound_pos; - mid_point = oct_tree_pos + (float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale)); - - uint child_index = next_oct_tree_child(mid_point, intersection_pos, children_open); - if (child_index == 0) { - // go up to parent - // if parent is 0 abort, as we have reached the root node again and try to exit it - if (oct_tree_mem[oct_tree_address] == 0) { - break; - } - for (int i=0; i < 8; i++) { - children_open[i] = true; - } - uint parent_index = oct_tree_mem[oct_tree_address]; - // check which child we came from - child_index = 1 * uint(oct_tree_address == oct_tree_mem[parent_index + 1]) + 2 * uint(oct_tree_address == oct_tree_mem[parent_index + 2]) + 3 * uint(oct_tree_address == oct_tree_mem[parent_index + 3]) + 4 * uint(oct_tree_address == oct_tree_mem[parent_index + 4]) + 5 * uint(oct_tree_address == oct_tree_mem[parent_index + 5]) + 6 * uint(oct_tree_address == oct_tree_mem[parent_index + 6]) + 7 * uint(oct_tree_address == oct_tree_mem[parent_index + 7]) + 8 * uint(oct_tree_address == oct_tree_mem[parent_index + 8]); - // mark as done to avoid reinvestigating, since intersection_pos is on its edge - children_open[child_index - 1] = false; - prev_prev_child = prev_child; - prev_child = oct_tree_address; - - uvec3 back_vec = parent_child_vec(current_size, child_index); - grid_pos -= parent_child_vec(current_size, child_index); - current_size *= 2; - oct_tree_address = parent_index; - } else { - // go down into child - if (current_size == 2) { - // check block if hit break - if (oct_tree_mem[oct_tree_address + child_index] != 0) { - result.has_hit = true; - result.end_color = unpack_color(oct_tree_mem[oct_tree_address + child_index]); - break; - } - } else { - // check if the child has content, else skip to next child of current parent - uint x = oct_tree_mem[oct_tree_address + child_index]; - if (oct_tree_mem[x] != 0) { - // change base address and position to child - current_size /= 2; - oct_tree_address = x; - grid_pos += parent_child_vec(current_size, child_index); - for (int i=0; i < 8; i++) { - children_open[i] = true; - } - continue; - } - } - children_open[child_index - 1] = false; - - // we did not go deeper or had a hit, so intersection pos needs to be updated - // new intersection pos calc - vec3 offset = vec3(parent_child_vec(current_size / 2, child_index)) * compound_scale; - vec3 low = oct_tree_pos + offset; - float x_border = low.x + float((compound_scale * current_size / 2) * uint(x_pos)); - float y_border = low.y + float((compound_scale * current_size / 2) * uint(y_pos)); - float z_border = low.z + float((compound_scale * current_size / 2) * uint(z_pos)); - - if (!x_null) { - x_factor = (x_border - pos.x) / direction.x; - if (x_factor <= 0.0) { - x_factor = max_factor; - } - } else { - x_factor = max_factor; - } - if (!y_null) { - y_factor = (y_border - pos.y) / direction.y; - if (y_factor <= 0.0) { - y_factor = max_factor; - } - } else { - y_factor = max_factor; - } - if (!z_null) { - z_factor = (z_border - pos.z) / direction.z; - if (z_factor <= 0.0) { - z_factor = max_factor; - } - } else { - z_factor = max_factor; - } - float smallest_factor = min(min(x_factor, y_factor), z_factor); - - if (x_factor == smallest_factor) { - is_x_hit = true; - is_y_hit = false; - is_z_hit = false; - } - if (y_factor == smallest_factor) { - is_x_hit = false; - is_y_hit = true; - is_z_hit = false; - } - if (z_factor == smallest_factor) { - is_x_hit = false; - is_y_hit = false; - is_z_hit = true; - } - - // move a bit further to fully enter the next quadrant - smallest_factor += overstep; - - //has_moved = length(intersection_pos - (pos + smallest_factor * direction)) >= 0.00001; - has_moved = intersection_pos != (pos + smallest_factor * direction); - intersection_pos = pos + smallest_factor * direction; - } - } - - uint hit_facing = uint(is_x_hit) * (2 + uint(x_pos)) + uint(is_y_hit) * (4 + uint(y_pos)) + uint(is_z_hit && !z_pos); - //result.has_hit = true; - result.end_pos = intersection_pos; - result.end_facing = hit_facing; - result.end_volume = volume_index; - result.end_direction = direction; - } + done_volumetrics[next_volumetric_index] = compound_start; + next_volumetric_index = (next_volumetric_index + 1) % max_num_compounds; compound_num += 1; } + for (int i =0; i < hits; i++) { + if (result.has_hit) { + break; + } + // find encounters in order + float min_factor = max_factor; + uint min_index = 0; + for (int j = 0; j < hits; j++) { + if (hit_factors[j] < min_factor) { + min_factor = hit_factors[j]; + min_index = j; + } + } + // set up the compound + uint compound_start = compound_starts[min_index]; + bool is_x_hit = is_x_hits[min_index]; + bool is_y_hit = is_y_hits[min_index]; + bool is_z_hit = is_z_hits[min_index]; + uint oct_tree_index = compounds[compound_start + 8]; + uint compound_grid_size = compounds[compound_start]; + float compound_scale = uintBitsToFloat(compounds[compound_start + 1]); + vec3 compound_pos = vec3(uintBitsToFloat(compounds[compound_start + 5]), uintBitsToFloat(compounds[compound_start + 6]), uintBitsToFloat(compounds[compound_start + 7])); + vec3 intersection_pos = pos + hit_factors[min_index] * direction; + // invalidate the min found + hit_factors[min_index] = max_factor; + + vec3 oct_tree_pos = vec3(compound_pos); + uint current_size = compound_grid_size; + vec3 mid_point = oct_tree_pos + float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale); + bool children_open[8] = {true, true, true, true, true, true, true, true}; + uint oct_tree_address = oct_tree_index; + // iterate through the oct_tree + uint check_it = 0; + uint max_check_it = 60; + uint prev_child = 0; + uint prev_prev_child = 0; + + uvec3 grid_pos = uvec3(0, 0, 0); + uvec3 parent_pos = uvec3(0, 0, 0); + + bool has_moved = false; + while (!result.has_hit && check_it < max_check_it) { + // failsafe to get out in case has_moved runs into an accuracy issue + check_it ++; + oct_tree_pos = vec3(grid_pos) * compound_scale + compound_pos; + mid_point = oct_tree_pos + (float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale)); + + uint child_index = next_oct_tree_child(mid_point, intersection_pos, children_open); + if (child_index == 0) { + // go up to parent + // if parent is 0 abort, as we have reached the root node again and try to exit it + if (oct_tree_mem[oct_tree_address] == 0) { + break; + } + for (int i=0; i < 8; i++) { + children_open[i] = true; + } + uint parent_index = oct_tree_mem[oct_tree_address]; + // check which child we came from + child_index = 1 * uint(oct_tree_address == oct_tree_mem[parent_index + 1]) + 2 * uint(oct_tree_address == oct_tree_mem[parent_index + 2]) + 3 * uint(oct_tree_address == oct_tree_mem[parent_index + 3]) + 4 * uint(oct_tree_address == oct_tree_mem[parent_index + 4]) + 5 * uint(oct_tree_address == oct_tree_mem[parent_index + 5]) + 6 * uint(oct_tree_address == oct_tree_mem[parent_index + 6]) + 7 * uint(oct_tree_address == oct_tree_mem[parent_index + 7]) + 8 * uint(oct_tree_address == oct_tree_mem[parent_index + 8]); + // mark as done to avoid reinvestigating, since intersection_pos is on its edge + children_open[child_index - 1] = false; + prev_prev_child = prev_child; + prev_child = oct_tree_address; + + uvec3 back_vec = parent_child_vec(current_size, child_index); + grid_pos -= parent_child_vec(current_size, child_index); + current_size *= 2; + oct_tree_address = parent_index; + } else { + // go down into child + if (current_size == 2) { + // check block if hit break + if (oct_tree_mem[oct_tree_address + child_index] != 0) { + result.has_hit = true; + result.end_color = unpack_color(oct_tree_mem[oct_tree_address + child_index]); + break; + } + } else { + // check if the child has content, else skip to next child of current parent + uint x = oct_tree_mem[oct_tree_address + child_index]; + if (oct_tree_mem[x] != 0) { + // change base address and position to child + current_size /= 2; + oct_tree_address = x; + grid_pos += parent_child_vec(current_size, child_index); + for (int i=0; i < 8; i++) { + children_open[i] = true; + } + continue; + } + } + children_open[child_index - 1] = false; + + // we did not go deeper or had a hit, so intersection pos needs to be updated + // new intersection pos calc + vec3 offset = vec3(parent_child_vec(current_size / 2, child_index)) * compound_scale; + vec3 low = oct_tree_pos + offset; + float x_border = low.x + float((compound_scale * current_size / 2) * uint(x_pos)); + float y_border = low.y + float((compound_scale * current_size / 2) * uint(y_pos)); + float z_border = low.z + float((compound_scale * current_size / 2) * uint(z_pos)); + + if (!x_null) { + x_factor = (x_border - pos.x) / direction.x; + if (x_factor <= 0.0) { + x_factor = max_factor; + } + } else { + x_factor = max_factor; + } + if (!y_null) { + y_factor = (y_border - pos.y) / direction.y; + if (y_factor <= 0.0) { + y_factor = max_factor; + } + } else { + y_factor = max_factor; + } + if (!z_null) { + z_factor = (z_border - pos.z) / direction.z; + if (z_factor <= 0.0) { + z_factor = max_factor; + } + } else { + z_factor = max_factor; + } + float smallest_factor = min(min(x_factor, y_factor), z_factor); + + if (x_factor == smallest_factor) { + is_x_hit = true; + is_y_hit = false; + is_z_hit = false; + } + if (y_factor == smallest_factor) { + is_x_hit = false; + is_y_hit = true; + is_z_hit = false; + } + if (z_factor == smallest_factor) { + is_x_hit = false; + is_y_hit = false; + is_z_hit = true; + } + + // move a bit further to fully enter the next quadrant + smallest_factor += overstep; + + //has_moved = length(intersection_pos - (pos + smallest_factor * direction)) >= 0.00001; + has_moved = intersection_pos != (pos + smallest_factor * direction); + intersection_pos = pos + smallest_factor * direction; + } + } + + uint hit_facing = uint(is_x_hit) * (2 + uint(x_pos)) + uint(is_y_hit) * (4 + uint(y_pos)) + uint(is_z_hit && !z_pos); + //result.has_hit = true; + result.end_pos = intersection_pos; + result.end_facing = hit_facing; + result.end_volume = volume_index; + result.end_direction = direction; + } + if (result.has_hit) { break; } @@ -667,6 +723,11 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl z_pos = direction.z > 0.0; z_null = (direction.z == 0.0); + + // clear volumetrics for reevaluation + for (int i=0; i < max_num_compounds; i++) { + done_volumetrics[i] = 0; + } } else { break; } diff --git a/shaders/rt_quad.frag b/shaders/rt_quad.frag index d5f4a7b..5fad61a 100644 --- a/shaders/rt_quad.frag +++ b/shaders/rt_quad.frag @@ -47,7 +47,8 @@ float pos_infinity = uintBitsToFloat(0x7F800000); // set limit for maximal iterations uint max_iterations = max_num_lights * max_iterations_per_light * raster_points; uint iteration_num = 0; -uint max_num_compounds = scene_info.infos[6]; +const uint absolute_max_compounds = 10; +uint max_num_compounds = min(scene_info.infos[6], absolute_max_compounds); uvec4 unpack_color(uint val) { // left most 8 bits first @@ -322,20 +323,40 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl vec3 color_mul_transparent; uint next_volumetric_index = 0; - uint[5] done_volumetrics; - for (int i=0; i < 5; i++) { + uint[absolute_max_compounds] done_volumetrics; + for (int i=0; i < max_num_compounds; i++) { done_volumetrics[i] = 0; } + uint[absolute_max_compounds] compound_starts; + float[absolute_max_compounds] hit_factors; + bool[absolute_max_compounds] is_x_hits; + bool[absolute_max_compounds] is_y_hits; + bool[absolute_max_compounds] is_z_hits; + bool[absolute_max_compounds] hits_inside; + while (iteration_num < max_iterations) { iteration_num ++; + for (int i=0; i < max_num_compounds; i++) { + compound_starts[i] = 0; + hit_factors[i] = 0.0; + is_x_hits[i] = false; + is_y_hits[i] = false; + is_z_hits[i] = false; + hits_inside[i] = false; + } + uint compound_num = 0; + // go over the borders by this amount + float overstep = 0.00001 / length(direction); + uint hits = 0; + // todo needs depth ordering of volumetrics inside of the volume while (scene_info.infos[volume_index + 6 + max_num_lights + compound_num] != 0 && compound_num < max_num_compounds && iteration_num < max_iterations && !result.has_hit) { uint compound_start = scene_info.infos[volume_index + 6 + max_num_lights + compound_num]; bool already_checked = false; - for (int i=0; i < 5; i++) { + for (int i=0; i < max_num_compounds; i++) { if (compound_start == done_volumetrics[i]) { already_checked = true; break; @@ -345,8 +366,6 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl compound_num += 1; continue; } - done_volumetrics[next_volumetric_index] = compound_start; - next_volumetric_index = (next_volumetric_index + 1) % 5; //iteration_num ++; uint oct_tree_index = compounds[compound_start + 8]; @@ -358,9 +377,6 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl float y_border = compound_pos.y + float((compound_grid_size) * uint(!y_pos)) * compound_scale; float z_border = compound_pos.z + float((compound_grid_size) * uint(!z_pos)) * compound_scale; - // go over the borders by this amount - float overstep = 0.00001 / length(direction); - if (!x_null) { x_factor = (x_border - pos.x) / direction.x; } else { @@ -380,15 +396,18 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl y_factor += overstep; z_factor += overstep; - vec3 intersection_pos = pos; + vec3 intersection_pos = pos + 10.0 * overstep * direction; bool is_x_hit = false; bool is_y_hit = false; bool is_z_hit = false; bool hit_inside = false; + float hit_factor; + // check that either the hit is in range or we are inside of the compound from the start if ((compound_pos.x <= intersection_pos.x && intersection_pos.x <= compound_pos.x + float(compound_grid_size) * compound_scale) && (compound_pos.y <= intersection_pos.y && intersection_pos.y <= compound_pos.y + float(compound_grid_size) * compound_scale) && (compound_pos.z <= intersection_pos.z && intersection_pos.z <= compound_pos.z + float(compound_grid_size) * compound_scale)){ - //hit_inside = true; + hit_inside = true; + hit_factor = 10.0 * overstep; } else { vec3 intersection_pos_x = pos + x_factor * direction; vec3 intersection_pos_y = pos + y_factor * direction; @@ -399,6 +418,7 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl hit_inside = true; is_x_hit = true; intersection_pos = intersection_pos_x; + hit_factor = x_factor; } if ((compound_pos.x <= intersection_pos_y.x && intersection_pos_y.x <= compound_pos.x + float(compound_grid_size) * compound_scale) && @@ -407,6 +427,7 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl hit_inside = true; is_y_hit = true; intersection_pos = intersection_pos_y; + hit_factor = y_factor; } if ((compound_pos.x <= intersection_pos_z.x && intersection_pos_z.x <= compound_pos.x + float(compound_grid_size) * compound_scale) && @@ -415,149 +436,185 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl hit_inside = true; is_z_hit = true; intersection_pos = intersection_pos_z; + hit_factor = z_factor; } } - // check that either the hit is in range or we are inside of the compound from the start - if (hit_inside) { - vec3 oct_tree_pos = vec3(compound_pos); - uint current_size = compound_grid_size; - vec3 mid_point = oct_tree_pos + float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale); - bool children_open[8] = {true, true, true, true, true, true, true, true}; - uint oct_tree_address = oct_tree_index; - // iterate through the oct_tree - uint check_it = 0; - uint max_check_it = 60; - uint prev_child = 0; - uint prev_prev_child = 0; + compound_starts[hits] = compound_start; + hit_factors[hits] = hit_factor; + is_x_hits[hits] = is_x_hit; + is_y_hits[hits] = is_y_hit; + is_z_hits[hits] = is_z_hit; + hits_inside[hits] = hit_inside; + hits += 1 * uint(hit_inside); - uvec3 grid_pos = uvec3(0, 0, 0); - uvec3 parent_pos = uvec3(0, 0, 0); - - bool has_moved = false; - while (!result.has_hit && check_it < max_check_it) { - // failsafe to get out in case has_moved runs into an accuracy issue - check_it ++; - oct_tree_pos = vec3(grid_pos) * compound_scale + compound_pos; - mid_point = oct_tree_pos + (float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale)); - - uint child_index = next_oct_tree_child(mid_point, intersection_pos, children_open); - if (child_index == 0) { - // go up to parent - // if parent is 0 abort, as we have reached the root node again and try to exit it - if (oct_tree_mem[oct_tree_address] == 0) { - break; - } - for (int i=0; i < 8; i++) { - children_open[i] = true; - } - uint parent_index = oct_tree_mem[oct_tree_address]; - // check which child we came from - child_index = 1 * uint(oct_tree_address == oct_tree_mem[parent_index + 1]) + 2 * uint(oct_tree_address == oct_tree_mem[parent_index + 2]) + 3 * uint(oct_tree_address == oct_tree_mem[parent_index + 3]) + 4 * uint(oct_tree_address == oct_tree_mem[parent_index + 4]) + 5 * uint(oct_tree_address == oct_tree_mem[parent_index + 5]) + 6 * uint(oct_tree_address == oct_tree_mem[parent_index + 6]) + 7 * uint(oct_tree_address == oct_tree_mem[parent_index + 7]) + 8 * uint(oct_tree_address == oct_tree_mem[parent_index + 8]); - // mark as done to avoid reinvestigating, since intersection_pos is on its edge - children_open[child_index - 1] = false; - prev_prev_child = prev_child; - prev_child = oct_tree_address; - - uvec3 back_vec = parent_child_vec(current_size, child_index); - grid_pos -= parent_child_vec(current_size, child_index); - current_size *= 2; - oct_tree_address = parent_index; - } else { - // go down into child - if (current_size == 2) { - // check block if hit break - if (oct_tree_mem[oct_tree_address + child_index] != 0) { - result.has_hit = true; - result.end_color = unpack_color(oct_tree_mem[oct_tree_address + child_index]); - break; - } - } else { - // check if the child has content, else skip to next child of current parent - uint x = oct_tree_mem[oct_tree_address + child_index]; - if (oct_tree_mem[x] != 0) { - // change base address and position to child - current_size /= 2; - oct_tree_address = x; - grid_pos += parent_child_vec(current_size, child_index); - for (int i=0; i < 8; i++) { - children_open[i] = true; - } - continue; - } - } - children_open[child_index - 1] = false; - - // we did not go deeper or had a hit, so intersection pos needs to be updated - // new intersection pos calc - vec3 offset = vec3(parent_child_vec(current_size / 2, child_index)) * compound_scale; - vec3 low = oct_tree_pos + offset; - float x_border = low.x + float((compound_scale * current_size / 2) * uint(x_pos)); - float y_border = low.y + float((compound_scale * current_size / 2) * uint(y_pos)); - float z_border = low.z + float((compound_scale * current_size / 2) * uint(z_pos)); - - if (!x_null) { - x_factor = (x_border - pos.x) / direction.x; - if (x_factor <= 0.0) { - x_factor = max_factor; - } - } else { - x_factor = max_factor; - } - if (!y_null) { - y_factor = (y_border - pos.y) / direction.y; - if (y_factor <= 0.0) { - y_factor = max_factor; - } - } else { - y_factor = max_factor; - } - if (!z_null) { - z_factor = (z_border - pos.z) / direction.z; - if (z_factor <= 0.0) { - z_factor = max_factor; - } - } else { - z_factor = max_factor; - } - float smallest_factor = min(min(x_factor, y_factor), z_factor); - - if (x_factor == smallest_factor) { - is_x_hit = true; - is_y_hit = false; - is_z_hit = false; - } - if (y_factor == smallest_factor) { - is_x_hit = false; - is_y_hit = true; - is_z_hit = false; - } - if (z_factor == smallest_factor) { - is_x_hit = false; - is_y_hit = false; - is_z_hit = true; - } - - // move a bit further to fully enter the next quadrant - smallest_factor += overstep; - - //has_moved = length(intersection_pos - (pos + smallest_factor * direction)) >= 0.00001; - has_moved = intersection_pos != (pos + smallest_factor * direction); - intersection_pos = pos + smallest_factor * direction; - } - } - - uint hit_facing = uint(is_x_hit) * (2 + uint(x_pos)) + uint(is_y_hit) * (4 + uint(y_pos)) + uint(is_z_hit && !z_pos); - //result.has_hit = true; - result.end_pos = intersection_pos; - result.end_facing = hit_facing; - result.end_volume = volume_index; - result.end_direction = direction; - } + done_volumetrics[next_volumetric_index] = compound_start; + next_volumetric_index = (next_volumetric_index + 1) % max_num_compounds; compound_num += 1; } + for (int i =0; i < hits; i++) { + if (result.has_hit) { + break; + } + // find encounters in order + float min_factor = max_factor; + uint min_index = 0; + for (int j = 0; j < hits; j++) { + if (hit_factors[j] < min_factor) { + min_factor = hit_factors[j]; + min_index = j; + } + } + // set up the compound + uint compound_start = compound_starts[min_index]; + bool is_x_hit = is_x_hits[min_index]; + bool is_y_hit = is_y_hits[min_index]; + bool is_z_hit = is_z_hits[min_index]; + uint oct_tree_index = compounds[compound_start + 8]; + uint compound_grid_size = compounds[compound_start]; + float compound_scale = uintBitsToFloat(compounds[compound_start + 1]); + vec3 compound_pos = vec3(uintBitsToFloat(compounds[compound_start + 5]), uintBitsToFloat(compounds[compound_start + 6]), uintBitsToFloat(compounds[compound_start + 7])); + vec3 intersection_pos = pos + hit_factors[min_index] * direction; + // invalidate the min found + hit_factors[min_index] = max_factor; + + vec3 oct_tree_pos = vec3(compound_pos); + uint current_size = compound_grid_size; + vec3 mid_point = oct_tree_pos + float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale); + bool children_open[8] = {true, true, true, true, true, true, true, true}; + uint oct_tree_address = oct_tree_index; + // iterate through the oct_tree + uint check_it = 0; + uint max_check_it = 60; + uint prev_child = 0; + uint prev_prev_child = 0; + + uvec3 grid_pos = uvec3(0, 0, 0); + uvec3 parent_pos = uvec3(0, 0, 0); + + bool has_moved = false; + while (!result.has_hit && check_it < max_check_it) { + // failsafe to get out in case has_moved runs into an accuracy issue + check_it ++; + oct_tree_pos = vec3(grid_pos) * compound_scale + compound_pos; + mid_point = oct_tree_pos + (float(current_size / 2) * vec3(compound_scale, compound_scale, compound_scale)); + + uint child_index = next_oct_tree_child(mid_point, intersection_pos, children_open); + if (child_index == 0) { + // go up to parent + // if parent is 0 abort, as we have reached the root node again and try to exit it + if (oct_tree_mem[oct_tree_address] == 0) { + break; + } + for (int i=0; i < 8; i++) { + children_open[i] = true; + } + uint parent_index = oct_tree_mem[oct_tree_address]; + // check which child we came from + child_index = 1 * uint(oct_tree_address == oct_tree_mem[parent_index + 1]) + 2 * uint(oct_tree_address == oct_tree_mem[parent_index + 2]) + 3 * uint(oct_tree_address == oct_tree_mem[parent_index + 3]) + 4 * uint(oct_tree_address == oct_tree_mem[parent_index + 4]) + 5 * uint(oct_tree_address == oct_tree_mem[parent_index + 5]) + 6 * uint(oct_tree_address == oct_tree_mem[parent_index + 6]) + 7 * uint(oct_tree_address == oct_tree_mem[parent_index + 7]) + 8 * uint(oct_tree_address == oct_tree_mem[parent_index + 8]); + // mark as done to avoid reinvestigating, since intersection_pos is on its edge + children_open[child_index - 1] = false; + prev_prev_child = prev_child; + prev_child = oct_tree_address; + + uvec3 back_vec = parent_child_vec(current_size, child_index); + grid_pos -= parent_child_vec(current_size, child_index); + current_size *= 2; + oct_tree_address = parent_index; + } else { + // go down into child + if (current_size == 2) { + // check block if hit break + if (oct_tree_mem[oct_tree_address + child_index] != 0) { + result.has_hit = true; + result.end_color = unpack_color(oct_tree_mem[oct_tree_address + child_index]); + break; + } + } else { + // check if the child has content, else skip to next child of current parent + uint x = oct_tree_mem[oct_tree_address + child_index]; + if (oct_tree_mem[x] != 0) { + // change base address and position to child + current_size /= 2; + oct_tree_address = x; + grid_pos += parent_child_vec(current_size, child_index); + for (int i=0; i < 8; i++) { + children_open[i] = true; + } + continue; + } + } + children_open[child_index - 1] = false; + + // we did not go deeper or had a hit, so intersection pos needs to be updated + // new intersection pos calc + vec3 offset = vec3(parent_child_vec(current_size / 2, child_index)) * compound_scale; + vec3 low = oct_tree_pos + offset; + float x_border = low.x + float((compound_scale * current_size / 2) * uint(x_pos)); + float y_border = low.y + float((compound_scale * current_size / 2) * uint(y_pos)); + float z_border = low.z + float((compound_scale * current_size / 2) * uint(z_pos)); + + if (!x_null) { + x_factor = (x_border - pos.x) / direction.x; + if (x_factor <= 0.0) { + x_factor = max_factor; + } + } else { + x_factor = max_factor; + } + if (!y_null) { + y_factor = (y_border - pos.y) / direction.y; + if (y_factor <= 0.0) { + y_factor = max_factor; + } + } else { + y_factor = max_factor; + } + if (!z_null) { + z_factor = (z_border - pos.z) / direction.z; + if (z_factor <= 0.0) { + z_factor = max_factor; + } + } else { + z_factor = max_factor; + } + float smallest_factor = min(min(x_factor, y_factor), z_factor); + + if (x_factor == smallest_factor) { + is_x_hit = true; + is_y_hit = false; + is_z_hit = false; + } + if (y_factor == smallest_factor) { + is_x_hit = false; + is_y_hit = true; + is_z_hit = false; + } + if (z_factor == smallest_factor) { + is_x_hit = false; + is_y_hit = false; + is_z_hit = true; + } + + // move a bit further to fully enter the next quadrant + smallest_factor += overstep; + + //has_moved = length(intersection_pos - (pos + smallest_factor * direction)) >= 0.00001; + has_moved = intersection_pos != (pos + smallest_factor * direction); + intersection_pos = pos + smallest_factor * direction; + } + } + + uint hit_facing = uint(is_x_hit) * (2 + uint(x_pos)) + uint(is_y_hit) * (4 + uint(y_pos)) + uint(is_z_hit && !z_pos); + //result.has_hit = true; + result.end_pos = intersection_pos; + result.end_facing = hit_facing; + result.end_volume = volume_index; + result.end_direction = direction; + } + if (result.has_hit) { break; } @@ -678,6 +735,11 @@ Tracing trace_ray(uint volume_start, vec3 starting_pos, vec3 start_direction, fl z_pos = direction.z > 0.0; z_null = (direction.z == 0.0); + + // clear volumetrics for reevaluation + for (int i=0; i < max_num_compounds; i++) { + done_volumetrics[i] = 0; + } } else { break; }