2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-13 21:11:21 +00:00
metaforce/Runtime/Collision/CollisionUtil.cpp
2017-06-23 18:58:59 -10:00

291 lines
9.4 KiB
C++

#include "CollisionUtil.hpp"
#include "CCollisionInfo.hpp"
#include "CCollisionInfoList.hpp"
namespace urde
{
namespace CollisionUtil
{
bool LineIntersectsOBBox(const zeus::COBBox& obb, const zeus::CMRay& ray, float& d)
{
const zeus::CVector3f transXf = obb.transform.toMatrix4f().vec[0].toVec3f();
return RayAABoxIntersection(ray.getInvUnscaledTransformRay(obb.transform), {-obb.extents, obb.extents},
transXf, d);
}
u32 RayAABoxIntersection(const zeus::CMRay& ray, const zeus::CAABox& box, const zeus::CVector3f&, float& d)
{
return 0;
}
u32 RaySphereIntersection_Double(const zeus::CSphere&, const zeus::CVector3f &, const zeus::CVector3f &, double &)
{
return 0;
}
bool RaySphereIntersection(const zeus::CSphere& sphere, const zeus::CVector3f& pos, const zeus::CVector3f& dir,
float mag, float& T, zeus::CVector3f& point)
{
zeus::CVector3f rayToSphere = sphere.position - pos;
float magSq = rayToSphere.magSquared();
float dirDot = rayToSphere.dot(dir);
float radSq = sphere.radius * sphere.radius;
if (dirDot < 0.f && magSq > radSq)
return false;
float intersectSq = radSq - (magSq - dirDot * dirDot);
if (intersectSq < 0.f)
return false;
T = magSq > radSq ? dirDot - std::sqrt(intersectSq) : dirDot + std::sqrt(intersectSq);
if (T < mag || mag == 0.f)
{
point = pos + T * dir;
return true;
}
return false;
}
void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in, CCollisionInfoList& out)
{
if (vec.canBeNormalized())
{
zeus::CVector3f norm = vec.normalized();
for (const CCollisionInfo& info : in)
{
if (info.GetNormalLeft().dot(norm) < 0.001f)
out.Add(info, false);
}
}
else
{
out = in;
}
}
void FilterByClosestNormal(const zeus::CVector3f& norm, const CCollisionInfoList& in, CCollisionInfoList& out)
{
float maxDot = -1.1f;
int idx = -1;
int i=0;
for (const CCollisionInfo& info : in)
{
float dot = info.GetNormalLeft().dot(norm);
if (dot > maxDot)
{
maxDot = dot;
idx = i;
}
++i;
}
if (idx != -1)
out.Add(in.GetItem(i), false);
}
static const zeus::CVector3f AABBNormalTable[] =
{
{-1.f, 0.f, 0.f},
{1.f, 0.f, 0.f},
{0.f, -1.f, 0.f},
{0.f, 1.f, 0.f},
{0.f, 0.f, -1.f},
{0.f, 0.f, 1.f}
};
bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list0,
const zeus::CAABox& aabb1, const CMaterialList& list1,
CCollisionInfoList& infoList)
{
zeus::CAABox boolAABB = aabb0.booleanIntersection(aabb1);
if (boolAABB.invalid())
return false;
/* TODO: Finish */
if (!infoList.GetCount())
{
infoList.Add(CCollisionInfo(boolAABB, list0, list1, AABBNormalTable[4], -AABBNormalTable[4]), false);
infoList.Add(CCollisionInfo(boolAABB, list0, list1, AABBNormalTable[5], -AABBNormalTable[5]), false);
}
return true;
}
bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const zeus::CAABox& 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 */
}
}
}