-
[DirectX11] 기본 게임 도형(Sphere,AABB,OBB등)과 Point Test2024년 03월 14일
- 유니얼
-
작성자
-
2024.03.14.:00
728x90DirectX 11로 게임 엔진 아키텍처 만들기
게임 개발, 특히 3D 게임 개발에서 수학은 게임 월드를 형성하고, 객체 간의 상호 작용을 정의하는 데 필수적인 도구입니다. 복잡한 3D 공간에서의 상호 작용을 가능하게 하는 기본적인 수학적 개념과 알고리즘을 이해하는 것은, 개발자가 현실감 있는 게임 환경을 구축하고 풍부한 게임 플레이 경험을 제공하는 데 도움이 됩니다. 이 글에서는 3D 게임 개발에 자주 사용되는 기본 도형들과, 이들 간의 점 테스트(Point Test) 방법을 중점적으로 살펴보겠습니다.
참고강의 링크:
3D 게임 개발의 기본 도형
3D 게임 개발에는 여러 기본 도형이 사용됩니다. 이들 도형은 게임 월드를 구성하는 요소로, 다음과 같은 역할을 합니다:
- Sphere(구): 충돌 감지, 영역 내 객체 판별 등에 사용됩니다.
- AABB(Axis-Aligned Bounding Box, 축에 정렬된 경계 상자): 빠른 충돌 감지와 공간 분할에 유용합니다.
- OBB(Oriented Bounding Box, 방향이 있는 경계 상자): AABB보다 정밀한 충돌 감지에 사용되며, 객체의 회전을 고려할 수 있습니다.
- Plane(평면): 게임 월드에서의 지면이나 벽 등을 모델링하는 데 사용됩니다.
- Ray(광선): 시야 판별, 레이캐스팅 등에 활용됩니다.
점 테스트(Point Test)
점 테스트는 주어진 점이 특정 도형 내부에 있는지를 판별하는 과정입니다. 이는 충돌 감지, 객체 선택, 시야 판별 등 다양한 게임 메커니즘에 핵심적인 역할을 합니다. 점 테스트의 구현은 도형의 종류에 따라 다르며, 각 도형에 맞는 수학적 계산을 필요로 합니다.
PointInSphere
- PointInSphere: 구와 점 사이의 거리 제곱이 구의 반지름 제곱 이하일 때, 점은 구 내부에 있습니다. 이는 구의 중심에서 점까지의 벡터의 크기를 계산하여 확인할 수 있습니다.
- ClossetPoint: 구의 표면 위에서 주어진 점에 가장 가까운 점은, 구의 중심에서 주어진 점으로의 단위 벡터 방향으로 반지름을 곱한 값으로 계산할 수 있습니다.
// 점이 구 안에 있는지 판별합니다. bool MathUtils::PointInSphere(const Point3D& point, const Sphere3D& sphere) { float magSq = (point - sphere.position).LengthSquared(); float radSq = sphere.radius * sphere.radius; return magSq <= radSq; } // 구에서 주어진 점에 가장 가까운 점을 찾습니다. Point3D MathUtils::ClossetPoint(const Sphere3D& sphere, const Point3D& point) { Vec3 sphereToPointDir = (point - sphere.position); sphereToPointDir.Normalize(); return sphere.position + sphereToPointDir * sphere.radius; }
PointInAABB
- PointInAABB: 점이 AABB 내부에 있는지 확인하기 위해, 점의 각 좌표가 AABB의 최소 좌표와 최대 좌표 사이에 있는지 확인합니다.
- ClossetPoint: 주어진 점과 AABB의 가장 가까운 점은, 각 축에 대해 주어진 점의 좌표를 AABB의 최소 좌표와 최대 좌표 사이로 제한함으로써 계산할 수 있습니다.
// 점이 AABB 안에 있는지 판별합니다. bool MathUtils::PointInAABB(const Point3D& point, const AABB3D& aabb) { Point3D min = AABB3D::GetMin(aabb); Point3D max = AABB3D::GetMax(aabb); if (point.x < min.x || point.y < min.y || point.z < min.z) return false; if (point.x > max.x || point.y > max.y || point.z > max.z) return false; return true; } // AABB에서 주어진 점에 가장 가까운 점을 찾습니다. Point3D MathUtils::ClossetPoint(const AABB3D& aabb, const Point3D& point) { Point3D result = point; Point3D minPt = AABB3D::GetMin(aabb); Point3D maxPt = AABB3D::GetMax(aabb); result.x = max(result.x, minPt.x); result.y = max(result.y, minPt.y); result.z = max(result.z, minPt.z); result.x = min(result.x, minPt.x); result.y = min(result.y, minPt.y); result.z = min(result.z, minPt.z); return result; }
PointInOBB
- PointInOBB: 점이 OBB 내부에 있는지 확인하기 위해, 점으로부터 OBB의 중심까지의 벡터를 OBB의 방향 벡터(오리엔테이션)로 투영하고, 이 투영된 거리가 OBB의 각 축에 대한 크기 이내인지 확인합니다.
- ClossetPoint: OBB에서 주어진 점에 가장 가까운 점은, 점에서 OBB의 중심으로의 벡터를 OBB의 각 축 방향으로 투영하고, 이를 OBB의 크기 내로 제한한 후, OBB의 중심에서 이 제한된 투영 벡터를 이용해 계산합니다.
// 점이 OBB 안에 있는지 판별합니다. bool MathUtils::PointInOBB(const Point3D& point, const OBB3D& obb) { Vec3 dir = point - obb.position; vector<Vec3> axis = { obb.orientation.Right(), obb.orientation.Up(), obb.orientation.Backward() }; vector<float> size = { obb.size.x, obb.size.y, obb.size.z }; for (int i = 0; i < 3; i++) { float distance = dir.Dot(axis[i]); if (distance > size[i] || distance < -size[i]) return false; } return true; } // OBB에서 주어진 점에 가장 가까운 점을 찾습니다. Point3D MathUtils::ClossetPoint(const OBB3D& obb, const Point3D& point) { Vec3 dir = point - obb.position; Point3D result; vector<Vec3> axis = { obb.orientation.Right(), obb.orientation.Up(), obb.orientation.Backward() }; vector<float> size = { obb.size.x, obb.size.y, obb.size.z }; for (int i = 0; i < 3; i++) { float distance = dir.Dot(axis[i]); distance = clamp(distance, -size[i], size[i]); result = result + (axis[i] * distance); } return obb.position + result; }
PointInPlane
- PointInPlane: 점이 평면 위에 있는지 확인하기 위해, 점의 위치와 평면의 법선 벡터를 내적한 값이 평면으로부터의 거리와 같은지 확인합니다.
- ClossetPoint: 평면에서 주어진 점에 가장 가까운 점은, 점에서 평면의 법선 방향으로 평면까지의 거리만큼 이동한 위치입니다.
// 점이 평면 위에 있는지 판별합니다. bool MathUtils::PointInPlane(const Point3D& point, const Plane3D& plane) { float dot = point.Dot(plane.normal); return fabs(dot - plane.distance) < FLT_EPSILON; // 부동소수점 비교 시 EPSILON 사용 } // 평면에서 주어진 점에 가장 가까운 점을 찾습니다. Point3D MathUtils::ClossetPoint(const Plane3D& plane, const Point3D& point) { float dot = point.Dot(plane.normal); float distance = dot - plane.distance; return point - plane.normal * distance; }
PointInLine, PointInRay
- PointInLine, PointInRay: 점이 선이나 광선 위에 있는지 확인하기 위해, 선이나 광선의 방향과 점으로부터 선이나 광선의 시작점까지의 벡터를 내적하여 그 결과가 1에 가까운지 확인합니다. 이는 점이 해당 선이나 광선 위에 정확히 있거나, 시작점에 있는 경우입니다.
- ClossetPoint: 선이나 광선에서 주어진 점에 가장 가까운 점은, 선이나 광선의 시작점에서 주어진 점까지의 벡터를 선이나 광선의 방향 벡터로 투영하고, 이 투영된 길이를 이용하여 계산합니다. 이때, 광선의 경우 투영된 길이가 음수일 경우 시작점이 가장 가까운 점이 됩니다.
// 점이 선 위에 있는지 판별합니다. bool MathUtils::PointInLine(const Point3D& point, const Line3D& line) { Point3D closest = ClossetPoint(line, point); return (closest - point).LengthSquared() == 0.f; } // 선에서 주어진 점에 가장 가까운 점을 찾습니다. Point3D MathUtils::ClossetPoint(const Line3D& line, const Point3D& point) { Vec3 lineVec = line.end - line.start; float t = (point - line.start).Dot(lineVec) / lineVec.Dot(lineVec); t = clamp(t, 0.0f, 1.0f); // t 값을 0과 1 사이로 제한 return line.start + lineVec * t; }
// 점이 광선 위에 있는지 판별합니다. bool MathUtils::PointInRay(const Point3D& point, const Ray3D& ray) { if (point == ray.origin) return true; Vec3 norm = point - ray.origin; norm.Normalize(); return fabs(norm.Dot(ray.direction) - 1.0f) < FLT_EPSILON; // 방향 비교 시 EPSILON 사용 } // 광선에서 주어진 점에 가장 가까운 점을 찾습니다. Point3D MathUtils::ClossetPoint(const Ray3D& ray, const Point3D& point) { float t = (point - ray.origin).Dot(ray.direction); t = fmaxf(t, 0.0f); // t가 음수이면 0으로 설정 return ray.origin + ray.direction * t; }
결론
3D 게임 개발에서의 수학은 게임 월드의 구성과 게임 오브젝트 간의 상호 작용을 정의하는 데 매우 중요합니다. 기본 도형과 점 테스트 같은 기본적인 수학적 개념과 알고리즘을 이해하고 활용함으로써, 개발자는 더욱 풍부하고 현실적인 게임 경험을 제공할 수 있습니다.
반응형다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드
받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이
감지되어도 모달 창이 표시되지 않습니다.)