게임에서 충돌은 크게 두 가지로 나뉜다.
두 경우 모두 충돌(Collision)이라는 개념을 기반으로 한다.
먼저 테스트를 위한 씬을 만들기 위해 CollisionDemo 클래스를 생성한다. 기존 ViewportDemo를 복사해서 Client/Game/Week3 필터에 CollisionDemo로 만든다.
이제 여기서 충돌 관련 기능을 실험할 예정이다.
모든 충돌 컴포넌트들의 공통 기반 클래스다. 모든 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: 어떤 타입인지 구분할 수 있도록 해주는 정보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));
}
마우스로 클릭한 위치가 어떤 3D 오브젝트를 선택하는지 알아내는 기능이다. 이 때 Ray를 생성하고 Collider와 충돌 검사를 한다.
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);
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 관련 코드를 추가한다.
shared_ptr<BaseCollider> GameObject::GetCollider()
{
auto comp = GetFixedComponent(ComponentType::Collider);
return static_pointer_cast<BaseCollider>(comp);
}
예: 10000개의 물체가 있을 때 각각 삼각형 기반으로 충돌 체크하면 엄청난 연산량!