From 35fa9b0992bfafaae82cf0932db8d9e537e96889 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 23 Jun 2017 18:58:59 -1000 Subject: [PATCH] Initial CMetroidAreaCollider implementations --- Runtime/Collision/CCollisionSurface.cpp | 7 - Runtime/Collision/CCollisionSurface.hpp | 2 +- Runtime/Collision/CMetroidAreaCollider.cpp | 48 +++++- Runtime/Collision/CMetroidAreaCollider.hpp | 14 ++ Runtime/Collision/CollisionUtil.cpp | 169 +++++++++++++++++++++ Runtime/Collision/CollisionUtil.hpp | 3 + 6 files changed, 234 insertions(+), 9 deletions(-) diff --git a/Runtime/Collision/CCollisionSurface.cpp b/Runtime/Collision/CCollisionSurface.cpp index 070a0da24..aee5957f4 100644 --- a/Runtime/Collision/CCollisionSurface.cpp +++ b/Runtime/Collision/CCollisionSurface.cpp @@ -16,13 +16,6 @@ zeus::CVector3f CCollisionSurface::GetNormal() const return zeus::CUnitVector3f({v1.y, v1.z, v1.x}, true); } -zeus::CVector3f CCollisionSurface::GetVert(s32 idx) const -{ - if (idx < 0 || idx > 3) - return zeus::CVector3f::skZero; - return (&x0_a)[idx]; -} - zeus::CPlane CCollisionSurface::GetPlane() const { zeus::CVector3f norm = GetNormal(); diff --git a/Runtime/Collision/CCollisionSurface.hpp b/Runtime/Collision/CCollisionSurface.hpp index 587d21483..d623e491e 100644 --- a/Runtime/Collision/CCollisionSurface.hpp +++ b/Runtime/Collision/CCollisionSurface.hpp @@ -16,7 +16,7 @@ public: CCollisionSurface(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&, u32); zeus::CVector3f GetNormal() const; - zeus::CVector3f GetVert(s32) const; + const zeus::CVector3f& GetVert(s32 idx) const { return (&x0_a)[idx]; } zeus::CVector3f GetPoint(s32) const; zeus::CPlane GetPlane() const; u32 GetSurfaceFlags() const { return x24_flags; } diff --git a/Runtime/Collision/CMetroidAreaCollider.cpp b/Runtime/Collision/CMetroidAreaCollider.cpp index 6ef064f90..34b52a1e2 100644 --- a/Runtime/Collision/CMetroidAreaCollider.cpp +++ b/Runtime/Collision/CMetroidAreaCollider.cpp @@ -1,8 +1,16 @@ #include "CMetroidAreaCollider.hpp" +#include "CMaterialFilter.hpp" +#include "CollisionUtil.hpp" namespace urde { +u32 CMetroidAreaCollider::g_TrianglesProcessed = 0; + +CBooleanAABoxAreaCache::CBooleanAABoxAreaCache(const zeus::CAABox& aabb, const CMaterialFilter& filter) +: x0_aabb(aabb), x4_filter(filter), x8_center(aabb.center()), x14_halfExtent(aabb.extents()) +{} + CMetroidAreaCollider::COctreeLeafCache::COctreeLeafCache(const CAreaOctTree& octTree) : x0_octTree(octTree) { @@ -46,10 +54,48 @@ bool CMetroidAreaCollider::AABoxCollisionCheckBoolean_Cached(const COctreeLeafCa return false; } +bool CMetroidAreaCollider::AABoxCollisionCheckBoolean_Internal(const CAreaOctTree::Node& node, + const CBooleanAABoxAreaCache& cache) +{ + for (int i=0 ; i<8 ; ++i) + { + CAreaOctTree::Node::ETreeType type = node.GetChildType(i); + if (type != CAreaOctTree::Node::ETreeType::Invalid) + { + CAreaOctTree::Node ch = node.GetChild(i); + if (cache.x0_aabb.intersects(ch.GetBoundingBox())) + { + if (type == CAreaOctTree::Node::ETreeType::Leaf) + { + CAreaOctTree::TriListReference list = ch.GetTriangleArray(); + for (int j=0 ; j="-bug! */ +/********************************************************/ + +#define FINDMINMAX(x0,x1,x2,min,max) \ + min = max = x0; \ + if (x1max) max = x1;\ + if (x2max) max = x2; + +static bool planeBoxOverlap(const zeus::CVector3f& normal, float d, const zeus::CVector3f& maxbox) +{ + zeus::CVector3f vmin, vmax; + for (int q=0 ; q<=2 ; q++) + { + if (normal[q] > 0.0f) + { + vmin[q] = -maxbox[q]; + vmax[q] = maxbox[q]; + } + else + { + vmin[q] = maxbox[q]; + vmax[q] = -maxbox[q]; + } + } + if (normal.dot(vmin) + d > 0.0f) return false; + if (normal.dot(vmax) + d >= 0.0f) return true; + + return false; +} + + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a*v0.y - b*v0.z; \ + p2 = a*v2.y - b*v2.z; \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a*v0.y - b*v0.z; \ + p1 = a*v1.y - b*v1.z; \ + if(p0rad || max<-rad) return false; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a*v0.x + b*v0.z; \ + p2 = -a*v2.x + b*v2.z; \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a*v0.x + b*v0.z; \ + p1 = -a*v1.x + b*v1.z; \ + if(p0rad || max<-rad) return false; + +/*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a*v1.x - b*v1.y; \ + p2 = a*v2.x - b*v2.y; \ + if(p2rad || max<-rad) return false; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a*v0.x - b*v0.y; \ + p1 = a*v1.x - b*v1.y; \ + if(p0rad || max<-rad) return false; + +bool TriBoxOverlap(const zeus::CVector3f& boxcenter, const zeus::CVector3f& boxhalfsize, + const zeus::CVector3f& trivert0, const zeus::CVector3f& trivert1, + const zeus::CVector3f& trivert2) +{ + + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + zeus::CVector3f v0, v1, v2; + float min, max, d, p0, p1, p2, rad, fex, fey, fez; + zeus::CVector3f normal, e0, e1, e2; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + v0 = trivert0 - boxcenter; + v1 = trivert1 - boxcenter; + v2 = trivert2 - boxcenter; + + /* compute triangle edges */ + e0 = v1 - v0; /* tri edge 0 */ + e1 = v2 - v1; /* tri edge 1 */ + e2 = v0 - v2; /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = std::fabs(e0.x); + fey = std::fabs(e0.y); + fez = std::fabs(e0.z); + AXISTEST_X01(e0.z, e0.y, fez, fey); + AXISTEST_Y02(e0.z, e0.x, fez, fex); + AXISTEST_Z12(e0.y, e0.x, fey, fex); + + fex = std::fabs(e1.x); + fey = std::fabs(e1.y); + fez = std::fabs(e1.z); + AXISTEST_X01(e1.z, e1.y, fez, fey); + AXISTEST_Y02(e1.z, e1.x, fez, fex); + AXISTEST_Z0(e1.y, e1.x, fey, fex); + + fex = std::fabs(e2.x); + fey = std::fabs(e2.y); + fez = std::fabs(e2.z); + AXISTEST_X2(e2.z, e2.y, fez, fey); + AXISTEST_Y1(e2.z, e2.x, fez, fex); + AXISTEST_Z12(e2.y, e2.x, fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if (min>boxhalfsize.x || max<-boxhalfsize.x) return false; + + /* test in Y-direction */ + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if (min>boxhalfsize.y || max<-boxhalfsize.y) return false; + + /* test in Z-direction */ + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if (min>boxhalfsize.z || max<-boxhalfsize.z) return false; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + normal = e0.cross(e1); + d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ + if (!planeBoxOverlap(normal, d, boxhalfsize)) return false; + + return true; /* box and triangle overlaps */ +} + } } diff --git a/Runtime/Collision/CollisionUtil.hpp b/Runtime/Collision/CollisionUtil.hpp index b7bec3804..7cb444fcf 100644 --- a/Runtime/Collision/CollisionUtil.hpp +++ b/Runtime/Collision/CollisionUtil.hpp @@ -21,6 +21,9 @@ bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list const zeus::CAABox& aabb1, const CMaterialList& list1, CCollisionInfoList& infoList); bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1); +bool TriBoxOverlap(const zeus::CVector3f& boxcenter, const zeus::CVector3f& boxhalfsize, + const zeus::CVector3f& trivert0, const zeus::CVector3f& trivert1, + const zeus::CVector3f& trivert2); } } #endif // __URDE_COLLISIONUTIL_HPP__