Intersection (수학)

Jaemyeong Lee·2025년 4월 2일

게임 서버1

목록 보기
217/220

🎯 1. Sphere(구) 관련 충돌

✅ Sphere to Sphere

두 구가 충돌하고 있는지는 중심 간 거리반지름 합을 비교하면 된다.

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;
}
  • 중심 간 거리 제곱이 두 구의 반지름 합의 제곱보다 작거나 같으면 겹치는 것이다.
  • 제곱 비교를 통해 루트 연산을 생략하여 성능 최적화.

✅ Sphere to AABB

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;
}
  • 핵심: AABB 바깥에 있는 구는 박스와 가장 가까운 지점을 기준으로 거리 판정.

✅ Sphere to OBB

구와 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;
}
  • OBB는 회전이 있으므로 투영 좌표계에서 가장 가까운 점을 찾는 방식 필요.

✅ Sphere to Plane

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;
}
  • 평면과 구의 중심 사이의 거리와 반지름 비교.
  • 평면과의 거리 계산은 평면 법선 벡터에 대한 내적(dot)을 이용.

📦 2. AABB 관련 충돌

✅ AABB to AABB

  • 각 축(x, y, z)에 대해 최소/최대 좌표 범위가 겹치는지 확인.
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);
}
  • Axis-Aligned(축 정렬) 되어 있으므로 이처럼 단순한 비교 가능.

✅ AABB to Plane

  • 평면의 법선 방향으로 AABB를 투영했을 때, 평면과의 거리가 일정 범위 이내면 충돌.
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;
}
  • 반응 길이(pLen) = 평면 법선 방향으로 AABB의 반 크기만큼 늘어남.

🧱 3. OBB 관련 충돌 - SAT의 핵심

📌 Separating Axis Theorem(SAT)

  • 두 도형이 충돌하지 않으려면 한 축이 존재해서, 그 축 위로 프로젝션 했을 때 겹치지 않으면 된다.
  • 이론상 총 15개의 축을 테스트해야 한다:
3 (AABB 축) + 3 (OBB 축) + 9 (AABB축 × OBB축 외적) = 15

✅ AABB to OBB

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;
}

✅ OBB to OBB

  • OBB는 AABB보다 복잡하다. 두 도형의 회전을 고려해 더 많은 축 조합 필요.
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;
}

📄 4. Plane 관련 충돌

✅ Plane to Plane

  • 두 평면의 법선 벡터가 수직이 아니면 교차한다고 본다.
bool MathUtils::PlanePlane(const Plane3D& plane1, const Plane3D& plane2)
{
    Vec3 d = plane1.normal.Cross(plane2.normal);
    return d.Dot(d) != 0; // 평행하지 않으면 충돌
}

profile
李家네_공부방

0개의 댓글