그래픽스(DirectX)

[DirectX11] Ray와 물체의 충돌 판정 (Intersection)

gamzachips 2023. 5. 1. 12:28

Ray와 물체의 Intersection

 

Ray- Mesh 

ray를 이용해서 picking을 하기 위해서는 일단 ray가 mesh를 지나는지를 알아야 할 것이다. 

 

mesh를 이루는 각 삼각형들에 대해서 충돌 판정을 하고, 

삼각형과 충돌이 확인되면 그 삼각형이 속한 mesh가 선택될 수 있다. 

 

그러나 매 프레임마다 mesh를 이루는 수많은 삼각형에 대해서 충돌 체크를 한다면 부담이 될 것이다.

연산량을 줄이기 위해 bounding box와 같은 단순한 collider와 먼저 충돌 체크를 하고, 충돌했을 때 삼각형들을 체크한다. 

bounding box와 충돌하지 않았으면 삼각형과도 충돌하지 않은 것이므로 연산을 할 필요가 없다. 

picking, 충돌 감지 목적의 단순한 mesh가 따로 저장되어있는 경우도 있다.

 

uint32 pickedTriangle = -1;
float minDistance = 0.0f;

if(boundingBox.Intersects(rayOrigin, rayDir, OUT distance)
{
	uint32 dMin = UINT32_MAX;
    
    const auto& indices = _mesh->GetGeometry()->GetIndices();
    
    for(int32 i = 0; i < indices.size(); i++)
    {
    	uint32 index[3];
        index[0] = indices[i*3+0];
        index[1] = indices[i*3+1];
        index[2] = indices[i*3+2];
        
        Vector3 vertex[3];
        for(int32 j = 0; j < 3; v++)
        	vertex[j] = vertices[index[j]].position;
        
        float& d = 0.0f;
        if(ray.Intersects(vertex[0], vertex[1], vertex[2], OUT d))
        {
        	if(d < dMin)
            {
            	dMiin = d;
                pickedTriangle = i;
            }
        }
    }
    distance = dMin;
}

 

 

 

 

Ray - Bounding Box  

위에서 설명한 것처럼 mesh의 삼각형마다 충돌 판정을 하는 것은 부담이 되므로 bounding box와 같이 단순한 도형의 collider를 두는 것을 고려할 수 있다. 

 

Box collider에는 크게 AABB와 OBB의 두 종류가 있다. 

 

 

AABB(Axis-Aligned Bounding Box)

AABB는 축이 좌표계의 축과 일치하는 상자이다. 

DirectXMath 에서 BoundingBox 로 제공되며, Intersects 함수를 이용하여 충돌 판정을 할 수 있다. 

BoundingBox aabb;
aabb.Center = Vec3(0.0f);
aabb.Extents = Vec3(0.5f);
aabb.Intersects(ray.position, ray.direction, OUT distance);

 

 

OBB(Oriented Bounding Box)

OBB는 축이 좌표계의 축과 일치하지 않는 상자이다. 

물체가 축에 나란하게 정렬되어 있지 않거나 회전하는 경우에 사용할 수 있다. 

DirectXMath 에서 BoundingOrientedBox 로 제공되며 Orientation 으로 회전값을 설정할 수 있다. 

마찬가지로 Intersects 함수를 사용하여 충돌 판정을 할 수 있다. 

 

BoundingOrientedBox obb;
obb.Center = Vec3(0.0f);
obb.Extents = Vec3(0.5f);
obb.Orientation = Quaternion::CreateFromYawPitchRoll(45, 0, 0);
obb.Intersects(ray.position, ray.direction, OUT distance);

 

 

 

Ray - Sphere

구체는 BoundingSphere로 제공되며, Cender와 Radius 값을 가진다. 마찬가지로 Intersects 함수를 이용한다. 

 

BoundingSphere sphere;
sphere.Center = Vec3(0.0f);
sphere.Radius = Vec3(0.5f);
sphere.Intersects(ray.position, ray.direction, OUT distance);

 

 

 

 

참고 자료

Introduction to 3D Game Programming with DirectX11 - Frank D. Luna

Rookiss님 인프런 멘토링 강의