Wiseguy's fixed raycast traversal (#681)

* wiseguy's fixed raycast traversal

* Use while (TRUE) { for the sake of repo consistency
This commit is contained in:
thecozies
2023-09-18 08:40:37 -05:00
committed by GitHub
parent 63ddb28641
commit c3f300be9f

View File

@@ -1277,8 +1277,6 @@ s32 anim_spline_poll(Vec3f result) {
* RAYCASTING *
**************************************************/
#define RAY_STEPS 4 /* How many steps to do when casting rays, default to quartersteps. */
/**
* @brief Checks if a ray intersects a surface using MöllerTrumbore intersection algorithm.
*
@@ -1399,8 +1397,6 @@ void find_surface_on_ray_cell(s32 cellX, s32 cellZ, Vec3f orig, Vec3f normalized
f32 find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags) {
Vec3f normalized_dir;
f32 step;
s32 i;
const f32 invcell = 1.0f / CELL_SIZE;
PUPPYPRINT_ADD_COUNTER(gPuppyCallCounter.collision_raycast);
@@ -1414,46 +1410,47 @@ f32 find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec
vec3f_copy(normalized_dir, dir);
vec3f_normalize(normalized_dir);
// Get our cell coordinate
f32 fCellX = (orig[0] + LEVEL_BOUNDARY_MAX) * invcell;
f32 fCellZ = (orig[2] + LEVEL_BOUNDARY_MAX) * invcell;
s32 cellX = fCellX;
s32 cellZ = fCellZ;
s32 cellPrevX = cellX;
s32 cellPrevZ = cellZ;
// Get the start and end coords converted to cell-space
f32 start_cell_coord_x = (orig[0] + LEVEL_BOUNDARY_MAX) * invcell;
f32 start_cell_coord_z = (orig[2] + LEVEL_BOUNDARY_MAX) * invcell;
f32 end_cell_coord_x = (orig[0] + dir[0] + LEVEL_BOUNDARY_MAX) * invcell;
f32 end_cell_coord_z = (orig[2] + dir[2] + LEVEL_BOUNDARY_MAX) * invcell;
// Don't do DDA if straight down
// Don't do grid traversal if straight down
if ((normalized_dir[1] >= NEAR_ONE) || (normalized_dir[1] <= -NEAR_ONE)) {
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
find_surface_on_ray_cell((s32)start_cell_coord_x, (s32)start_cell_coord_z, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
return max_length;
}
// Get cells we cross using DDA
f32 absDir0 = absf(dir[0]);
f32 absDir2 = absf(dir[2]);
if (absDir0 >= absDir2) {
step = (RAY_STEPS * absDir0) * invcell;
} else {
step = (RAY_STEPS * absDir2) * invcell;
}
// "A Fast Voxel Traversal Algorithm for Ray Tracing" - John Amanatides & Andrew Woo
// Adapted from implementation at https://www.shadertoy.com/view/XddcWn
f32 rd_x = end_cell_coord_x - start_cell_coord_x;
f32 rd_z = end_cell_coord_z - start_cell_coord_z;
f32 p_x = (s32)start_cell_coord_x;
f32 p_z = (s32)start_cell_coord_z;
f32 rdinv_x = 1.0f / rd_x;
f32 rdinv_z = 1.0f / rd_z;
f32 stp_x = signum_positive(rd_x);
f32 stp_z = signum_positive(rd_z);
f32 delta_x = MIN(rdinv_x * stp_x, 1.0f);
f32 delta_z = MIN(rdinv_z * stp_z, 1.0f);
f32 t_max_x = ABS((p_x + MAX(stp_x, 0.0f) - start_cell_coord_x) * rdinv_x);
f32 t_max_z = ABS((p_z + MAX(stp_z, 0.0f) - start_cell_coord_z) * rdinv_z);
f32 dx = (dir[0] / step) * invcell;
f32 dz = (dir[2] / step) * invcell;
while (TRUE) {
find_surface_on_ray_cell((s32)p_x, (s32)p_z, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
f32 t_next = MIN(t_max_x, t_max_z);
if (t_next > 1.0f) {
break;
}
for (i = 0; i < step && *hit_surface == NULL; i++) {
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
// Move cell coordinate
fCellX += dx;
fCellZ += dz;
cellPrevX = cellX;
cellPrevZ = cellZ;
cellX = fCellX;
cellZ = fCellZ;
if ((cellPrevX != cellX) && (cellPrevZ != cellZ)) {
find_surface_on_ray_cell(cellX, cellPrevZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
find_surface_on_ray_cell(cellPrevX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags);
if (t_max_x < t_max_z) {
t_max_x += delta_x;
p_x += stp_x;
}
else {
t_max_z += delta_z;
p_z += stp_z;
}
}
return max_length;