diff --git a/Runtime/Collision/CCollidableOBBTree.cpp b/Runtime/Collision/CCollidableOBBTree.cpp index 4cec33b71..786a72b4e 100644 --- a/Runtime/Collision/CCollidableOBBTree.cpp +++ b/Runtime/Collision/CCollidableOBBTree.cpp @@ -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 ; iGetSurface(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(node).SetHit(true); + } + else + { + const_cast(*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(*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(*this).x14_tries += 1; + if (obb.OBBIntersectsBox(node.GetOBB())) + { + const_cast(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(*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(*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(*this).x14_tries += 1; + if (obb.OBBIntersectsBox(node.GetOBB())) + { + const_cast(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(*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(*this).x14_tries += 1; + if (obb.OBBIntersectsBox(node.GetOBB())) + { + const_cast(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(*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(*this).x14_tries += 1; + if (obb.OBBIntersectsBox(node.GetOBB())) + { + const_cast(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(*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(*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(*this).x14_tries += 1; + if (obb.OBBIntersectsBox(node.GetOBB())) + { + const_cast(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(*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(*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(*this).x14_tries += 1; + if (obb.OBBIntersectsBox(node.GetOBB())) + { + const_cast(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(*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 diff --git a/Runtime/Collision/CCollidableOBBTree.hpp b/Runtime/Collision/CCollidableOBBTree.hpp index cf7d94bfb..47b288e2b 100644 --- a/Runtime/Collision/CCollidableOBBTree.hpp +++ b/Runtime/Collision/CCollidableOBBTree.hpp @@ -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; }; } diff --git a/Runtime/Collision/CCollidableOBBTreeGroup.cpp b/Runtime/Collision/CCollidableOBBTreeGroup.cpp index de3cdf98e..5dd2bb15d 100644 --- a/Runtime/Collision/CCollidableOBBTreeGroup.cpp +++ b/Runtime/Collision/CCollidableOBBTreeGroup.cpp @@ -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& 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(collision.GetLeft().GetPrim()); + const CCollidableOBBTreeGroup& p1 = static_cast(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& 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(collision.GetLeft().GetPrim()); + const CCollidableOBBTreeGroup& p1 = static_cast(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& 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(collision.GetLeft().GetPrim()); + const CCollidableOBBTreeGroup& p1 = static_cast(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& 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(collision.GetLeft().GetPrim()); + const CCollidableOBBTreeGroup& p1 = static_cast(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& 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(collision.GetLeft().GetPrim()); + const CCollidableOBBTreeGroup& p1 = static_cast(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& 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(collision.GetLeft().GetPrim()); + const CCollidableOBBTreeGroup& p1 = static_cast(collision.GetRight().GetPrim()); -bool CCollidableOBBTreeGroup::AABoxCollide(const CInternalCollisionStructure &, CCollisionInfoList &) -{ - return false; -} + zeus::CAABox b0 = p0.CalculateAABox(collision.GetLeft().GetTransform()); -bool CCollidableOBBTreeGroup::AABoxCollideBoolean(const CInternalCollisionStructure &) -{ - return false; -} + CMovingAABoxComponents components(b0, dir); -bool CCollidableOBBTreeGroup::CollideMovingAABox(const CInternalCollisionStructure &, const zeus::CVector3f &, double &, CCollisionInfo &) -{ - return false; + 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& 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; + } + + return ret; } CFactoryFnReturn FCollidableOBBTreeGroupFactory(const SObjectTag &tag, CInputStream& in, diff --git a/Runtime/Collision/CInternalRayCastStructure.hpp b/Runtime/Collision/CInternalRayCastStructure.hpp index 929956f71..06ebe0661 100644 --- a/Runtime/Collision/CInternalRayCastStructure.hpp +++ b/Runtime/Collision/CInternalRayCastStructure.hpp @@ -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) { diff --git a/Runtime/Collision/CMetroidAreaCollider.cpp b/Runtime/Collision/CMetroidAreaCollider.cpp index d282ca26e..62945c89a 100644 --- a/Runtime/Collision/CMetroidAreaCollider.cpp +++ b/Runtime/Collision/CMetroidAreaCollider.cpp @@ -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)); diff --git a/Runtime/Collision/CMetroidAreaCollider.hpp b/Runtime/Collision/CMetroidAreaCollider.hpp index f1c453f69..12d33d3ae 100644 --- a/Runtime/Collision/CMetroidAreaCollider.hpp +++ b/Runtime/Collision/CMetroidAreaCollider.hpp @@ -75,6 +75,7 @@ struct SBoxEdge class CMovingAABoxComponents { friend class CMetroidAreaCollider; + friend class CCollidableOBBTree; rstl::reserved_vector x0_edges; rstl::reserved_vector 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; diff --git a/Runtime/Collision/COBBTree.cpp b/Runtime/Collision/COBBTree.cpp index a49d88c09..2490ef54b 100644 --- a/Runtime/Collision/COBBTree.cpp +++ b/Runtime/Collision/COBBTree.cpp @@ -1,4 +1,5 @@ #include "COBBTree.hpp" +#include "CCollidableOBBTreeGroup.hpp" namespace urde { @@ -29,6 +30,12 @@ COBBTree::COBBTree(CInputStream& in) { } +std::unique_ptr +COBBTree::BuildOrientedBoundingBoxTree(const zeus::CVector3f& a, const zeus::CVector3f& b) +{ + return std::make_unique(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; diff --git a/Runtime/Collision/COBBTree.hpp b/Runtime/Collision/COBBTree.hpp index df47e15fb..d29cfb54a 100644 --- a/Runtime/Collision/COBBTree.hpp +++ b/Runtime/Collision/COBBTree.hpp @@ -8,6 +8,8 @@ namespace urde { +class CCollidableOBBTreeGroupContainer; + class COBBTree { public: @@ -43,19 +45,21 @@ public: std::unique_ptr x40_left; std::unique_ptr x44_right; std::unique_ptr 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 + 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; } }; } diff --git a/Runtime/Collision/CollisionUtil.cpp b/Runtime/Collision/CollisionUtil.cpp index 1bfe32d48..2e68dafb2 100644 --- a/Runtime/Collision/CollisionUtil.cpp +++ b/Runtime/Collision/CollisionUtil.cpp @@ -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()) diff --git a/Runtime/Collision/CollisionUtil.hpp b/Runtime/Collision/CollisionUtil.hpp index 7544c23e7..da39e47e0 100644 --- a/Runtime/Collision/CollisionUtil.hpp +++ b/Runtime/Collision/CollisionUtil.hpp @@ -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, diff --git a/nod b/nod index 6454d68ab..8bdbcf0c9 160000 --- a/nod +++ b/nod @@ -1 +1 @@ -Subproject commit 6454d68abc2180a33aa4359c0ed3906519083c7e +Subproject commit 8bdbcf0c9080f26c7fdb9364af03f1dd6b74c350 diff --git a/specter b/specter index 1c17a2864..c35ccdd3c 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit 1c17a28648e33d52a0eaea1e272da49ac6a940dd +Subproject commit c35ccdd3cd7517e4e277d02e336997b519d00162