• 티스토리 홈
  • 프로필사진
    유니얼
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
유니얼
  • 프로필사진
    유니얼
    • 분류 전체보기 (295)
      • Unity (17)
        • 게임 개발 (5)
      • Unreal (24)
        • 게임 개발 (20)
      • DirectX (36)
      • 코딩테스트 (91)
        • 프로그래머스 (25)
        • 백준 (66)
      • Google Workspace (1)
      • Programing (102)
        • C# (68)
        • C++ (24)
        • JavaScript (10)
      • 게임 서버 프로그래밍 (17)
      • Web (6)
        • 슈퍼코딩 (6)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
    등록된 댓글이 없습니다.
  • 최근 공지
    등록된 공지가 없습니다.
# Home
# 공지사항
#
# 태그
# 검색결과
# 방명록
  • [DirectX11] 기본 게임 도형(Sphere,AABB,OBB등)과 Point Test
    2024년 03월 14일
    • 유니얼
    • 작성자
    • 2024.03.14.:00
    728x90

    DirectX 11로 게임 엔진 아키텍처 만들기

    게임 개발, 특히 3D 게임 개발에서 수학은 게임 월드를 형성하고, 객체 간의 상호 작용을 정의하는 데 필수적인 도구입니다. 복잡한 3D 공간에서의 상호 작용을 가능하게 하는 기본적인 수학적 개념과 알고리즘을 이해하는 것은, 개발자가 현실감 있는 게임 환경을 구축하고 풍부한 게임 플레이 경험을 제공하는 데 도움이 됩니다. 이 글에서는 3D 게임 개발에 자주 사용되는 기본 도형들과, 이들 간의 점 테스트(Point Test) 방법을 중점적으로 살펴보겠습니다.

    참고강의 링크:

    https://www.inflearn.com/course/directx11-%EA%B2%8C%EC%9E%84%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%95%BD%EB%B0%98/dashboard

     

    [게임 프로그래머 도약반] DirectX11 입문 강의 - 인프런

    게임 프로그래머 공부에 있어서 필수적인 DirectX 11 지식을 초보자들의 눈높이에 맞춰 설명하는 강의입니다., [사진][사진] [사진] 게임 개발자는 Unreal, Unity만 사용할 줄 알면 되는 거 아닌가요? 엔

    www.inflearn.com

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

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

    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일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
목차
표시할 목차가 없습니다.
    • 안녕하세요
    • 감사해요
    • 잘있어요

    티스토리툴바