mirror of https://github.com/AxioDL/metaforce.git
Implement CCollidableOBBTree
This commit is contained in:
parent
704e1b110a
commit
0cfefd22a1
|
@ -1,4 +1,8 @@
|
|||
#include "CCollidableOBBTree.hpp"
|
||||
#include "CMaterialFilter.hpp"
|
||||
#include "CollisionUtil.hpp"
|
||||
#include "CInternalRayCastStructure.hpp"
|
||||
#include "CCollisionInfoList.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -11,22 +15,704 @@ CCollidableOBBTree::CCollidableOBBTree(const COBBTree* tree, const urde::CMateri
|
|||
|
||||
bool CCollidableOBBTree::LineIntersectsLeaf(const COBBTree::CLeafData& leaf, CRayCastInfo& info) const
|
||||
{
|
||||
bool ret = false;
|
||||
u16 intersectIdx = 0;
|
||||
for (int i=0 ; i<leaf.GetSurfaceVector().size() ; ++i)
|
||||
{
|
||||
u16 surfIdx = leaf.GetSurfaceVector()[i];
|
||||
CCollisionSurface surface = x10_tree->GetSurface(surfIdx);
|
||||
if (info.GetMaterialFilter().Passes(GetMaterial()))
|
||||
{
|
||||
if (CollisionUtil::RayTriangleIntersection(info.GetRay().start, info.GetRay().dir,
|
||||
surface.GetVerts(), info.Magnitude()))
|
||||
{
|
||||
intersectIdx = i;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetSurface(intersectIdx);
|
||||
info.Plane() = surf.GetPlane();
|
||||
info.Material() = CMaterialList(surf.GetSurfaceFlags());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::LineIntersectsOBBTree(const COBBTree::CNode& n0, const COBBTree::CNode& n1,
|
||||
CRayCastInfo& info) const
|
||||
{
|
||||
bool ret = false;
|
||||
float t0, t1;
|
||||
bool intersects0 = false;
|
||||
bool intersects1 = false;
|
||||
if (CollisionUtil::LineIntersectsOBBox(n0.GetOBB(), info.GetRay(), t0) && t0 < info.GetMagnitude())
|
||||
intersects0 = true;
|
||||
if (CollisionUtil::LineIntersectsOBBox(n1.GetOBB(), info.GetRay(), t1) && t1 < info.GetMagnitude())
|
||||
intersects1 = true;
|
||||
|
||||
if (intersects0 && intersects1)
|
||||
{
|
||||
if (t0 < t1)
|
||||
{
|
||||
if (n0.IsLeaf() ?
|
||||
LineIntersectsLeaf(n0.GetLeafData(), info) :
|
||||
LineIntersectsOBBTree(n0.GetLeft(), n0.GetRight(), info))
|
||||
{
|
||||
if (info.GetMagnitude() < t1)
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
if (n1.IsLeaf())
|
||||
{
|
||||
if (LineIntersectsLeaf(n1.GetLeafData(), info))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LineIntersectsOBBTree(n1.GetLeft(), n1.GetRight(), info))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n1.IsLeaf() ?
|
||||
LineIntersectsLeaf(n1.GetLeafData(), info) :
|
||||
LineIntersectsOBBTree(n1.GetLeft(), n1.GetRight(), info))
|
||||
{
|
||||
if (info.GetMagnitude() < t0)
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
if (n0.IsLeaf())
|
||||
{
|
||||
if (LineIntersectsLeaf(n0.GetLeafData(), info))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LineIntersectsOBBTree(n0.GetLeft(), n0.GetRight(), info))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (intersects0)
|
||||
{
|
||||
return n0.IsLeaf() ?
|
||||
LineIntersectsLeaf(n0.GetLeafData(), info) :
|
||||
LineIntersectsOBBTree(n0.GetLeft(), n0.GetRight(), info);
|
||||
}
|
||||
else if (intersects1)
|
||||
{
|
||||
return n1.IsLeaf() ?
|
||||
LineIntersectsLeaf(n1.GetLeafData(), info) :
|
||||
LineIntersectsOBBTree(n1.GetLeft(), n1.GetRight(), info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::LineIntersectsOBBTree(const COBBTree::CNode& node, CRayCastInfo& info) const
|
||||
{
|
||||
float t;
|
||||
bool ret = false;
|
||||
|
||||
if (CollisionUtil::LineIntersectsOBBox(node.GetOBB(), info.GetRay(), t) && t < info.GetMagnitude())
|
||||
{
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
if (LineIntersectsLeaf(node.GetLeafData(), info))
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LineIntersectsOBBTree(node.GetLeft(), node.GetRight(), info))
|
||||
ret = true;
|
||||
}
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRayCastResult CCollidableOBBTree::LineIntersectsTree(const zeus::CMRay& ray, const CMaterialFilter& filter,
|
||||
float maxTime, const zeus::CTransform& xf) const
|
||||
{
|
||||
zeus::CMRay useRay = ray.getInvUnscaledTransformRay(xf);
|
||||
CRayCastInfo info(useRay, filter, maxTime);
|
||||
if (LineIntersectsOBBTree(x10_tree->GetRoot(), info))
|
||||
{
|
||||
zeus::CPlane xfPlane = TransformPlane(info.GetPlane(), xf);
|
||||
return CRayCastResult(info.GetMagnitude(), ray.start + info.GetMagnitude() * ray.dir,
|
||||
xfPlane, info.GetMaterial());
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
zeus::CPlane CCollidableOBBTree::TransformPlane(const zeus::CPlane& pl, const zeus::CTransform& xf)
|
||||
{
|
||||
zeus::CVector3f normal = xf.rotate(pl.normal());
|
||||
return zeus::CPlane(normal, (xf * (pl.normal() * pl.d)).dot(normal));
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::SphereCollideWithLeafMoving(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf,
|
||||
const zeus::CSphere& sphere, const CMaterialList& matList,
|
||||
const CMaterialFilter& filter, const zeus::CVector3f& dir,
|
||||
double& dOut, CCollisionInfo& infoOut) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
zeus::CAABox aabb(sphere.position - sphere.radius,
|
||||
sphere.position + sphere.radius);
|
||||
zeus::CAABox moveAABB = aabb;
|
||||
zeus::CVector3f moveVec = float(dOut) * dir;
|
||||
moveAABB.accumulateBounds(aabb.max + moveVec);
|
||||
moveAABB.accumulateBounds(aabb.min + moveVec);
|
||||
|
||||
zeus::CVector3f center = moveAABB.center();
|
||||
zeus::CVector3f extent = moveAABB.extents();
|
||||
|
||||
for (u16 triIdx : leaf.GetSurfaceVector())
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetTransformedSurface(triIdx, xf);
|
||||
CMaterialList triMat = GetMaterial();
|
||||
triMat.Add(CMaterialList(surf.GetSurfaceFlags()));
|
||||
if (filter.Passes(triMat))
|
||||
{
|
||||
if (CollisionUtil::TriBoxOverlap(center, extent,
|
||||
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2)))
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x1c_hits += 1;
|
||||
|
||||
zeus::CVector3f surfNormal = surf.GetNormal();
|
||||
if ((sphere.position + moveVec - surf.GetVert(0)).dot(surfNormal) <= sphere.radius)
|
||||
{
|
||||
float mag = (sphere.radius - (sphere.position - surf.GetVert(0)).dot(surfNormal)) / dir.dot(surfNormal);
|
||||
zeus::CVector3f intersectPoint = sphere.position + mag * dir;
|
||||
|
||||
bool outsideEdges[] =
|
||||
{(intersectPoint - surf.GetVert(0)).dot((surf.GetVert(1) - surf.GetVert(0)).cross(surfNormal)) < 0.f,
|
||||
(intersectPoint - surf.GetVert(1)).dot((surf.GetVert(2) - surf.GetVert(1)).cross(surfNormal)) < 0.f,
|
||||
(intersectPoint - surf.GetVert(2)).dot((surf.GetVert(0) - surf.GetVert(2)).cross(surfNormal)) < 0.f};
|
||||
|
||||
if (mag >= 0.f && !outsideEdges[0] && !outsideEdges[1] && !outsideEdges[2] && mag < dOut)
|
||||
{
|
||||
infoOut = CCollisionInfo(intersectPoint - sphere.radius * surfNormal, matList, triMat, surfNormal);
|
||||
dOut = mag;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
bool intersects = (sphere.position - surf.GetVert(0)).dot(surfNormal) <= sphere.radius;
|
||||
bool testVert[] = {true, true, true};
|
||||
const u16* edgeIndices = x10_tree->GetTriangleEdgeIndices(triIdx);
|
||||
for (int k=0 ; k<3 ; ++k)
|
||||
{
|
||||
if (intersects || outsideEdges[k])
|
||||
{
|
||||
u16 edgeIdx = edgeIndices[k];
|
||||
if (CMetroidAreaCollider::g_DupPrimitiveCheckCount != CMetroidAreaCollider::g_DupEdgeList[edgeIdx])
|
||||
{
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIdx] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMaterialList edgeMat(x10_tree->GetEdgeMaterial(edgeIdx));
|
||||
if (!edgeMat.HasMaterial(EMaterialTypes::TwentyFour))
|
||||
{
|
||||
int nextIdx = (k + 1) % 3;
|
||||
zeus::CVector3f edgeVec = surf.GetVert(nextIdx) - surf.GetVert(k);
|
||||
float edgeVecMag = edgeVec.magnitude();
|
||||
edgeVec *= (1.f / edgeVecMag);
|
||||
float dirDotEdge = dir.dot(edgeVec);
|
||||
zeus::CVector3f edgeRej = dir - dirDotEdge * edgeVec;
|
||||
float edgeRejMagSq = edgeRej.magSquared();
|
||||
zeus::CVector3f vertToSphere = sphere.position - surf.GetVert(k);
|
||||
float vtsDotEdge = vertToSphere.dot(edgeVec);
|
||||
zeus::CVector3f vtsRej = vertToSphere - vtsDotEdge * edgeVec;
|
||||
if (edgeRejMagSq > 0.f)
|
||||
{
|
||||
float tmp = 2.f * vtsRej.dot(edgeRej);
|
||||
float tmp2 = 4.f * edgeRejMagSq *
|
||||
(vtsRej.magSquared() - sphere.radius * sphere.radius) - tmp * tmp;
|
||||
if (tmp2 >= 0.f)
|
||||
{
|
||||
float mag = 0.5f / edgeRejMagSq * (-tmp - std::sqrt(tmp2));
|
||||
if (mag >= 0.f)
|
||||
{
|
||||
float t = mag * dirDotEdge + vtsDotEdge;
|
||||
if (t >= 0.f && t <= edgeVecMag && mag < dOut)
|
||||
{
|
||||
zeus::CVector3f point = surf.GetVert(k) + t * edgeVec;
|
||||
infoOut = CCollisionInfo(point, matList, edgeMat,
|
||||
(sphere.position + mag * dir - point).normalized());
|
||||
dOut = mag;
|
||||
ret = true;
|
||||
testVert[k] = false;
|
||||
testVert[nextIdx] = false;
|
||||
}
|
||||
else if (t < -sphere.radius && dirDotEdge <= 0.f)
|
||||
{
|
||||
testVert[k] = false;
|
||||
}
|
||||
else if (t > edgeVecMag + sphere.radius && dirDotEdge >= 0.0)
|
||||
{
|
||||
testVert[nextIdx] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
testVert[k] = false;
|
||||
testVert[nextIdx] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u16 vertIndices[3];
|
||||
x10_tree->GetTriangleVertexIndices(triIdx, vertIndices);
|
||||
|
||||
for (int k=0 ; k<3 ; ++k)
|
||||
{
|
||||
u16 vertIdx = vertIndices[k];
|
||||
if (testVert[k])
|
||||
{
|
||||
if (CMetroidAreaCollider::g_DupPrimitiveCheckCount != CMetroidAreaCollider::g_DupVertexList[vertIdx])
|
||||
{
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIdx] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
double d = dOut;
|
||||
if (CollisionUtil::RaySphereIntersection_Double(zeus::CSphere(surf.GetVert(k), sphere.radius),
|
||||
sphere.position, dir, d) && d >= 0.0)
|
||||
{
|
||||
infoOut = CCollisionInfo(surf.GetVert(k), matList, x10_tree->GetVertMaterial(vertIdx),
|
||||
(sphere.position + dir * d - surf.GetVert(k)).normalized());
|
||||
dOut = d;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIdx] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u16* edgeIndices = x10_tree->GetTriangleEdgeIndices(triIdx);
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIndices[0]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIndices[1]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIndices[2]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
|
||||
u16 vertIndices[3];
|
||||
x10_tree->GetTriangleVertexIndices(triIdx, vertIndices);
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIndices[0]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIndices[1]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIndices[2]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::SphereCollisionMoving(const COBBTree::CNode& node, const zeus::CTransform& xf,
|
||||
const zeus::CSphere& sphere, const zeus::COBBox& obb,
|
||||
const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const zeus::CVector3f& dir, double& dOut, CCollisionInfo& info) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
const_cast<CCollidableOBBTree&>(*this).x14_tries += 1;
|
||||
if (obb.OBBIntersectsBox(node.GetOBB()))
|
||||
{
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
if (SphereCollideWithLeafMoving(node.GetLeafData(), xf, sphere, material, filter, dir, dOut, info))
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SphereCollisionMoving(node.GetLeft(), xf, sphere, obb, material, filter, dir, dOut, info))
|
||||
ret = true;
|
||||
if (SphereCollisionMoving(node.GetRight(), xf, sphere, obb, material, filter, dir, dOut, info))
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::AABoxCollideWithLeafMoving(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf,
|
||||
const zeus::CAABox& aabb, const CMaterialList& matList,
|
||||
const CMaterialFilter& filter, const CMovingAABoxComponents& components,
|
||||
const zeus::CVector3f& dir, double& dOut, CCollisionInfo& infoOut) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
zeus::CAABox movedAABB = components.x6e8_aabb;
|
||||
zeus::CVector3f moveVec = float(dOut) * dir;
|
||||
movedAABB.accumulateBounds(aabb.min + moveVec);
|
||||
movedAABB.accumulateBounds(aabb.max + moveVec);
|
||||
|
||||
zeus::CVector3f center = movedAABB.center();
|
||||
zeus::CVector3f extent = movedAABB.extents();
|
||||
|
||||
zeus::CVector3f normal, point;
|
||||
|
||||
for (u16 triIdx : leaf.GetSurfaceVector())
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetTransformedSurface(triIdx, xf);
|
||||
CMaterialList triMat = GetMaterial();
|
||||
triMat.Add(CMaterialList(surf.GetSurfaceFlags()));
|
||||
if (filter.Passes(triMat))
|
||||
{
|
||||
if (CollisionUtil::TriBoxOverlap(center, extent,
|
||||
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2)))
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x1c_hits += 1;
|
||||
|
||||
u16 vertIndices[3];
|
||||
x10_tree->GetTriangleVertexIndices(triIdx, vertIndices);
|
||||
|
||||
double d = dOut;
|
||||
if (CMetroidAreaCollider::MovingAABoxCollisionCheck_BoxVertexTri(surf, aabb, components.x6c4_vertIdxs,
|
||||
dir, d, normal, point) && d < dOut)
|
||||
{
|
||||
ret = true;
|
||||
infoOut = CCollisionInfo(point, matList, triMat, normal);
|
||||
dOut = d;
|
||||
}
|
||||
|
||||
for (int k=0 ; k<3 ; ++k)
|
||||
{
|
||||
u16 vertIdx = vertIndices[k];
|
||||
const zeus::CVector3f& vtx = x10_tree->GetVert(vertIdx);
|
||||
if (CMetroidAreaCollider::g_DupPrimitiveCheckCount != CMetroidAreaCollider::g_DupVertexList[vertIdx])
|
||||
{
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIdx] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
if (movedAABB.pointInside(vtx))
|
||||
{
|
||||
d = dOut;
|
||||
if (CMetroidAreaCollider::MovingAABoxCollisionCheck_TriVertexBox(vtx, aabb, dir, d,
|
||||
normal, point) && d < dOut)
|
||||
{
|
||||
CMaterialList vertMat(x10_tree->GetVertMaterial(vertIdx));
|
||||
ret = true;
|
||||
infoOut = CCollisionInfo(point, matList, vertMat, normal);
|
||||
dOut = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const u16* edgeIndices = x10_tree->GetTriangleEdgeIndices(triIdx);
|
||||
for (int k=0 ; k<3 ; ++k)
|
||||
{
|
||||
u16 edgeIdx = edgeIndices[k];
|
||||
if (CMetroidAreaCollider::g_DupPrimitiveCheckCount != CMetroidAreaCollider::g_DupEdgeList[edgeIdx])
|
||||
{
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIdx] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMaterialList edgeMat(x10_tree->GetEdgeMaterial(edgeIdx));
|
||||
if (!edgeMat.HasMaterial(EMaterialTypes::TwentyFour))
|
||||
{
|
||||
d = dOut;
|
||||
const CCollisionEdge& edge = x10_tree->GetEdge(edgeIdx);
|
||||
if (CMetroidAreaCollider::MovingAABoxCollisionCheck_Edge(x10_tree->GetVert(edge.GetVertIndex1()),
|
||||
x10_tree->GetVert(edge.GetVertIndex2()),
|
||||
components.x0_edges, dir, d, normal, point) &&
|
||||
d < dOut)
|
||||
{
|
||||
ret = true;
|
||||
infoOut = CCollisionInfo(point, matList, edgeMat, normal);
|
||||
dOut = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u16* edgeIndices = x10_tree->GetTriangleEdgeIndices(triIdx);
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIndices[0]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIndices[1]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupEdgeList[edgeIndices[2]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
|
||||
u16 vertIndices[3];
|
||||
x10_tree->GetTriangleVertexIndices(triIdx, vertIndices);
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIndices[0]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIndices[1]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
CMetroidAreaCollider::g_DupVertexList[vertIndices[2]] = CMetroidAreaCollider::g_DupPrimitiveCheckCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::AABoxCollisionMoving(const COBBTree::CNode& node, const zeus::CTransform& xf,
|
||||
const zeus::CAABox& aabb, const zeus::COBBox& obb,
|
||||
const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const CMovingAABoxComponents& components, const zeus::CVector3f& dir,
|
||||
double& dOut, CCollisionInfo& info) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
const_cast<CCollidableOBBTree&>(*this).x14_tries += 1;
|
||||
if (obb.OBBIntersectsBox(node.GetOBB()))
|
||||
{
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
if (AABoxCollideWithLeafMoving(node.GetLeafData(), xf, aabb, material, filter, components, dir, dOut, info))
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AABoxCollisionMoving(node.GetLeft(), xf, aabb, obb, material, filter, components, dir, dOut, info))
|
||||
ret = true;
|
||||
if (AABoxCollisionMoving(node.GetRight(), xf, aabb, obb, material, filter, components, dir, dOut, info))
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::SphereCollisionBoolean(const COBBTree::CNode& node, const zeus::CTransform& xf,
|
||||
const zeus::CSphere& sphere, const zeus::COBBox& obb,
|
||||
const CMaterialFilter& filter) const
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x14_tries += 1;
|
||||
if (obb.OBBIntersectsBox(node.GetOBB()))
|
||||
{
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
for (u16 surfIdx : node.GetLeafData().GetSurfaceVector())
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetTransformedSurface(surfIdx, xf);
|
||||
CMaterialList triMat = GetMaterial();
|
||||
triMat.Add(CMaterialList(surf.GetSurfaceFlags()));
|
||||
if (filter.Passes(triMat) && CollisionUtil::TriSphereOverlap(sphere,
|
||||
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SphereCollisionBoolean(node.GetLeft(), xf, sphere, obb, filter))
|
||||
return true;
|
||||
if (SphereCollisionBoolean(node.GetRight(), xf, sphere, obb, filter))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::AABoxCollisionBoolean(const COBBTree::CNode& node, const zeus::CTransform& xf,
|
||||
const zeus::CAABox& aabb, const zeus::COBBox& obb,
|
||||
const CMaterialFilter& filter) const
|
||||
{
|
||||
zeus::CVector3f center = aabb.center();
|
||||
zeus::CVector3f extent = aabb.extents();
|
||||
|
||||
const_cast<CCollidableOBBTree&>(*this).x14_tries += 1;
|
||||
if (obb.OBBIntersectsBox(node.GetOBB()))
|
||||
{
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
for (u16 surfIdx : node.GetLeafData().GetSurfaceVector())
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetTransformedSurface(surfIdx, xf);
|
||||
CMaterialList triMat = GetMaterial();
|
||||
triMat.Add(CMaterialList(surf.GetSurfaceFlags()));
|
||||
if (filter.Passes(triMat) && CollisionUtil::TriBoxOverlap(center, extent,
|
||||
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AABoxCollisionBoolean(node.GetLeft(), xf, aabb, obb, filter))
|
||||
return true;
|
||||
if (AABoxCollisionBoolean(node.GetRight(), xf, aabb, obb, filter))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::SphereCollideWithLeaf(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf,
|
||||
const zeus::CSphere& sphere, const CMaterialList& material,
|
||||
const CMaterialFilter& filter, CCollisionInfoList& infoList) const
|
||||
{
|
||||
bool ret = false;
|
||||
zeus::CVector3f point, normal;
|
||||
|
||||
for (u16 surfIdx : leaf.GetSurfaceVector())
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetTransformedSurface(surfIdx, xf);
|
||||
CMaterialList triMat = GetMaterial();
|
||||
triMat.Add(CMaterialList(surf.GetSurfaceFlags()));
|
||||
if (filter.Passes(triMat))
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x1c_hits += 1;
|
||||
if (CollisionUtil::TriSphereIntersection(sphere,
|
||||
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2),
|
||||
point, normal))
|
||||
{
|
||||
CCollisionInfo collision(point, material, triMat, normal);
|
||||
infoList.Add(collision, false);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::SphereCollision(const COBBTree::CNode& node, const zeus::CTransform& xf,
|
||||
const zeus::CSphere& sphere, const zeus::COBBox& obb,
|
||||
const CMaterialList& material, const CMaterialFilter& filter,
|
||||
CCollisionInfoList& infoList) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
const_cast<CCollidableOBBTree&>(*this).x14_tries += 1;
|
||||
if (obb.OBBIntersectsBox(node.GetOBB()))
|
||||
{
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
if (SphereCollideWithLeaf(node.GetLeafData(), xf, sphere, material, filter, infoList))
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SphereCollision(node.GetLeft(), xf, sphere, obb, material, filter, infoList))
|
||||
ret = true;
|
||||
if (SphereCollision(node.GetRight(), xf, sphere, obb, material, filter, infoList))
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::AABoxCollideWithLeaf(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf,
|
||||
const zeus::CAABox& aabb, const CMaterialList& material,
|
||||
const CMaterialFilter& filter, const zeus::CPlane* planes,
|
||||
CCollisionInfoList& infoList) const
|
||||
{
|
||||
bool ret = false;
|
||||
zeus::CVector3f center = aabb.center();
|
||||
zeus::CVector3f extent = aabb.extents();
|
||||
|
||||
for (u16 surfIdx : leaf.GetSurfaceVector())
|
||||
{
|
||||
CCollisionSurface surf = x10_tree->GetTransformedSurface(surfIdx, xf);
|
||||
CMaterialList triMat = GetMaterial();
|
||||
triMat.Add(CMaterialList(surf.GetSurfaceFlags()));
|
||||
if (filter.Passes(triMat) && CollisionUtil::TriBoxOverlap(center, extent,
|
||||
surf.GetVert(0), surf.GetVert(1), surf.GetVert(2)))
|
||||
{
|
||||
zeus::CAABox newAABB = zeus::CAABox::skInvertedBox;
|
||||
const_cast<CCollidableOBBTree&>(*this).x1c_hits += 1;
|
||||
if (CMetroidAreaCollider::ConvexPolyCollision(planes, surf.GetVerts(), newAABB))
|
||||
{
|
||||
zeus::CPlane plane = surf.GetPlane();
|
||||
CCollisionInfo collision(newAABB, triMat, material,
|
||||
plane.normal(), -plane.normal());
|
||||
infoList.Add(collision, false);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTree::AABoxCollision(const COBBTree::CNode& node, const zeus::CTransform& xf,
|
||||
const zeus::CAABox& aabb, const zeus::COBBox& obb,
|
||||
const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const zeus::CPlane* planes, CCollisionInfoList& infoList) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
const_cast<CCollidableOBBTree&>(*this).x14_tries += 1;
|
||||
if (obb.OBBIntersectsBox(node.GetOBB()))
|
||||
{
|
||||
const_cast<COBBTree::CNode&>(node).SetHit(true);
|
||||
if (node.IsLeaf())
|
||||
{
|
||||
if (AABoxCollideWithLeaf(node.GetLeafData(), xf, aabb, material, filter, planes, infoList))
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AABoxCollision(node.GetLeft(), xf, aabb, obb, material, filter, planes, infoList))
|
||||
ret = true;
|
||||
if (AABoxCollision(node.GetRight(), xf, aabb, obb, material, filter, planes, infoList))
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const_cast<CCollidableOBBTree&>(*this).x18_misses += 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FourCC CCollidableOBBTree::GetPrimType() const
|
||||
{
|
||||
return SBIG('OBBT');
|
||||
}
|
||||
|
||||
CRayCastResult CCollidableOBBTree::CastRayInternal(const CInternalRayCastStructure&) const
|
||||
CRayCastResult CCollidableOBBTree::CastRayInternal(const CInternalRayCastStructure& rayCast) const
|
||||
{
|
||||
return {};
|
||||
return LineIntersectsTree(rayCast.GetRay(), rayCast.GetFilter(),
|
||||
rayCast.GetMaxTime(), rayCast.GetTransform());
|
||||
}
|
||||
|
||||
zeus::CAABox CCollidableOBBTree::CalculateAABox(const zeus::CTransform& xf) const
|
||||
{
|
||||
return x10_tree->CalculateAABox(xf);
|
||||
return zeus::COBBox::FromAABox(x10_tree->CalculateLocalAABox(), xf).calculateAABox();
|
||||
}
|
||||
|
||||
zeus::CAABox CCollidableOBBTree::CalculateLocalAABox() const
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "Collision/CCollisionPrimitive.hpp"
|
||||
#include "COBBTree.hpp"
|
||||
#include "zeus/COBBox.hpp"
|
||||
#include "CMetroidAreaCollider.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -11,19 +13,64 @@ class CRayCastInfo
|
|||
const zeus::CMRay& x0_ray;
|
||||
const CMaterialFilter& x4_filter;
|
||||
float x8_mag;
|
||||
zeus::CPlane xc_plane = {zeus::CVector3f::skUp, 0.f};
|
||||
CMaterialList x20_material;
|
||||
public:
|
||||
CRayCastInfo(const zeus::CMRay& ray, const CMaterialFilter& filter, float mag)
|
||||
: x0_ray(ray), x4_filter(filter), x8_mag(mag) {}
|
||||
const zeus::CMRay& GetRay() const { return x0_ray; }
|
||||
const CMaterialFilter& GetMaterialFilter() const { return x4_filter; }
|
||||
float GetMagnitude() const { return x8_mag; }
|
||||
float& Magnitude() { return x8_mag; }
|
||||
const zeus::CPlane& GetPlane() const { return xc_plane; }
|
||||
zeus::CPlane& Plane() { return xc_plane; }
|
||||
const CMaterialList& GetMaterial() const { return x20_material; }
|
||||
CMaterialList& Material() { return x20_material; }
|
||||
};
|
||||
|
||||
class CCollidableOBBTree : public CCollisionPrimitive
|
||||
{
|
||||
friend class CCollidableOBBTreeGroup;
|
||||
COBBTree* x10_tree = nullptr;
|
||||
u32 x14_ = 0;
|
||||
u32 x18_ = 0;
|
||||
u32 x1c_ = 0;
|
||||
u32 x14_tries = 0;
|
||||
u32 x18_misses = 0;
|
||||
u32 x1c_hits = 0;
|
||||
static u32 sTableIndex;
|
||||
bool LineIntersectsLeaf(const COBBTree::CLeafData& leaf, CRayCastInfo& info) const;
|
||||
bool LineIntersectsOBBTree(const COBBTree::CNode& n0, const COBBTree::CNode& n1, CRayCastInfo& info) const;
|
||||
bool LineIntersectsOBBTree(const COBBTree::CNode& node, CRayCastInfo& info) const;
|
||||
CRayCastResult LineIntersectsTree(const zeus::CMRay& ray, const CMaterialFilter& filter, float maxTime,
|
||||
const zeus::CTransform& xf) const;
|
||||
static zeus::CPlane TransformPlane(const zeus::CPlane& pl, const zeus::CTransform& xf);
|
||||
bool SphereCollideWithLeafMoving(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf, const zeus::CSphere& sphere,
|
||||
const CMaterialList& material, const CMaterialFilter& filter, const zeus::CVector3f& dir,
|
||||
double& dOut, CCollisionInfo& info) const;
|
||||
bool SphereCollisionMoving(const COBBTree::CNode& node, const zeus::CTransform& xf, const zeus::CSphere& sphere,
|
||||
const zeus::COBBox& obb, const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const zeus::CVector3f& dir, double& dOut, CCollisionInfo& info) const;
|
||||
bool AABoxCollideWithLeafMoving(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf, const zeus::CAABox& aabb,
|
||||
const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const CMovingAABoxComponents& components, const zeus::CVector3f& dir,
|
||||
double& dOut, CCollisionInfo& info) const;
|
||||
bool AABoxCollisionMoving(const COBBTree::CNode& node, const zeus::CTransform& xf, const zeus::CAABox& aabb,
|
||||
const zeus::COBBox& obb, const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const CMovingAABoxComponents& components, const zeus::CVector3f& dir,
|
||||
double& dOut, CCollisionInfo& info) const;
|
||||
bool SphereCollisionBoolean(const COBBTree::CNode& node, const zeus::CTransform& xf, const zeus::CSphere& sphere,
|
||||
const zeus::COBBox& obb, const CMaterialFilter& filter) const;
|
||||
bool AABoxCollisionBoolean(const COBBTree::CNode& node, const zeus::CTransform& xf, const zeus::CAABox& aabb,
|
||||
const zeus::COBBox& obb, const CMaterialFilter& filter) const;
|
||||
bool SphereCollideWithLeaf(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf, const zeus::CSphere& sphere,
|
||||
const CMaterialList& material, const CMaterialFilter& filter, CCollisionInfoList& infoList) const;
|
||||
bool SphereCollision(const COBBTree::CNode& node, const zeus::CTransform& xf, const zeus::CSphere& sphere,
|
||||
const zeus::COBBox& obb, const CMaterialList& material, const CMaterialFilter& filter,
|
||||
CCollisionInfoList& infoList) const;
|
||||
bool AABoxCollideWithLeaf(const COBBTree::CLeafData& leaf, const zeus::CTransform& xf, const zeus::CAABox& aabb,
|
||||
const CMaterialList& material, const CMaterialFilter& filter, const zeus::CPlane* planes,
|
||||
CCollisionInfoList& infoList) const;
|
||||
bool AABoxCollision(const COBBTree::CNode& node, const zeus::CTransform& xf, const zeus::CAABox& aabb,
|
||||
const zeus::COBBox& obb, const CMaterialList& material, const CMaterialFilter& filter,
|
||||
const zeus::CPlane* planes, CCollisionInfoList& infoList) const;
|
||||
public:
|
||||
CCollidableOBBTree(const COBBTree* tree, const CMaterialList& material);
|
||||
virtual ~CCollidableOBBTree() = default;
|
||||
|
@ -32,8 +79,8 @@ public:
|
|||
u32 GetTableIndex() const { return sTableIndex; }
|
||||
zeus::CAABox CalculateAABox(const zeus::CTransform &) const;
|
||||
zeus::CAABox CalculateLocalAABox() const;
|
||||
virtual FourCC GetPrimType() const;
|
||||
virtual CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const;
|
||||
FourCC GetPrimType() const;
|
||||
CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include "CCollidableOBBTreeGroup.hpp"
|
||||
#include "CCollidableOBBTree.hpp"
|
||||
#include "CCollidableAABox.hpp"
|
||||
#include "CCollidableSphere.hpp"
|
||||
#include "CInternalRayCastStructure.hpp"
|
||||
#include "CollisionUtil.hpp"
|
||||
#include "CToken.hpp"
|
||||
|
||||
namespace urde
|
||||
|
@ -37,7 +41,7 @@ CCollidableOBBTreeGroup::CCollidableOBBTreeGroup(const CCollidableOBBTreeGroupCo
|
|||
|
||||
void CCollidableOBBTreeGroup::ResetTestStats() const
|
||||
{
|
||||
|
||||
/* Remove me? */
|
||||
}
|
||||
|
||||
u32 CCollidableOBBTreeGroup::GetTableIndex() const
|
||||
|
@ -60,9 +64,35 @@ FourCC CCollidableOBBTreeGroup::GetPrimType() const
|
|||
return SBIG('OBTG');
|
||||
}
|
||||
|
||||
CRayCastResult CCollidableOBBTreeGroup::CastRayInternal(const CInternalRayCastStructure&) const
|
||||
CRayCastResult CCollidableOBBTreeGroup::CastRayInternal(const CInternalRayCastStructure& rayCast) const
|
||||
{
|
||||
return {};
|
||||
CRayCastResult ret;
|
||||
|
||||
zeus::CMRay xfRay = rayCast.GetRay().getInvUnscaledTransformRay(rayCast.GetTransform());
|
||||
auto aabbIt = x10_container->x10_aabbs.cbegin();
|
||||
float mag = rayCast.GetMaxTime();
|
||||
for (const std::unique_ptr<COBBTree>& tree : x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), GetMaterial());
|
||||
float tMin = 0.f;
|
||||
float tMax = 0.f;
|
||||
if (CollisionUtil::RayAABoxIntersection(xfRay, *aabbIt++, tMin, tMax))
|
||||
{
|
||||
CInternalRayCastStructure localCast(xfRay.start, xfRay.dir, mag,
|
||||
zeus::CTransform::Identity(), rayCast.GetFilter());
|
||||
CRayCastResult localResult = obbTree.CastRayInternal(localCast);
|
||||
if (localResult.IsValid())
|
||||
{
|
||||
if (ret.IsInvalid() || localResult.GetT() < ret.GetT())
|
||||
{
|
||||
ret = localResult;
|
||||
mag = localResult.GetT();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const CCollisionPrimitive::Type& CCollidableOBBTreeGroup::GetType()
|
||||
|
@ -75,34 +105,163 @@ void CCollidableOBBTreeGroup::SetStaticTableIndex(u32 index)
|
|||
sTableIndex = index;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::SphereCollide(const CInternalCollisionStructure &, CCollisionInfoList &)
|
||||
bool CCollidableOBBTreeGroup::SphereCollide(const CInternalCollisionStructure& collision, CCollisionInfoList& list)
|
||||
{
|
||||
bool ret = false;
|
||||
const CCollidableSphere& p0 = static_cast<const CCollidableSphere&>(collision.GetLeft().GetPrim());
|
||||
const CCollidableOBBTreeGroup& p1 = static_cast<const CCollidableOBBTreeGroup&>(collision.GetRight().GetPrim());
|
||||
|
||||
zeus::CSphere s0 = p0.Transform(collision.GetLeft().GetTransform());
|
||||
zeus::COBBox obb1 = zeus::COBBox::FromAABox(p0.CalculateLocalAABox(),
|
||||
collision.GetRight().GetTransform().inverse() * collision.GetLeft().GetTransform());
|
||||
|
||||
for (const std::unique_ptr<COBBTree>& tree : p1.x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), p1.GetMaterial());
|
||||
if (obbTree.SphereCollision(obbTree.x10_tree->GetRoot(), collision.GetRight().GetTransform(),
|
||||
s0, obb1, p0.GetMaterial(), collision.GetLeft().GetFilter(), list))
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::SphereCollideBoolean(const CInternalCollisionStructure& collision)
|
||||
{
|
||||
const CCollidableSphere& p0 = static_cast<const CCollidableSphere&>(collision.GetLeft().GetPrim());
|
||||
const CCollidableOBBTreeGroup& p1 = static_cast<const CCollidableOBBTreeGroup&>(collision.GetRight().GetPrim());
|
||||
|
||||
zeus::CSphere s0 = p0.Transform(collision.GetLeft().GetTransform());
|
||||
zeus::COBBox obb1 = zeus::COBBox::FromAABox(p0.CalculateLocalAABox(),
|
||||
collision.GetRight().GetTransform().inverse() * collision.GetLeft().GetTransform());
|
||||
|
||||
for (const std::unique_ptr<COBBTree>& tree : p1.x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), p1.GetMaterial());
|
||||
if (obbTree.SphereCollisionBoolean(obbTree.x10_tree->GetRoot(), collision.GetRight().GetTransform(),
|
||||
s0, obb1, collision.GetLeft().GetFilter()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::SphereCollideBoolean(const CInternalCollisionStructure &)
|
||||
bool CCollidableOBBTreeGroup::CollideMovingSphere(const CInternalCollisionStructure& collision, const zeus::CVector3f& dir,
|
||||
double& mag, CCollisionInfo& info)
|
||||
{
|
||||
bool ret = false;
|
||||
const CCollidableSphere& p0 = static_cast<const CCollidableSphere&>(collision.GetLeft().GetPrim());
|
||||
const CCollidableOBBTreeGroup& p1 = static_cast<const CCollidableOBBTreeGroup&>(collision.GetRight().GetPrim());
|
||||
|
||||
zeus::CSphere s0 = p0.Transform(collision.GetLeft().GetTransform());
|
||||
|
||||
zeus::CAABox movedAABB = p0.CalculateLocalAABox();
|
||||
zeus::CVector3f moveVec = float(mag) * dir;
|
||||
movedAABB.accumulateBounds(movedAABB.min + moveVec);
|
||||
movedAABB.accumulateBounds(movedAABB.max + moveVec);
|
||||
|
||||
zeus::COBBox p0Obb =
|
||||
zeus::COBBox::FromAABox(movedAABB,
|
||||
collision.GetRight().GetTransform().inverse() * collision.GetLeft().GetTransform());
|
||||
|
||||
for (const std::unique_ptr<COBBTree>& tree : p1.x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), p1.GetMaterial());
|
||||
CMetroidAreaCollider::ResetInternalCounters();
|
||||
if (obbTree.SphereCollisionMoving(obbTree.x10_tree->GetRoot(), collision.GetRight().GetTransform(),
|
||||
s0, p0Obb, p0.GetMaterial(), collision.GetLeft().GetFilter(),
|
||||
dir, mag, info))
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::AABoxCollide(const CInternalCollisionStructure& collision, CCollisionInfoList& list)
|
||||
{
|
||||
bool ret = false;
|
||||
const CCollidableAABox& p0 = static_cast<const CCollidableAABox&>(collision.GetLeft().GetPrim());
|
||||
const CCollidableOBBTreeGroup& p1 = static_cast<const CCollidableOBBTreeGroup&>(collision.GetRight().GetPrim());
|
||||
|
||||
zeus::CAABox b0 = p0.CalculateAABox(collision.GetLeft().GetTransform());
|
||||
zeus::COBBox p0Obb =
|
||||
zeus::COBBox::FromAABox(p0.CalculateLocalAABox(),
|
||||
collision.GetRight().GetTransform().inverse() * collision.GetLeft().GetTransform());
|
||||
|
||||
zeus::CPlane planes[] =
|
||||
{
|
||||
{zeus::CVector3f::skRight, b0.min.dot(zeus::CVector3f::skRight)},
|
||||
{zeus::CVector3f::skLeft, b0.max.dot(zeus::CVector3f::skLeft)},
|
||||
{zeus::CVector3f::skForward, b0.min.dot(zeus::CVector3f::skForward)},
|
||||
{zeus::CVector3f::skBack, b0.max.dot(zeus::CVector3f::skBack)},
|
||||
{zeus::CVector3f::skUp, b0.min.dot(zeus::CVector3f::skUp)},
|
||||
{zeus::CVector3f::skDown, b0.max.dot(zeus::CVector3f::skDown)}
|
||||
};
|
||||
|
||||
for (const std::unique_ptr<COBBTree>& tree : p1.x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), p1.GetMaterial());
|
||||
if (obbTree.AABoxCollision(obbTree.x10_tree->GetRoot(), collision.GetRight().GetTransform(),
|
||||
b0, p0Obb, p0.GetMaterial(), collision.GetLeft().GetFilter(),
|
||||
planes, list))
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::AABoxCollideBoolean(const CInternalCollisionStructure& collision)
|
||||
{
|
||||
const CCollidableAABox& p0 = static_cast<const CCollidableAABox&>(collision.GetLeft().GetPrim());
|
||||
const CCollidableOBBTreeGroup& p1 = static_cast<const CCollidableOBBTreeGroup&>(collision.GetRight().GetPrim());
|
||||
|
||||
zeus::CAABox b0 = p0.CalculateAABox(collision.GetLeft().GetTransform());
|
||||
zeus::COBBox p0Obb =
|
||||
zeus::COBBox::FromAABox(p0.CalculateLocalAABox(),
|
||||
collision.GetRight().GetTransform().inverse() * collision.GetLeft().GetTransform());
|
||||
|
||||
for (const std::unique_ptr<COBBTree>& tree : p1.x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), p1.GetMaterial());
|
||||
if (obbTree.AABoxCollisionBoolean(obbTree.x10_tree->GetRoot(), collision.GetRight().GetTransform(),
|
||||
b0, p0Obb, collision.GetLeft().GetFilter()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::CollideMovingSphere(const CInternalCollisionStructure &, const zeus::CVector3f &, double &, CCollisionInfo &)
|
||||
bool CCollidableOBBTreeGroup::CollideMovingAABox(const CInternalCollisionStructure& collision, const zeus::CVector3f& dir,
|
||||
double& mag, CCollisionInfo& info)
|
||||
{
|
||||
return false;
|
||||
bool ret = false;
|
||||
const CCollidableAABox& p0 = static_cast<const CCollidableAABox&>(collision.GetLeft().GetPrim());
|
||||
const CCollidableOBBTreeGroup& p1 = static_cast<const CCollidableOBBTreeGroup&>(collision.GetRight().GetPrim());
|
||||
|
||||
zeus::CAABox b0 = p0.CalculateAABox(collision.GetLeft().GetTransform());
|
||||
|
||||
CMovingAABoxComponents components(b0, dir);
|
||||
|
||||
zeus::CAABox movedAABB = p0.CalculateLocalAABox();
|
||||
zeus::CVector3f moveVec = float(mag) * dir;
|
||||
movedAABB.accumulateBounds(movedAABB.min + moveVec);
|
||||
movedAABB.accumulateBounds(movedAABB.max + moveVec);
|
||||
|
||||
zeus::COBBox p0Obb =
|
||||
zeus::COBBox::FromAABox(movedAABB,
|
||||
collision.GetRight().GetTransform().inverse() * collision.GetLeft().GetTransform());
|
||||
|
||||
for (const std::unique_ptr<COBBTree>& tree : p1.x10_container->x0_trees)
|
||||
{
|
||||
CCollidableOBBTree obbTree(tree.get(), p1.GetMaterial());
|
||||
CMetroidAreaCollider::ResetInternalCounters();
|
||||
if (obbTree.AABoxCollisionMoving(obbTree.x10_tree->GetRoot(), collision.GetRight().GetTransform(),
|
||||
b0, p0Obb, p0.GetMaterial(), collision.GetLeft().GetFilter(),
|
||||
components, dir, mag, info))
|
||||
ret = true;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::AABoxCollide(const CInternalCollisionStructure &, CCollisionInfoList &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::AABoxCollideBoolean(const CInternalCollisionStructure &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCollidableOBBTreeGroup::CollideMovingAABox(const CInternalCollisionStructure &, const zeus::CVector3f &, double &, CCollisionInfo &)
|
||||
{
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CFactoryFnReturn FCollidableOBBTreeGroupFactory(const SObjectTag &tag, CInputStream& in,
|
||||
|
|
|
@ -11,11 +11,12 @@ class CInternalRayCastStructure
|
|||
zeus::CMRay x0_ray;
|
||||
float x38_maxTime;
|
||||
zeus::CTransform x3c_xf;
|
||||
CMaterialFilter x6c_filter;
|
||||
const CMaterialFilter& x6c_filter;
|
||||
public:
|
||||
CInternalRayCastStructure(const zeus::CVector3f& start, const zeus::CVector3f& dir, float length,
|
||||
const zeus::CTransform& xf, const CMaterialFilter& filter)
|
||||
: x0_ray(start, dir, length),
|
||||
x38_maxTime(length),
|
||||
x3c_xf(xf),
|
||||
x6c_filter(filter)
|
||||
{
|
||||
|
|
|
@ -820,14 +820,14 @@ bool CMetroidAreaCollider::MovingAABoxCollisionCheck_Cached(const COctreeLeafCac
|
|||
for (int k=0 ; k<3 ; ++k)
|
||||
{
|
||||
u16 vertIdx = vertIndices[k];
|
||||
zeus::CVector3f point = node.GetOwner().GetVert(vertIdx);
|
||||
zeus::CVector3f vtx = node.GetOwner().GetVert(vertIdx);
|
||||
if (g_DupPrimitiveCheckCount != g_DupVertexList[vertIdx])
|
||||
{
|
||||
g_DupVertexList[vertIdx] = g_DupPrimitiveCheckCount;
|
||||
if (movedAABB.pointInside(point))
|
||||
if (movedAABB.pointInside(vtx))
|
||||
{
|
||||
d = dOut;
|
||||
if (MovingAABoxCollisionCheck_TriVertexBox(point, aabb, dir, d,
|
||||
if (MovingAABoxCollisionCheck_TriVertexBox(vtx, aabb, dir, d,
|
||||
normal, point) && d < dOut)
|
||||
{
|
||||
CMaterialList vertMat(node.GetOwner().GetVertMaterial(vertIdx));
|
||||
|
|
|
@ -75,6 +75,7 @@ struct SBoxEdge
|
|||
class CMovingAABoxComponents
|
||||
{
|
||||
friend class CMetroidAreaCollider;
|
||||
friend class CCollidableOBBTree;
|
||||
rstl::reserved_vector<SBoxEdge, 12> x0_edges;
|
||||
rstl::reserved_vector<u32, 8> x6c4_vertIdxs;
|
||||
zeus::CAABox x6e8_aabb;
|
||||
|
@ -84,6 +85,7 @@ public:
|
|||
|
||||
class CMetroidAreaCollider
|
||||
{
|
||||
friend class CCollidableOBBTree;
|
||||
static u32 g_CalledClip;
|
||||
static u32 g_RejectedByClip;
|
||||
static u32 g_TrianglesProcessed;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "COBBTree.hpp"
|
||||
#include "CCollidableOBBTreeGroup.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -29,6 +30,12 @@ COBBTree::COBBTree(CInputStream& in)
|
|||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<CCollidableOBBTreeGroupContainer>
|
||||
COBBTree::BuildOrientedBoundingBoxTree(const zeus::CVector3f& a, const zeus::CVector3f& b)
|
||||
{
|
||||
return std::make_unique<CCollidableOBBTreeGroupContainer>(a, b);
|
||||
}
|
||||
|
||||
CCollisionSurface COBBTree::GetSurface(u16 idx) const
|
||||
{
|
||||
u32 surfIdx = idx * 3;
|
||||
|
@ -52,6 +59,50 @@ CCollisionSurface COBBTree::GetSurface(u16 idx) const
|
|||
x18_indexData.x60_vertices[vert3], mat);
|
||||
}
|
||||
|
||||
void COBBTree::GetTriangleVertexIndices(u16 idx, u16 indicesOut[3]) const
|
||||
{
|
||||
const CCollisionEdge& e0 = x18_indexData.x40_edges[x18_indexData.x50_surfaceIndices[idx*3]];
|
||||
const CCollisionEdge& e1 = x18_indexData.x40_edges[x18_indexData.x50_surfaceIndices[idx*3+1]];
|
||||
indicesOut[2] =
|
||||
(e1.GetVertIndex1() != e0.GetVertIndex1() && e1.GetVertIndex1() != e0.GetVertIndex2()) ?
|
||||
e1.GetVertIndex1() : e1.GetVertIndex2();
|
||||
|
||||
u32 material = x18_indexData.x0_materials[x18_indexData.x30_surfaceMaterials[idx]];
|
||||
if (material & 0x2000000)
|
||||
{
|
||||
indicesOut[0] = e0.GetVertIndex2();
|
||||
indicesOut[1] = e0.GetVertIndex1();
|
||||
}
|
||||
else
|
||||
{
|
||||
indicesOut[0] = e0.GetVertIndex1();
|
||||
indicesOut[1] = e0.GetVertIndex2();
|
||||
}
|
||||
}
|
||||
|
||||
CCollisionSurface COBBTree::GetTransformedSurface(u16 idx, const zeus::CTransform& xf) const
|
||||
{
|
||||
u32 surfIdx = idx * 3;
|
||||
CCollisionEdge edge1 = x18_indexData.x40_edges[x18_indexData.x50_surfaceIndices[surfIdx]];
|
||||
CCollisionEdge edge2 = x18_indexData.x40_edges[x18_indexData.x50_surfaceIndices[surfIdx + 1]];
|
||||
u16 vert1 = edge2.GetVertIndex1();
|
||||
u16 vert2 = edge2.GetVertIndex2();
|
||||
u16 vert3 = edge1.GetVertIndex1();
|
||||
|
||||
if (vert3 == vert1 || vert3 == edge2.GetVertIndex2())
|
||||
vert3 = edge1.GetVertIndex2();
|
||||
|
||||
u32 mat = x18_indexData.x0_materials[x18_indexData.x30_surfaceMaterials[idx]];
|
||||
|
||||
if ((mat & 0x2000000) != 0)
|
||||
{
|
||||
return CCollisionSurface(xf * x18_indexData.x60_vertices[vert2], xf * x18_indexData.x60_vertices[vert1],
|
||||
xf * x18_indexData.x60_vertices[vert3], mat);
|
||||
}
|
||||
return CCollisionSurface(xf * x18_indexData.x60_vertices[vert1], xf * x18_indexData.x60_vertices[vert2],
|
||||
xf * x18_indexData.x60_vertices[vert3], mat);
|
||||
}
|
||||
|
||||
zeus::CAABox COBBTree::CalculateLocalAABox() const
|
||||
{
|
||||
return CalculateAABox(zeus::CTransform::Identity());
|
||||
|
@ -118,26 +169,6 @@ COBBTree::CNode::CNode(CInputStream& in)
|
|||
}
|
||||
}
|
||||
|
||||
COBBTree::CNode* COBBTree::CNode::GetLeft() const
|
||||
{
|
||||
return x40_left.get();
|
||||
}
|
||||
|
||||
COBBTree::CNode*COBBTree::CNode::GetRight() const
|
||||
{
|
||||
return x44_right.get();
|
||||
}
|
||||
|
||||
COBBTree::CLeafData*COBBTree::CNode::GetLeafData() const
|
||||
{
|
||||
return x48_leaf.get();
|
||||
}
|
||||
|
||||
const zeus::COBBox& COBBTree::CNode::GetOBB() const
|
||||
{
|
||||
return x0_obb;
|
||||
}
|
||||
|
||||
size_t COBBTree::CNode::GetMemoryUsage() const
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
namespace urde
|
||||
{
|
||||
class CCollidableOBBTreeGroupContainer;
|
||||
|
||||
class COBBTree
|
||||
{
|
||||
public:
|
||||
|
@ -43,19 +45,21 @@ public:
|
|||
std::unique_ptr<CNode> x40_left;
|
||||
std::unique_ptr<CNode> x44_right;
|
||||
std::unique_ptr<CLeafData> x48_leaf;
|
||||
bool x4c_hit;
|
||||
public:
|
||||
CNode() = default;
|
||||
CNode(const CNode&)=default;
|
||||
CNode(const zeus::CTransform&, const zeus::CVector3f&, const CNode*, const CNode*, const CLeafData*);
|
||||
CNode(CInputStream&);
|
||||
|
||||
bool WasHit() const;
|
||||
void SetHit(bool) const;
|
||||
CNode* GetLeft() const;
|
||||
CNode* GetRight() const;
|
||||
CLeafData* GetLeafData() const;
|
||||
const zeus::COBBox& GetOBB() const;
|
||||
bool WasHit() const { return x4c_hit; }
|
||||
void SetHit(bool h) { x4c_hit = h; }
|
||||
const CNode& GetLeft() const { return *x40_left; }
|
||||
const CNode& GetRight() const { return *x44_right; }
|
||||
const CLeafData& GetLeafData() const { return *x48_leaf; }
|
||||
const zeus::COBBox& GetOBB() const { return x0_obb; }
|
||||
size_t GetMemoryUsage() const;
|
||||
bool IsLeaf() const { return x3c_isLeaf; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -71,9 +75,19 @@ public:
|
|||
COBBTree(const COBBTree::SIndexData&, const CNode*);
|
||||
COBBTree(CInputStream&);
|
||||
|
||||
CCollisionSurface GetSurface(u16) const;
|
||||
static std::unique_ptr<CCollidableOBBTreeGroupContainer>
|
||||
BuildOrientedBoundingBoxTree(const zeus::CVector3f&, const zeus::CVector3f&);
|
||||
CCollisionSurface GetSurface(u16 idx) const;
|
||||
const u16* GetTriangleEdgeIndices(u16 idx) const { return &x18_indexData.x50_surfaceIndices[idx * 3]; }
|
||||
void GetTriangleVertexIndices(u16 idx, u16 indicesOut[3]) const;
|
||||
const CCollisionEdge& GetEdge(int idx) const { return x18_indexData.x40_edges[idx]; }
|
||||
const zeus::CVector3f& GetVert(int idx) const { return x18_indexData.x60_vertices[idx]; }
|
||||
u32 GetVertMaterial(u16 idx) const { return x18_indexData.x0_materials[x18_indexData.x10_vertMaterials[idx]]; }
|
||||
u32 GetEdgeMaterial(u16 idx) const { return x18_indexData.x0_materials[x18_indexData.x20_edgeMaterials[idx]]; }
|
||||
CCollisionSurface GetTransformedSurface(u16 idx, const zeus::CTransform& xf) const;
|
||||
zeus::CAABox CalculateLocalAABox() const;
|
||||
zeus::CAABox CalculateAABox(const zeus::CTransform&) const;
|
||||
const CNode& GetRoot() const { return *x88_root; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,46 @@ bool LineIntersectsOBBox(const zeus::COBBox& obb, const zeus::CMRay& ray, float&
|
|||
norm, d);
|
||||
}
|
||||
|
||||
u32 RayAABoxIntersection(const zeus::CMRay& ray, const zeus::CAABox& aabb, float& tMin, float& tMax)
|
||||
{
|
||||
tMin = -999999.f;
|
||||
tMax = 999999.f;
|
||||
|
||||
for (int i=0 ; i<3 ; ++i)
|
||||
{
|
||||
if (std::fabs(ray.dir[i]) < 0.00001f)
|
||||
{
|
||||
if (ray.start[i] < aabb.min[i] || ray.start[i] > aabb.max[i])
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ray.dir[i] < 0.f)
|
||||
{
|
||||
float startToMax = aabb.max[i] - ray.start[i];
|
||||
float startToMin = aabb.min[i] - ray.start[i];
|
||||
float dirRecip = 1.f / ray.dir[i];
|
||||
if (startToMax < tMin * ray.dir[i])
|
||||
tMin = startToMax * dirRecip;
|
||||
if (startToMin > tMax * ray.dir[i])
|
||||
tMax = startToMin * dirRecip;
|
||||
}
|
||||
else
|
||||
{
|
||||
float startToMin = aabb.min[i] - ray.start[i];
|
||||
float startToMax = aabb.max[i] - ray.start[i];
|
||||
float dirRecip = 1.f / ray.dir[i];
|
||||
if (startToMin > tMin * ray.dir[i])
|
||||
tMin = startToMin * dirRecip;
|
||||
if (startToMax < tMax * ray.dir[i])
|
||||
tMax = startToMax * dirRecip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tMin <= tMax ? 2 : 0;
|
||||
}
|
||||
|
||||
u32 RayAABoxIntersection(const zeus::CMRay& ray, const zeus::CAABox& aabb,
|
||||
zeus::CVector3f& norm, float& d)
|
||||
{
|
||||
|
@ -277,6 +317,30 @@ bool RayTriangleIntersection_Double(const zeus::CVector3f& point, const zeus::CV
|
|||
return true;
|
||||
}
|
||||
|
||||
bool RayTriangleIntersection(const zeus::CVector3f& point, const zeus::CVector3f& dir,
|
||||
const zeus::CVector3f* verts, float& d)
|
||||
{
|
||||
zeus::CVector3f v0tov1 = verts[1] - verts[0];
|
||||
zeus::CVector3f v0tov2 = verts[2] - verts[0];
|
||||
zeus::CVector3f cross0 = dir.cross(v0tov2);
|
||||
float dot0 = v0tov1.dot(cross0);
|
||||
if (dot0 < DBL_EPSILON)
|
||||
return false;
|
||||
zeus::CVector3f v0toPoint = point - verts[0];
|
||||
float dot1 = v0toPoint.dot(cross0);
|
||||
if (dot1 < 0.0 || dot1 > dot0)
|
||||
return false;
|
||||
zeus::CVector3f cross1 = v0toPoint.cross(v0tov1);
|
||||
float dot2 = cross1.dot(dir);
|
||||
if (dot2 < 0.0 || dot1 + dot2 > dot0)
|
||||
return false;
|
||||
float final = 1.0 / dot0 * cross1.dot(v0tov2);
|
||||
if (final < 0.0 || final >= d)
|
||||
return false;
|
||||
d = final;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in, CCollisionInfoList& out)
|
||||
{
|
||||
if (vec.canBeNormalized())
|
||||
|
|
|
@ -11,6 +11,7 @@ class CCollisionInfoList;
|
|||
namespace CollisionUtil
|
||||
{
|
||||
bool LineIntersectsOBBox(const zeus::COBBox&, const zeus::CMRay&, float&);
|
||||
u32 RayAABoxIntersection(const zeus::CMRay&, const zeus::CAABox&, float&, float&);
|
||||
u32 RayAABoxIntersection(const zeus::CMRay&, const zeus::CAABox&, zeus::CVector3f&, float&);
|
||||
u32 RayAABoxIntersection_Double(const zeus::CMRay&, const zeus::CAABox&, zeus::CVector3f&, double&);
|
||||
bool RaySphereIntersection_Double(const zeus::CSphere&, const zeus::CVector3f&, const zeus::CVector3f&, double&);
|
||||
|
@ -18,6 +19,8 @@ bool RaySphereIntersection(const zeus::CSphere& sphere, const zeus::CVector3f& p
|
|||
float mag, float& T, zeus::CVector3f& point);
|
||||
bool RayTriangleIntersection_Double(const zeus::CVector3f& point, const zeus::CVector3f& dir,
|
||||
const zeus::CVector3f* verts, double& d);
|
||||
bool RayTriangleIntersection(const zeus::CVector3f& point, const zeus::CVector3f& dir,
|
||||
const zeus::CVector3f* verts, float& d);
|
||||
void FilterOutBackfaces(const zeus::CVector3f& vec, const CCollisionInfoList& in, CCollisionInfoList& out);
|
||||
void FilterByClosestNormal(const zeus::CVector3f& norm, const CCollisionInfoList& in, CCollisionInfoList& out);
|
||||
bool AABoxAABoxIntersection(const zeus::CAABox& aabb0, const CMaterialList& list0,
|
||||
|
|
2
nod
2
nod
|
@ -1 +1 @@
|
|||
Subproject commit 6454d68abc2180a33aa4359c0ed3906519083c7e
|
||||
Subproject commit 8bdbcf0c9080f26c7fdb9364af03f1dd6b74c350
|
2
specter
2
specter
|
@ -1 +1 @@
|
|||
Subproject commit 1c17a28648e33d52a0eaea1e272da49ac6a940dd
|
||||
Subproject commit c35ccdd3cd7517e4e277d02e336997b519d00162
|
Loading…
Reference in New Issue