From 75bed240faf6997f3e3683303ab325b7fd164965 Mon Sep 17 00:00:00 2001 From: MysterD Date: Sat, 19 Sep 2020 18:59:58 -0700 Subject: [PATCH 1/3] Improve bettercam's collision detection and avoidance The precision of ray casting was too low previously, causing the collision checks to skip right past a wall sometimes. There was also nothing to prevent the camera from getting too close to a wall horizontally or vertically. --- src/engine/surface_collision.c | 11 ++++--- src/game/bettercamera.inc.h | 60 ++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 5b6775fe..1c6ee47b 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -919,13 +919,16 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length); return; } - + + // increase collision checking precision (normally 1) + f32 precision = 2; + // Get cells we cross using DDA if (absx(dir[0]) >= absx(dir[2])) - step = absx(dir[0]) / CELL_SIZE; + step = precision * absx(dir[0]) / CELL_SIZE; else - step = absx(dir[2]) / CELL_SIZE; - + step = precision * absx(dir[2]) / CELL_SIZE; + dx = dir[0] / step / CELL_SIZE; dz = dir[2] / step / CELL_SIZE; diff --git a/src/game/bettercamera.inc.h b/src/game/bettercamera.inc.h index 6e224d80..f9da431d 100644 --- a/src/game/bettercamera.inc.h +++ b/src/game/bettercamera.inc.h @@ -16,6 +16,9 @@ #include #endif +#define NEW_CAM_BOUNDING_BOX_RAYS 4 +#define NEW_CAM_BOUNDING_BOX_HRADIUS 250 +#define NEW_CAM_BOUNDING_BOX_VRADIUS 50 /** Quick explanation of the camera modes @@ -473,6 +476,47 @@ static void newcam_update_values(void) { } } +static void newcam_bounding_box(void) { + Vec3f camdirs[NEW_CAM_BOUNDING_BOX_RAYS] = { 0 }; + Vec3f raypos[NEW_CAM_BOUNDING_BOX_RAYS] = { 0 }; + s16 antiYaw = newcam_yaw - 0x4000; + + // sideways ray 1 + camdirs[0][0] = coss(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + camdirs[0][2] = sins(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + + // sideways ray 2 + camdirs[1][0] = -coss(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + camdirs[1][2] = -sins(antiYaw) * NEW_CAM_BOUNDING_BOX_HRADIUS; + + // vertical rays + camdirs[2][1] = -NEW_CAM_BOUNDING_BOX_VRADIUS; + camdirs[3][1] = NEW_CAM_BOUNDING_BOX_VRADIUS; + + for (int i = 0; i < NEW_CAM_BOUNDING_BOX_RAYS; i++) { + struct Surface* surf; + Vec3f offset = { 0 }; + + Vec3f startpos = { 0 }; + vec3f_copy(startpos, newcam_pos); + vec3f_add(startpos, offset); + + find_surface_on_ray(startpos, camdirs[i], &surf, raypos[i]); + if (!surf) { + vec3f_copy(raypos[i], startpos); + vec3f_add(raypos[i], camdirs[i]); + } + } + + Vec3f avg = { 0 }; + for (int i = 0; i < NEW_CAM_BOUNDING_BOX_RAYS; i++) { + vec3f_add(avg, raypos[i]); + } + vec3f_mul(avg, 1.0f / ((f32)NEW_CAM_BOUNDING_BOX_RAYS)); + + vec3f_copy(newcam_pos, avg); +} + static void newcam_collision(void) { struct Surface *surf; Vec3f camdir; @@ -486,8 +530,16 @@ static void newcam_collision(void) { newcam_coldist = sqrtf((newcam_pos_target[0] - hitpos[0]) * (newcam_pos_target[0] - hitpos[0]) + (newcam_pos_target[1] - hitpos[1]) * (newcam_pos_target[1] - hitpos[1]) + (newcam_pos_target[2] - hitpos[2]) * (newcam_pos_target[2] - hitpos[2])); if (surf) { + // offset the hit pos by the hit normal + Vec3f offset = { 0 }; + offset[0] = surf->normal.x; + offset[1] = surf->normal.y; + offset[2] = surf->normal.z; + vec3f_mul(offset, 5.0f); + vec3f_add(hitpos, offset); + newcam_pos[0] = hitpos[0]; - newcam_pos[1] = approach_f32(hitpos[1],newcam_pos[1],25,-25); + newcam_pos[1] = hitpos[1]; newcam_pos[2] = hitpos[2]; newcam_pan_x = 0; newcam_pan_z = 0; @@ -541,8 +593,10 @@ static void newcam_position_cam(void) { if (newcam_modeflags & NC_FLAG_FOCUSZ) newcam_lookat[2] = newcam_pos_target[2]-newcam_pan_z; - if (newcam_modeflags & NC_FLAG_COLLISION) - newcam_collision(); + if (newcam_modeflags & NC_FLAG_COLLISION) { + newcam_collision(); + newcam_bounding_box(); + } } From 47fca445829a0f071471648b76a44eeb63a3f2f8 Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 22 Sep 2020 22:14:43 -0700 Subject: [PATCH 2/3] Increase bettercam's precision --- src/engine/surface_collision.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 1c6ee47b..f7678f78 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -921,7 +921,7 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve } // increase collision checking precision (normally 1) - f32 precision = 2; + f32 precision = 5; // Get cells we cross using DDA if (absx(dir[0]) >= absx(dir[2])) From 7af6e308a4a732f5b93a1136ee81b79772628396 Mon Sep 17 00:00:00 2001 From: MysterD Date: Fri, 25 Sep 2020 21:40:59 -0700 Subject: [PATCH 3/3] Make bettercam/puppycam respect NO_CAM_COLLISION --- src/engine/surface_collision.c | 8 ++++++-- src/game/bettercamera.inc.h | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index f7678f78..d3cf1e4e 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -851,7 +851,11 @@ void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f // Reject surface if out of vertical bounds if (list->surface->lowerY > top || list->surface->upperY < bottom) continue; - + + // Reject no-cam collision surfaces + if (gCheckingSurfaceCollisionsForCamera && (list->surface->flags & SURFACE_FLAG_NO_CAM_COLLISION)) + continue; + // Check intersection between the ray and this surface if ((hit = ray_surface_intersect(orig, dir, dir_length, list->surface, chk_hit_pos, &length)) != 0) { @@ -921,7 +925,7 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve } // increase collision checking precision (normally 1) - f32 precision = 5; + f32 precision = 3; // Get cells we cross using DDA if (absx(dir[0]) >= absx(dir[2])) diff --git a/src/game/bettercamera.inc.h b/src/game/bettercamera.inc.h index f9da431d..d73fdaf1 100644 --- a/src/game/bettercamera.inc.h +++ b/src/game/bettercamera.inc.h @@ -10,6 +10,7 @@ #include "engine/surface_collision.h" #include "pc/configfile.h" #include "pc/controller/controller_mouse.h" + #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) //quick and dirty fix for some older MinGW.org mingwrt #else @@ -18,7 +19,7 @@ #define NEW_CAM_BOUNDING_BOX_RAYS 4 #define NEW_CAM_BOUNDING_BOX_HRADIUS 250 -#define NEW_CAM_BOUNDING_BOX_VRADIUS 50 +#define NEW_CAM_BOUNDING_BOX_VRADIUS 100 /** Quick explanation of the camera modes @@ -527,6 +528,7 @@ static void newcam_collision(void) { camdir[2] = newcam_pos[2]-newcam_lookat[2]; find_surface_on_ray(newcam_pos_target, camdir, &surf, hitpos); + newcam_coldist = sqrtf((newcam_pos_target[0] - hitpos[0]) * (newcam_pos_target[0] - hitpos[0]) + (newcam_pos_target[1] - hitpos[1]) * (newcam_pos_target[1] - hitpos[1]) + (newcam_pos_target[2] - hitpos[2]) * (newcam_pos_target[2] - hitpos[2])); if (surf) {