Merge pull request #431 from djoslin0/to-upstream

Improve bettercam/puppycam's collision detection and avoidance
This commit is contained in:
fgsfds 2020-09-29 19:14:08 +03:00 committed by GitHub
commit 12e088fd69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 8 deletions

View File

@ -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)
{
@ -919,13 +923,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 = 3;
// 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;

View File

@ -10,12 +10,16 @@
#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
#include <stdio.h>
#endif
#define NEW_CAM_BOUNDING_BOX_RAYS 4
#define NEW_CAM_BOUNDING_BOX_HRADIUS 250
#define NEW_CAM_BOUNDING_BOX_VRADIUS 100
/**
Quick explanation of the camera modes
@ -473,6 +477,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;
@ -483,11 +528,20 @@ 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) {
// 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 +595,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();
}
}