입체충돌처리

16

Click here to load reader

Upload: quxn6

Post on 08-Jul-2015

751 views

Category:

Technology


1 download

DESCRIPTION

게임 프로그래밍의 정석 chapter 18, 22 내용 스터디

TRANSCRIPT

Page 1: 입체충돌처리

3D Collision

Page 2: 입체충돌처리

게임 프로그래밍의 정석

chapter 18직육면체 충돌 처리구 충돌 처리선분과 삼각형 충돌 처리

chapter 22느리지 않은 충돌 검출

내용

Page 3: 입체충돌처리

직육면체와 직육면체의 충돌 검출

직육면체를 Cuboid 라는 클래스로 표현하면

class Cuboid {int mX, mY, mZ; // 직육면체의 중심int mHalfSizeX, mHalfSizeY, mHalfSizeZ; // 각 축의 크기 / 2bool isIntersect ( const Cuboid& b)

}

다른 직육면체와의 충돌검출 함수 isIntersect()는 좌표축별로 겹쳐있는지에 대한 여부를 판정한다.한 축에서 직육면체의 오른쪽이 다른 직육면체의 왼쪽과 닿았는지, 혹은 그 반대인지에 대한 여부를축을 바꿔가며 반복해서 판정.

직육면체충돌처리

< 2차원이라 생각하면 x축으로 겹쳐있는지를 판단 한 후 y축도 겹쳐있는지를 판단해보는 것 >

Page 4: 입체충돌처리

충돌에 대한 처리

X축, Y축, Z축을 각각 나눠서 생각해야 한다. (충돌했을 때 그냥 물체를 멈춰버리게 만들 수는없으므로) 따라서 충돌이 없는 경우, x, y, z, xy, yz, xz 로 일곱 번에 걸쳐서 충돌 체크를 해야한다.(xyz는 안하나)

* 처리 순서1. object들의 이동 여부를 판정2. 다음 frame에서의 위치를 계산3. 충돌하는 방향으로의 이동은 줄이고, 충돌이 없는 방향으로의 이동만 반영

움직임의 최소 단위에 대한 정의가 필요함.

간단 하지만 경사를 표현하기가 어렵다.(비탈을 만든다고 하면 계단모양으로 세밀하게 만들어야 한다고 함)

직육면체충돌처리

x

z

x

z

x

z

< y축 평면 상에서 움직임을 –y축 시점으로 볼 때. 빨간 화살표 만큼이 움직임의 최소 단위라고 생각하자 >

Page 5: 입체충돌처리

구와 구의 교차 판정

두 구의 중심끼리의 거리가 거리의 반경을 합한 것보다 작으면 충돌.

피타고라스 정리로 간단하게 알 수 있음!!

구충돌처리

< 머 이런거 >

Page 6: 입체충돌처리

구와 구의 충돌 응답

구와 구가 만날 때 생기는 접선 방향으로 이동을 비껴가게 한다. 아래 그림에서는 v방향으로 가던 물체가 벽을 만났을 경우, 수평방향인 a로 이동하는 것을 보여준다.

아래 그림에서 a벡터는 v벡터에서 d벡터를 빼면 구할 수 있다. d벡터는 v * cos ∅ 한 값으로

구할 수 있고 cos ∅의 값은𝑣∙𝑏

𝑣 |𝑏|으로 구할 수 있다.

두 면이 교차하는 곳에서 어느 면을 먼저 계산하느냐에 따라 떨리는 현상이 발생할 수도 있다고함.

구충돌처리

< 이 작업을 매 프레임 하는 듯 >

𝒃 = 𝒄𝟎− 𝒄𝟏

𝒂 = 𝒗 −𝒃

𝒃∙ |𝒗| ∙ cos ∅

Page 7: 입체충돌처리

지면에 세우기

지형은 원래 폴리곤들의 집합이므로 지형과의 충돌처리에서 지형을 삼각형으로 하는 것은 좋은선택임.지형과 충돌처리하는 object의 경우 직육면체, 원기둥 등 보다 선분을 사용하는 것이 가장 적은부하가 걸림.

캐릭터 발 주변에 있는 한 점을 잡고 그 점의 현재 프레임의 위치와 다음 프레임의 위치를 계산해서삼각형과 교차하는지를 판단하면 된다.

선분과삼각형의충돌처리

Page 8: 입체충돌처리

삼각형과 선분 교차 판정 개요

직선 표시법𝒑 = 𝒂 + 𝑡𝒃 , 점 a와 이동량 b, 파라미터 t로 다음 점 p를 나타내는 것. t에 따라 p가 직선상을이동t = [0,1]로 제한하면 a에서 a+b로 가는 선분이 된다.

삼각형 표시법𝒒 = 𝒄 + 𝑢𝒅 + 𝑣𝒆 , 마찬가지로 점 c와 이동량 d, e 파라미터 u,v로 표현할 수 있다.q는 세 점 c, c+d, c+e로 생기는 평면을 나타낸다.

이 때, u,v를 [0, 1] 범위로 제한하면 평행사변형이 되고 u+v<1인 조건을 추가하면 삼각형이된다.

충돌 검출위 두식을 동시에 만족하는 점이 있다면 충돌임!𝒂 + 𝑡𝒃 = 𝒄 + 𝑢𝒅 + 𝑣𝒆

축이 세개이므로 x,y,z에 대해서 각각 식이 나오고 따라서 t,u,v를 구할 수 있음

얘네를 크래머의 공식(나누는 쪽이 0이 안나오도록 )을 이용해서 푸는 방법이 있고다음 장에서 나오는 방법으로 풀 수도 있음

선분과삼각형의충돌처리

Page 9: 입체충돌처리

충돌 검출 방법 (계속)

1. 세 점이 이루는 평면 상에 점 p가 있다고 가정하고 세 점 중 하나인 점c와 점p가 이루는 벡터가 평면의 normal 벡터와 수직임을 이용해서 점 p를 이루는 직선의 방정식 미지수인 t를 구하고 이 t가 [0,1]범위인지 판단하므로써 평면과 만나는 지를 판단할 수 있다.

2. 만난다면 그 점과 d,e와의 내적을 이용하여 삼각형의 방정식에서 u,v 로 세 점이 이루는 삼각형 내에 p가 존재하는지를 판단하므로서 충돌을 검출한다.

선분과삼각형의충돌처리

< 빨간 선분이 캐릭터(한 점)의 이동을 나타낸다고 할 때, 실선에서 끝난다고 하면, t가 [0,1] 사이가 아니라는 것이고, 그렇다는 것은 다음프레임이던 그 다음이던 언젠가

는 만나겠지만 지금은 아니라는 것이다.>

𝒑 = 𝒄 + 𝑢𝒅 + 𝑣𝒆 를𝒑 − 𝒄 = 𝑢𝒅 + 𝑣𝒆 로 치환하고 (이러면 p-c가 한 벡터가 될 것이고) 이를 d, e 벡터와각각 내적하므로서 u,v를 구할 수 있다. u+v<1이라면 삼각형 안에 있는 것으로 판단할 수 있다.

Page 10: 입체충돌처리

이음매 문제

u, v가 0 또는 1이라면 두 삼각형의 접선에서 뚫고 나갈 수 있음. 따라서 그 부분에 대한 처리를 해서 두번 충돌하더라도 관통되지 않게 만들어야함

비탈에서도 알아서 잘 움직인다는데 이 점은 이해가 잘 안됨.

선분과삼각형의충돌처리

Page 11: 입체충돌처리

전체 검사를 하면 속도가 느리다

화면에 1600개의 원을 그리고 전체에 대한 충돌 검사를 하는 경우

충돌 판정은 128만 회 해야하지만 실제 충돌은 4000번 미만으로 일어난다.

실제 충돌한 것만 판정할 수 있다고 하면 판정에 시간은 320분의 1로 줄어들 것.

이상적으로 줄이지는 못하더라도 충돌할 확률이 높은 것들만 체크하면 좋을 것 같다.

느리지않은충돌검출

0

1

2

3

4

< 다섯 개의 원이 있다고 할 때 전체에 대해 충돌체크를 한다면 4+3+2+1=10회다. 𝟓!

𝟑!𝟐!과도 같다. >

Page 12: 입체충돌처리

한 축을 기준으로 정렬해서 판단

한 축 기준으로 원들을 모두 이동시킬 경우 0,1 한 그룹 3,2,4 한 그룹 두 그룹이 생긴다. 1+3으로 4회의 충돌체크만으로 충분하다.

구역을 나눠서 충돌 체크

가까운 곳에 있는 것들끼리 묶어 왼쪽과 오른쪽 그룹 둘로 나누고 이를 또 상하 두 그룹으로 나누는 것. 이렇게 되면 0과 1 한번 2는 없고 3,4 한번 해서 2번의 충돌체크만으로 가능하다.하지만 어떻게 선을 그을지 또 선과 원이 겹칠 경우 어떻게 할지에 대한 고민이 따른다.

느리지않은충돌검출

< 구역을 나누는 방법 >

0

1

2

3

4

0

1

2

3

4

< 정렬하는 방법 >

0 1 3 2 4

Page 13: 입체충돌처리

한 축을 기준으로 정렬해서 판단

각각의 원의 크기가 다르다면 원의 중심만으로는 체크할 수 없다.(엄청 큰 원이 있다면..)따라서 원의 좌측 끝 우측 끝 두 포인트를 체크한다.

아래 그림은 원을 좌우 끝과 그 반경으로만 표현한 것이다.한 원의 충돌을 판정할 때 다음과 같은 로직을 적용할 수 있다.

if (왼쪽이다.) {판정한다기억해둔다.

} else if (오른쪽이다.) {if (만난 적이 있다.) { 기억해둔 것을 잊어버린다.}else if (처음 만났다.) { 판정한다.}

}

느리지않은충돌검출

< 원 2의 충돌체크인 경우 먼저 [1은 처음이므로 판정 후 리스트에 저장하고 다음 1]을 만나면 리스트에서 제거한다. 0]은 처음 만났으므로 판정하되 좌측이 아니므로 저장은 하지 않는다. >

[0 0]

[1 1]

[2 2]

[3 3]

Page 14: 입체충돌처리

한 축을 기준으로 정렬해서 판단

세로 축으로 정렬해 있을 경우 위 방법은 O(N2)이 되는데다 한 원을 두 번씩 나눠 계산하게 되므로 계산양이 그냥 전체 체크하는 것보다 더 크게 된다. 따라서 이런 경우에는 다른 축을 기준으로 하는 것도 고려해보아야 하는데 이를 판단하는 기준은 원들의 분산 정도가 될 수 있다.

즉 축 별로 분산을 계산하여 큰 쪽을 고르는 것으로, 분산을 구하는 데는 O(N)정도의 복잡도로가능하므로 평균적으로 좋은 성능을 낼 수 있을 것이다.

느리지않은충돌검출

Page 15: 입체충돌처리

구역을 나눠서 충돌 체크 (균등 분할)

xyz 축에 대해서 균일하게 공간을 나눈 뒤, 각 물체가 어느 상자에 들어가는 지 조사하고 상자별로 전체검사를 하는 방식이다. 문제는 물체가 여러 상자에 걸치는 경우다. (세 물체가 동시에두 상자에 걸친다고 생각해도 3번의 충돌체크로 끝날 것을 상자 별로 6번 충돌체크 해야 한다.)

상자 내에 물체를 저장할 때 사용할 자료구조에 따라 속도차이가 많이 나는데 std::list를 사용할 경우 매번 new하는 과정이 있기 때문에 속도가 굉장히 늦다. 배열로 만들어서 넣어두면 정렬해서 판단하는 방법보다 빨라질 수 있으나 메모리 용량을 계속 고려해주어야 한다는 점이 문제다.

또한 물체들이 한 곳에 모여있는 경우, 즉 물체가 편중되어 있을 경우 쓸데 없는 상자가 대량으로 생기고 물체가 모여있는 상자에서는 전체 검사를 해야 하는 경우가 생기기 때문에 최악의 경우 O(N2)이 된다.

이런 특성 때문에 고정된 물체(지형 등)와의 판정에서 주로 쓴다고 한다.

느리지않은충돌검출

< 물체가 여러 상자에 걸치는 경우> < 물체들이 한 상자에 집중된 경우>

0 1 3

01

234

Page 16: 입체충돌처리

구역을 나눠서 충돌 체크 (고도의 공간 분할)

K-d tree : 재귀적으로 동일한 영역 두 개로 나누면서 그 분할선이 xyz축 중 하나와 평행하게만듦

1. 전체 물체가 들어가는 큰 상자를 만들고 분할 시작2. 분할 방식을 결정하고 xy중 어느 쪽으로 분할할지 결정3. 자식 노드를 두 개 만들어 물체를 나눈다.4. 자식 노드에 대해 2부터 반복

트리를 구축하는데 시간이 걸리므로 분할 횟수를 어느 정도로 한정하면 판정횟수는 늘지만 분할에 걸리는 시간은 경감 된다.

느리지않은충돌검출