From e71fd96e6a5877d88af546e6bb3eec5e99a9e001 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Sat, 27 Apr 2024 17:12:16 +0900 Subject: [PATCH] Impl Sphere/Generic_Box collision checking --- src/sc_sacd.cpp | 76 ++++++++++++++++++++++++++++++++++++++++--------- src/test.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 14 deletions(-) diff --git a/src/sc_sacd.cpp b/src/sc_sacd.cpp index 93cb9f2..c0695f9 100644 --- a/src/sc_sacd.cpp +++ b/src/sc_sacd.cpp @@ -43,7 +43,8 @@ std::vector SC_SACD_Get_Box_Normals( normals.back() = SC_SACD_Vec3_Rotate(normals.back(), box->x_radians, box->y_radians, box->z_radians); - // Not normalizing the normals on purpose for optimization. (No unit vectors.) + // Not normalizing the normals on purpose for optimization. It should already + // be normalized as each normal is a rotated unit vector. return normals; } @@ -208,21 +209,19 @@ int SC_SACD_Sphere_Collision(const SC_SACD_Sphere *a, const SC_SACD_Sphere *b) { int SC_SACD_Sphere_AABB_Box_Collision(const SC_SACD_Sphere *sphere, const SC_SACD_AABB_Box *box) { SC_SACD_Vec3 box_min{ - box->x - box->width / 2.0F, - box->y - box->height / 2.0F, - box->z - box->depth / 2.0F, + box->x - box->width / 2.0F, + box->y - box->height / 2.0F, + box->z - box->depth / 2.0F, }; SC_SACD_Vec3 box_max{ - box->x + box->width / 2.0F, - box->y + box->height / 2.0F, - box->z + box->depth / 2.0F, + box->x + box->width / 2.0F, + box->y + box->height / 2.0F, + box->z + box->depth / 2.0F, }; - SC_SACD_Vec3 clamped{ - std::max(box_min.x, std::min(sphere->x, box_max.x)), - std::max(box_min.y, std::min(sphere->y, box_max.y)), - std::max(box_min.z, std::min(sphere->z, box_max.z)) - }; + SC_SACD_Vec3 clamped{std::max(box_min.x, std::min(sphere->x, box_max.x)), + std::max(box_min.y, std::min(sphere->y, box_max.y)), + std::max(box_min.z, std::min(sphere->z, box_max.z))}; SC_SACD_Vec3 diff = clamped - SC_SACD_Vec3{sphere->x, sphere->y, sphere->z}; @@ -233,8 +232,57 @@ int SC_SACD_Sphere_AABB_Box_Collision(const SC_SACD_Sphere *sphere, int SC_SACD_Sphere_Box_Collision(const SC_SACD_Sphere *sphere, const SC_SACD_Generic_Box *box) { - // TODO - return 0; + // Adapted from Generic_Box/Generic_Box collision. + + // First check plane where normal = box_pos - sphere_pos. + + SC_SACD_Vec3 sphere_pos{sphere->x, sphere->y, sphere->z}; + SC_SACD_Vec3 sphere_box_normal = + SC_SACD_Vec3{box->x, box->y, box->z} - sphere_pos; + sphere_box_normal = + sphere_box_normal / + std::sqrt(SC_SACD_Dot_Product(sphere_box_normal, sphere_box_normal)); + + std::vector normals{sphere_box_normal}; + + std::vector box_minmaxes = + SC_SACD_Get_Box_MinMax(box, normals); + + float projected_0 = SC_SACD_Dot_Product( + sphere_box_normal, sphere_pos + sphere_box_normal * sphere->radius); + float projected_1 = SC_SACD_Dot_Product( + sphere_box_normal, sphere_pos - sphere_box_normal * sphere->radius); + if (projected_0 < projected_1) { + if (box_minmaxes[0].max < projected_0 || + box_minmaxes[0].min > projected_1) { + return 0; + } + } else if (box_minmaxes[0].max < projected_1 || + box_minmaxes[0].min > projected_0) { + return 0; + } + + // Next check the planes for the 3 normals of the box. + + normals = SC_SACD_Get_Box_Normals(box); + box_minmaxes = SC_SACD_Get_Box_MinMax(box, normals); + for (unsigned int i = 0; i < normals.size(); ++i) { + projected_0 = SC_SACD_Dot_Product(normals[i], + sphere_pos + normals[i] * sphere->radius); + projected_1 = SC_SACD_Dot_Product(normals[i], + sphere_pos - normals[i] * sphere->radius); + if (projected_0 < projected_1) { + if (box_minmaxes[i].max < projected_0 || + box_minmaxes[i].min > projected_1) { + return 0; + } + } else if (box_minmaxes[i].max < projected_1 || + box_minmaxes[i].min > projected_0) { + return 0; + } + } + + return 1; } float SC_SACD_Dot_Product(const SC_SACD_Vec3 a, const SC_SACD_Vec3 b) { diff --git a/src/test.cpp b/src/test.cpp index 5aaa9b2..f5f9471 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -222,6 +222,76 @@ int main() { CHECK_FALSE(SC_SACD_Sphere_AABB_Box_Collision(&sphere, &box)); } + // Test Sphere/Generic_Box collision check. + { + SC_SACD_Sphere sphere{0.0F, 0.0F, 0.0F, 1.0F}; + SC_SACD_Generic_Box box{0.0F, 0.0F, 0.0F, + 2.0F, 2.0F, 2.0F, + 0.0F, 0.0F, std::numbers::pi_v / 4.0F}; + + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = 2.5F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.x = -2.5F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.x = 2.3F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.x = -2.3F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = 0.0F; + sphere.y = 2.5F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.y = -2.5F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.y = 2.3F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.y = -2.3F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.y = 0.0F; + sphere.z = 2.1F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.z = -2.1F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.z = 1.9F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.z = -1.9F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = 1.5F; + sphere.y = 1.5F; + sphere.z = 0.0F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.x = 1.4F; + sphere.y = 1.4F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = 2.2F; + sphere.y = 0.7929F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = 2.1F; + sphere.y = 0.6929F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = -1.5F; + sphere.y = -1.5F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + sphere.x = -1.4F; + sphere.y = -1.4F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = -2.2F; + sphere.y = -0.7929F; + CHECK_FALSE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + + sphere.x = -2.1F; + sphere.y = -0.6929F; + CHECK_TRUE(SC_SACD_Sphere_Box_Collision(&sphere, &box)); + } + std::cout << "Checks checked: " << checks_checked << '\n' << "Checks passed: " << checks_passed << '\n';