🎯 충돌 감지(Collision Detection)란?

게임에서 충돌은 크게 두 가지로 나뉜다.

  1. 레이저를 쏴서 무언가를 맞추는 경우 (RayCasting)
  2. 두 개의 오브젝트가 서로 충돌하는 경우 (Object vs Object)

두 경우 모두 충돌(Collision)이라는 개념을 기반으로 한다.


🏗 CollisionDemo - 충돌 시스템 실험장

먼저 테스트를 위한 씬을 만들기 위해 CollisionDemo 클래스를 생성한다. 기존 ViewportDemo를 복사해서 Client/Game/Week3 필터에 CollisionDemo로 만든다.

이제 여기서 충돌 관련 기능을 실험할 예정이다.


🧱 BaseCollider - 모든 Collider의 부모

역할

모든 충돌 컴포넌트들의 공통 기반 클래스다. 모든 Collider는 이 클래스를 상속받는다.

enum class ColliderType { Sphere, AABB, OBB };

class BaseCollider : public Component
{
public:
	BaseCollider(ColliderType type);
	virtual bool Intersects(Ray& ray, OUT float& distance) = 0;
	ColliderType GetColliderType();
	// ...
};
  • Intersects: 레이와 충돌하는지 검사하는 추상 메서드
  • ColliderType: 어떤 타입인지 구분할 수 있도록 해주는 정보

🟢 SphereCollider - 구형 충돌체

BoundingSphere란?

DirectX에서 제공하는 구 형태의 충돌 영역. 중심점과 반지름으로 구성되며, 충돌 체크나 레이 교차 검사가 매우 효율적으로 구현돼 있다.

class SphereCollider : public BaseCollider
{
public:
	void SetRadius(float radius);
	bool Intersects(Ray& ray, OUT float& distance) override;
	void Update() override;
private:
	float _radius = 1.f;
	BoundingSphere _boundingSphere;
};

핵심 로직

  • Update()에서 오브젝트의 위치와 스케일에 따라 BoundingSphere를 갱신한다.
  • Intersects()는 레이와의 교차 검사. 내부적으로 BoundingSphere의 메서드를 활용하므로 구현은 단순하다.
void SphereCollider::Update()
{
	_boundingSphere.Center = GetGameObject()->GetTransform()->GetPosition();
	Vec3 scale = GetGameObject()->GetTransform()->GetScale();
	_boundingSphere.Radius = _radius * max(scale.x, max(scale.y, scale.z));
}

🧠 Scene::Pick - 피킹(Picking) 로직

목표

마우스로 클릭한 위치가 어떤 3D 오브젝트를 선택하는지 알아내는 기능이다. 이 때 Ray를 생성하고 Collider와 충돌 검사를 한다.

작동 방식

  1. 스크린 좌표 → ViewSpace 좌표로 변환
  2. ViewSpace 좌표 → WorldSpace로 변환
  3. Ray 생성 후 모든 오브젝트와 충돌 검사
  4. 가장 가까운 오브젝트 반환
Vec4 rayOrigin = { 0, 0, 0, 1 }; // 카메라 기준
Vec4 rayDir = { viewX, viewY, 1, 0 }; // 방향

Vec3 worldRayOrigin = XMVector3TransformCoord(rayOrigin, viewInv);
Vec3 worldRayDir = XMVector3TransformNormal(rayDir, viewInv);
worldRayDir.Normalize();

Ray ray(worldRayOrigin, worldRayDir);

🧪 CollisionDemo::Update - 클릭으로 오브젝트 제거

void CollisionDemo::Update()
{
	if (INPUT->GetButtonDown(KEY_TYPE::LBUTTON))
	{
		int32 x = INPUT->GetMousePos().x;
		int32 y = INPUT->GetMousePos().y;

		auto picked = CUR_SCENE->Pick(x, y);
		if (picked)
			CUR_SCENE->Remove(picked);
	}
}

클릭 → Ray → 충돌된 오브젝트 → 제거.


🧱 GameObject의 Collider 지원

GameObject에 Collider 관련 코드를 추가한다.

shared_ptr<BaseCollider> GameObject::GetCollider()
{
	auto comp = GetFixedComponent(ComponentType::Collider);
	return static_pointer_cast<BaseCollider>(comp);
}

⚠️ 왜 Collider를 사용해야 하나?

  • Mesh 자체로 충돌 계산하면 삼각형 수 만큼 계산이 발생 → 너무 무겁다.
  • Collider는 단순 도형 기반이므로 연산이 훨씬 빠르고 간단하다.

예: 10000개의 물체가 있을 때 각각 삼각형 기반으로 충돌 체크하면 엄청난 연산량!


profile
李家네_공부방

0개의 댓글