두 구가 충돌하고 있는지는 중심 간 거리와 반지름 합을 비교하면 된다.
bool MathUtils::SphereSphere(const Sphere3D& s1, const Sphere3D& s2)
{
float sum = s1.radius + s2.radius;
float sqDistance = (s1.position - s2.position).LengthSquared();
return sqDistance <= sum * sum;
}
AABB 박스에서 가장 가까운 점을 찾고, 그 점과 구 중심 간의 거리로 판별한다.
bool MathUtils::SphereAABB(const Sphere3D& sphere, const AABB3D& aabb)
{
Point3D closest = ClosestPoint(aabb, sphere.position);
float distSq = (sphere.position - closest).LengthSquared();
return distSq < sphere.radius * sphere.radius;
}
구와 OBB의 충돌도 Closest Point 방식으로 동일하게 판단.
bool MathUtils::SphereOBB(const Sphere3D& sphere, const OBB3D& obb)
{
Point3D closest = ClosestPoint(obb, sphere.position);
float distSq = (sphere.position - closest).LengthSquared();
return distSq < sphere.radius * sphere.radius;
}
bool MathUtils::SpherePlane(const Sphere3D& sphere, const Plane3D& plane)
{
Point3D closest = ClosestPoint(plane, sphere.position);
float distSq = (sphere.position - closest).LengthSquared();
return distSq < sphere.radius * sphere.radius;
}
bool MathUtils::AABBAABB(const AABB3D& aabb1, const AABB3D& aabb2)
{
Point3D aMin = AABB3D::GetMin(aabb1);
Point3D aMax = AABB3D::GetMax(aabb1);
Point3D bMin = AABB3D::GetMin(aabb2);
Point3D bMax = AABB3D::GetMax(aabb2);
return (aMin.x <= bMax.x && aMax.x >= bMin.x) &&
(aMin.y <= bMax.y && aMax.y >= bMin.y) &&
(aMin.z <= bMax.z && aMax.z >= bMin.z);
}
bool MathUtils::AABBPlane(const AABB3D& aabb, const Plane3D& plane)
{
float pLen = aabb.size.x * fabsf(plane.normal.x) +
aabb.size.y * fabsf(plane.normal.y) +
aabb.size.z * fabsf(plane.normal.z);
float dot = plane.normal.Dot(aabb.position);
float dist = dot - plane.distance;
return fabsf(dist) <= pLen;
}
3 (AABB 축) + 3 (OBB 축) + 9 (AABB축 × OBB축 외적) = 15
bool MathUtils::AABBOBB(const AABB3D& aabb, const OBB3D& obb)
{
Vec3 test[15] = {
Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1), // AABB 축
obb.orientation.Right(), obb.orientation.Up(), obb.orientation.Backward() // OBB 축
};
// AABB × OBB 축의 외적 추가
for (int i = 0; i < 3; ++i)
{
test[6 + i * 3 + 0] = test[i].Cross(test[3]);
test[6 + i * 3 + 1] = test[i].Cross(test[4]);
test[6 + i * 3 + 2] = test[i].Cross(test[5]);
}
for (int i = 0; i < 15; ++i)
{
if (!OverlapOnAxis(aabb, obb, test[i]))
return false;
}
return true;
}
bool MathUtils::OBBOBB(const OBB3D& obb1, const OBB3D& obb2)
{
Vec3 test[15] = {
obb1.orientation.Right(), obb1.orientation.Up(), obb1.orientation.Backward(),
obb2.orientation.Right(), obb2.orientation.Up(), obb2.orientation.Backward()
};
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
test[6 + i * 3 + j] = test[i].Cross(test[3 + j]);
}
}
for (int i = 0; i < 15; ++i)
{
if (!OverlapOnAxis(obb1, obb2, test[i]))
return false;
}
return true;
}
bool MathUtils::PlanePlane(const Plane3D& plane1, const Plane3D& plane2)
{
Vec3 d = plane1.normal.Cross(plane2.normal);
return d.Dot(d) != 0; // 평행하지 않으면 충돌
}