mirror of https://github.com/AxioDL/metaforce.git
Initial CMetroidAreaCollider implementations
This commit is contained in:
parent
a2c462529f
commit
35fa9b0992
|
@ -16,13 +16,6 @@ zeus::CVector3f CCollisionSurface::GetNormal() const
|
||||||
return zeus::CUnitVector3f({v1.y, v1.z, v1.x}, true);
|
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::CPlane CCollisionSurface::GetPlane() const
|
||||||
{
|
{
|
||||||
zeus::CVector3f norm = GetNormal();
|
zeus::CVector3f norm = GetNormal();
|
||||||
|
|
|
@ -16,7 +16,7 @@ public:
|
||||||
CCollisionSurface(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&, u32);
|
CCollisionSurface(const zeus::CVector3f&, const zeus::CVector3f&, const zeus::CVector3f&, u32);
|
||||||
|
|
||||||
zeus::CVector3f GetNormal() const;
|
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::CVector3f GetPoint(s32) const;
|
||||||
zeus::CPlane GetPlane() const;
|
zeus::CPlane GetPlane() const;
|
||||||
u32 GetSurfaceFlags() const { return x24_flags; }
|
u32 GetSurfaceFlags() const { return x24_flags; }
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
#include "CMetroidAreaCollider.hpp"
|
#include "CMetroidAreaCollider.hpp"
|
||||||
|
#include "CMaterialFilter.hpp"
|
||||||
|
#include "CollisionUtil.hpp"
|
||||||
|
|
||||||
namespace urde
|
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)
|
CMetroidAreaCollider::COctreeLeafCache::COctreeLeafCache(const CAreaOctTree& octTree)
|
||||||
: x0_octTree(octTree)
|
: x0_octTree(octTree)
|
||||||
{
|
{
|
||||||
|
@ -46,10 +54,48 @@ bool CMetroidAreaCollider::AABoxCollisionCheckBoolean_Cached(const COctreeLeafCa
|
||||||
return false;
|
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<list.GetSize() ; ++j)
|
||||||
|
{
|
||||||
|
++g_TrianglesProcessed;
|
||||||
|
CCollisionSurface surf = ch.GetOwner().GetMasterListTriangle(list.GetAt(j));
|
||||||
|
if (cache.x4_filter.Passes(CMaterialList(surf.GetSurfaceFlags())))
|
||||||
|
{
|
||||||
|
if (CollisionUtil::TriBoxOverlap(cache.x8_center, cache.x14_halfExtent,
|
||||||
|
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (AABoxCollisionCheckBoolean_Internal(ch, cache))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CMetroidAreaCollider::AABoxCollisionCheckBoolean(const CAreaOctTree& octTree, const zeus::CAABox& aabb,
|
bool CMetroidAreaCollider::AABoxCollisionCheckBoolean(const CAreaOctTree& octTree, const zeus::CAABox& aabb,
|
||||||
const CMaterialFilter& filter)
|
const CMaterialFilter& filter)
|
||||||
{
|
{
|
||||||
return false;
|
CBooleanAABoxAreaCache cache(aabb, filter);
|
||||||
|
return AABoxCollisionCheckBoolean_Internal(octTree.GetRootNode(), cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMetroidAreaCollider::SphereCollisionCheckBoolean_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb,
|
bool CMetroidAreaCollider::SphereCollisionCheckBoolean_Cached(const COctreeLeafCache& leafCache, const zeus::CAABox& aabb,
|
||||||
|
|
|
@ -11,8 +11,22 @@ class CCollisionInfoList;
|
||||||
class CCollisionInfo;
|
class CCollisionInfo;
|
||||||
class CMaterialList;
|
class CMaterialList;
|
||||||
|
|
||||||
|
class CBooleanAABoxAreaCache
|
||||||
|
{
|
||||||
|
friend class CMetroidAreaCollider;
|
||||||
|
const zeus::CAABox& x0_aabb;
|
||||||
|
const CMaterialFilter& x4_filter;
|
||||||
|
zeus::CVector3f x8_center;
|
||||||
|
zeus::CVector3f x14_halfExtent;
|
||||||
|
public:
|
||||||
|
CBooleanAABoxAreaCache(const zeus::CAABox& aabb, const CMaterialFilter& filter);
|
||||||
|
};
|
||||||
|
|
||||||
class CMetroidAreaCollider
|
class CMetroidAreaCollider
|
||||||
{
|
{
|
||||||
|
static u32 g_TrianglesProcessed;
|
||||||
|
static bool AABoxCollisionCheckBoolean_Internal(const CAreaOctTree::Node& node,
|
||||||
|
const CBooleanAABoxAreaCache& cache);
|
||||||
public:
|
public:
|
||||||
class COctreeLeafCache
|
class COctreeLeafCache
|
||||||
{
|
{
|
||||||
|
|
|
@ -117,5 +117,174 @@ bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1
|
||||||
return aabb0.intersects(aabb1);
|
return aabb0.intersects(aabb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/tribox2.txt */
|
||||||
|
/********************************************************/
|
||||||
|
/* AABB-triangle overlap test code */
|
||||||
|
/* by Tomas Akenine-Möller */
|
||||||
|
/* Function: int triBoxOverlap(float boxcenter[3], */
|
||||||
|
/* float boxhalfsize[3],float triverts[3][3]); */
|
||||||
|
/* History: */
|
||||||
|
/* 2001-03-05: released the code in its first version */
|
||||||
|
/* 2001-06-18: changed the order of the tests, faster */
|
||||||
|
/* */
|
||||||
|
/* Acknowledgement: Many thanks to Pierre Terdiman for */
|
||||||
|
/* suggestions and discussions on how to optimize code. */
|
||||||
|
/* Thanks to David Hunt for finding a ">="-bug! */
|
||||||
|
/********************************************************/
|
||||||
|
|
||||||
|
#define FINDMINMAX(x0,x1,x2,min,max) \
|
||||||
|
min = max = x0; \
|
||||||
|
if (x1<min) min = x1;\
|
||||||
|
if (x1>max) max = x1;\
|
||||||
|
if (x2<min) min = x2;\
|
||||||
|
if (x2>max) 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(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
|
||||||
|
rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
|
||||||
|
if(min>rad || 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(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
||||||
|
rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
|
||||||
|
if(min>rad || 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(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
|
||||||
|
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
|
||||||
|
if(min>rad || 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(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
||||||
|
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
|
||||||
|
if(min>rad || 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(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
|
||||||
|
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
|
||||||
|
if(min>rad || 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(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
||||||
|
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
|
||||||
|
if(min>rad || 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 */
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@ bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list
|
||||||
const zeus::CAABox& aabb1, const CMaterialList& list1,
|
const zeus::CAABox& aabb1, const CMaterialList& list1,
|
||||||
CCollisionInfoList& infoList);
|
CCollisionInfoList& infoList);
|
||||||
bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1);
|
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__
|
#endif // __URDE_COLLISIONUTIL_HPP__
|
||||||
|
|
Loading…
Reference in New Issue