원 모양 물체의 2차원 비탄성 충돌에 대한 고민

2022. 5. 10. 15:29개발하다가

이슈

2차원 상 충돌을 간단하게 구현해 본다고 할 때, 원과 선분, 원과 원, 선분과 선분의 교점을 구하는 함수를 만들어 (여러 개면 그 평균, 즉 질량중심을) 작용점으로 사용하도록 했었습니다. 이후 해결해야 할 것이 하나 더 있으니 충격량 그 자체를 정하는 것입니다. 충격량 적용 그 자체는 간단한 편으로 볼 수 있습니다.

inline void impulse(const vec2& force, const vec2& globalPoint) {
	velocity += inverseMass * force;
	angularVel += inverseMoment * cross2(globalPoint - transform->getGlobalPosition(), force);
}

하지만 그 충격량을 구하려면 반발계수에 따른 충격을 구해야 하는데, 이 역시 그냥 검색해 갖고는 대체로 안 나오는 편입니다.

* 이 글은 고민하는 과정이 들어 있지, 정답 같은 걸 담고 있지 않습니다. 그래서 사실 오답을 담고 있을 수도 있습니다.

 

이것저것 보았는데 대부분이 이런 내용입니다.

"반발 계수가 1일 때는 운동 에너지가 보존될 때. 그래서 0.5mv²의 합이 같다는 걸 가지고 x와 y에 대한 각각의 운동량 성분 보존을 구하여 방정식을 풉니다. 그 외의 경우는 막 구해지기 어렵습니다. 근데 이것 보세요. 질량이 같은 물체끼리 비스듬히 탄성 충돌을 할 때 각도의 합은 90도네요?" 고3때가 떠오르네요. 물리2에서 딱 이 정도 가르쳤습니다만 역시, 쓸데없는 내용으로 시선을 돌렸다는 생각을 떨칠 수 없습니다.

그래서 반발 계수가 1이고 각운동량을 무시한다면 이런 코드를 쓸 수 있습니다.

c1.velocity = v1 - (c1.center - c2.center) * dot(v1 - v2, c1.center - c2.center) / length2(c1.center - c2.center) * 2 * m2 / (m1 + m2);
c2.velocity = v2 - (c2.center - c1.center) * dot(v2 - v1, c2.center - c1.center) / length2(c2.center - c1.center) * 2 * m1 / (m1 + m2);

뭔가 설명하는 곳도 있긴 합니다. 여기와 여기를 참고하세요.

회전이 있다면 그렇게 간단한 말로는 해결이 절대 안 됩니다. 회전 운동 에너지인 0.5Iω²까지 유지되어야 하고, 각운동량도 보존되어야 하고, 마찰까지 있다면 접촉 법선도 틀어야겠죠. 그래서 편의상 각(angular) 성분은 빼고 말하겠습니다.

문제 1. 반발 계수 R일 때의 선충격량

선운동량만 고려한 충돌에서는 다음이 주어질 수 있습니다.

각 원의 질량 m1, m2, 기존 속도 v1, v2, 충돌 시점의 중심 좌표들 p1, p2

이때 충격량의 방향이 아주 중요합니다. 접촉 법선과 각이 달라 충격량의 방향은 단순히 중심 좌표 벡터의 차라고 할 수는 없습니다. 고등학교 물리에서 현실적으로 의미가 없는 1차원 상 충돌을 가르치는 데는 다 그런 이유가 있습니다. 그래서 우리는 충돌을 1차원 상에 올릴 겁니다. (충돌이 있기 때문에 올릴 수 있는 겁니다.)

여기서 식이 복잡해질 예정이니 상대 속도와 상대 위치를 이용하여 m1, m2 / 0, v3 / 0, p₃라고 표현하겠습니다. 현재로부터 지난 시간 t에 대하여, 둘의 중심 사이의 '거리'는 다음과 같이 표현됩니다.

아쉽게도 이 식은 더 벡터를 유지한다면 줄일 수가 없고 단순 벡터 식이 아닌 크기 표현식이기 때문에 그대로는 미분이 불가능합니다. 어쩔 수 없이 성분 전개하도록 하겠습니다.

t=0에서의 미분 계수는 다음과 같습니다. 이는 충돌 시점의 접근 속력, 즉 1차원 공간에서의 정면 충돌 시의 상대 속도를 의미합니다.

말하자면 접촉점과 중심을 잇는 벡터를 충격량의 방향으로 하기 위해 충격과 관계 없을 속도 성분을 없앤 겁니다. 이는 다음 논리에 기반합니다. 오류가 있으면 지적해 주셨으면 좋겠습니다.

- 각 충돌 물체와 상호 접근 속도가 모두 같은데 충격량이 다를 리가 없다

- 선형 공간에서 마주보고 충돌한 물체의 충격량 방향은 진행 방향임이 자명하다

아무튼 선형 상 방향이 p임은 확실하니 충격량의 방향은 또 나온 정사영. 이 값을 w라고 하고, 충돌 시 선속력으로 정하면 그 방향은 -p₃입니다. 그래서 속도는 -p₃ × w/||p₃||인데, 이를 Y=bp₃라고 합시다. 이를 이용하여 식을 세웁니다.

현재 원점에 있는 것으로 보고 있는 원이 받는 충격량을 I라고 할 때, 충격 후 각 원의 속도는 다음과 같습니다. I는 ap₃ (a는 실수. 접근 속도는 충돌 후 후퇴 속도가 되므로, 즉 p₃의 반대 방향으로 힘을 받아야 하므로 a의 유의미한 근은 음의 실수뿐입니다.)로 나타낼 수 있음을 기억해 둡시다.

 I/m₁,  Y - I/m₂

반발 계수가 R일 경우 이것의 차의 크기는 원래 차의 크기의 R배여야 합니다. 즉, ||I/m₁ - Y + I/m₂|| = ||Rp||입니다. 식을 간단히 하기 위해 X=1/m₁+1/m₂라는 기호를 하나 더 만듭시다.

||I/m₁ - Y + I/m₂||=||Xap₃-bp||=||Rp||

모르는 수는 a뿐입니다. 양 변이 모두 실수이므로 제곱하면 이렇게 됩니다. X²a²(pp₃)-2Xa(pv₃)+(vv₃)=R²(vv₃)

이를 단순히 풀어 내면, a는 아래와 같습니다.

 

b = -w/||p₃|| = (vp₃) / (pp₃)

이것은 음수입니다. 충돌이 있다는 것 자체가 상대 속도 v₃는 정지한 원(기준으로 본 원)을 향하며 상대 위치 p₃는 그 반대 비슷한 방향을 가리키는 상황 밖에 없기 때문입니다.

(실수로 계산을 잘못 했습니다. 부호가 반대여야 합니다. 나중에 사진을 수정하겠습니다.)

보면 알겠지만, 차원수를 내리거나 올려도 되고, 위의 사후 속도를 구하는 코드와 다른 점은 여기 R+1인 게 저기서는 2인 것뿐입니다. 위의 유도 과정에서 

위의 impulse 함수는 충격력이 아닌 충격량을 받습니다. Δt가 곱해지지 않고 원하는 만큼 속도를 변화(더 정확히 말하면 Δt=1을 프레임 내에 했다고 가정하는 것)시키는 것입니다.

한 가지만 예를 들어 확인해 봅시다.

각 원의 질량 1, 2, 기존 속도 (1,2), (2,3), 충돌 시점의 중심 좌표들 (0,0), (-1,0), R=1

v=(1,1), p₃=(-1,0)이므로 I=(-1)(1+1)(1×2)/(1+2) × (-1,0)=(4/3,0)

따라서 충돌 후 원의 속도는 각각 (7/3, 2), (4/3, 3)입니다. R=1인데 운동에너지 총량도 보존되네요.

그런데 R에 대하여 일반화할 경우, ((2R+5)/3, 2)와 ((5-R)/3, 3)으로 상대 속도 비율은 p₃ 방향에 해당하는 x축 성분에서만 R로 유지됨을 확인할 수 있습니다.

첫 번째 원이 받는 충격량이 (2/3,0)이므로 식대로면 충돌 후 원의 속도는 각각 (5/3, 2), (5/3, 3)입니다. 상대 속도의 크기가 같은 R=1일 때와 달리 경우와는 충격력 방향으로 상정한 x축과 수직한 성분인 y축 속도는 통일되지 않았는데요, 이는 우리가 아는 바와는 다릅니다. 2차원에서는 대충 어떤 일이 일어나고 있을까요?

 
 

위의 그림은 위쪽의 공식을 사용하여 계산한 반발 계수가 0인 원형 강체의 비스듬한 충돌에서, 중력을 위쪽에 있던 물체에만 적용하고 있습니다. 왼쪽은 질량비가 1:10만, 오른쪽은 1:2입니다. 양 경우 모두에서 타고 내려가는 모습을 확인할 수 있습니다. (당연히 충돌 판정은 여러 번 이루어짐) 완전 비탄성 충돌의 대표격인, 젖은 휴지를 던진 모양새랑은 거리가 있습니다.

진짜 후퇴 속도가 0이라면 굳이 시뮬레이션하지 않더라도 왼쪽의 경우에는 착 달라붙어 멈추었을 거고, 오른쪽은 붙어서 둘 다 정확히 아래 방향을 향해 움직일 거라는 걸 예측할 수 있습니다.

이는 제가 원하는 바가 아닙니다. 지금 비스듬한 충돌의 각도가 작아서 붙어도 별로 안 이상해 보이지만, 이게 더 왼쪽으로 치우쳤다면 옆으로 지나가다가 마치 갈고리라도 건 듯이 걸렸을 겁니다. 즉, 방금 얻은 수직 성분 문제는 일반 각도에서의 수직 항력 역할을 합니다. (R값이 늘어나도 마찬가지입니다.) 만약 동일 공식을 고정된 벽에 적용했다면, 비스듬히 날아오던 공은 벽에 붙어서 벽을 따라 움직일 겁니다.

결국 현실 물리 법칙과는 약간 거리를 두고, 우리의 R는 다른 의미를 가진다고 타협하여 넘어간다고 칩시다. 문제는 이겁니다. 시뮬레이션에서 진짜로 젖은 휴지를 던지고 싶다면 어떻게 할까요?

위의 그림은 위쪽의 공식을 사용하여 계산한 반발 계수가 0인 원형 강체의 비스듬한 충돌에서, 중력을 적용하지 않고 있습니다. 마찬가지로 질량비는 왼쪽이 1:10만, 오른쪽이 1:2입니다. 상대 속도가 R=1일 때보다는 눈에 띄게 작긴 하지만, 붙어 움직이고 있지는 않습니다. 그러니까 마찰이고 뭐고 포함해도, 일반적 방법으로 젖은 휴지를 구현할 방법은 없어집니다. 따로 구현해야 할 듯 싶습니다.

 

그러면 이제 2가지 의문이 남았군요.

- 원 말고 다른 모양의 충돌은 어떻게 일반화할까요?

- 관성 모멘트를 질량중심처럼 평균값 하나로 뭉개서 생각할 때, 각운동량은 어떻게 포함할까요?

 

한데 이에 관한 내용은 적어 두고 보니 위의 내용보다도 궤변에 가까워서 일단은 접어 두겠습니다.

더보기

사실 원 이외의 충돌도 식은 같습니다. 방금 질량 중심이 선형 공간 상에서 접근하는 속도 성분을 충격량 방향으로 상정했었죠. 대부분의 프로그램 상에서도 학창 시절 문제처럼 질량중심의 속도를 따집니다. 다만 현실은 선형 공간이 아니라서, 다음과 같은 형태의 충돌에서 가해지는 힘의 방향을 질량 중심 상대 위치 벡터와 같게 잡을 수 있다는 상상이 안 갑니다. 각운동량을 제외하면 아래 그림과 같은 충돌이 당구공과 비슷하게 이루어질 것 같나요?

물리적으로 유한 질량과 무한 관성 모멘트를 가질 수 있을 리가 없으니 외력이 있는 경우를 생각해 봅시다. 외력이 기가 막히게 각운동량만 0으로 고정시키는 겁니다. 어떤가요? 마찰 0이 가능하다는 가정 하에서 상상 불가능한 경우는 아닙니다. 외력 그림을 보시죠.

파란 선은 움직이지 않고 마찰이 없는 벽, 빨간 다각형은 역시 마찰이 없고 원래 사각형들에 붙어 다니는 강체 신발입니다. 당구공과 같게 충돌할 수밖에 없겠네요. 이것이 충돌 전후 아주 약간의 시간 동안 잠깐 주어졌다 사라집니다. 말도 안 되지만 당구공과 비슷하긴 하겠네요. 왜 말도 안 되는 일을 할까요? 게임 상에서는 선운동량만 고려하여 충돌시키는 것을 허용할 때가 많기 때문입니다.

별 이론이 들어가지는 않았지만, 물리는 이렇게 상상력이 중요합니다. 사람들이 물리를 어려워하는 이유는 (현실에 있는 마찰, 저항을 배제하거나, 적분을 중심 하나로 퉁치는 등의 이유로) 상상이 안 가기 때문입니다. 아니라고요? 그럼 말고.

대충 결론짓자면 선분과 선분, 원과 원의 충돌에서는 교점을 작용점으로 하고 충격량은 위의 식을 이용하면 그리 나쁘지 않은 근사가 될 것 같다는 겁니다.

 

* m₁>>m₂인 경우 위 식은 아래와 같이 생각할 수 있습니다.

이런 식으로 하는 것도 아마 물리2 때 배우신 분들이 많을 겁니다. 그런데 여기서 생각할 때 문제가 발생합니다.

이 상황에서 공이 충격받는 방향은 의심할 여지 없이 화면 기준 위쪽입니다. 하지만 프로그램 내에서 무한대 질량 강체의 질량 중심을 두고 그 값을 넣어 시뮬레이션한다면, 공은 그 질량 중심과 마주보는 방향의 충격을 받을 걸 어렵지 않게 예상할 수 있습니다. 이런 문제가 발생한 이유는 m₁>>m₂가 그만큼 특수한 경우이기 때문입니다. 질량이 정말로 무한대라면 질량 중심을 고려할 이유가 없습니다. 그럼 상대 물체 질량이 무한대일 때 접촉점이 질량중심인 것처럼 계산하면 끝일까요?

위 상황에서 아래 2개 물체의 충돌을 먼저 계산해 봅시다. 정지 상태이므로 상대 속도는 0, 따라서 충격량은 0입니다. 그 다음 위 2개 물체의 충돌을 계산합니다. 원은 유한 질량 물체에 부딪쳤으니 충격의 방향은 막대와 질량중심을 이은 것이 되겠네요. 이후 프레임에 아래 2개 물체에 대한 충돌이 재차 발생하긴 하겠습니다만 튀어나간 원과 다시 충돌하지 않을 수 있으니, 이미 잘못된 거나 마찬가지입니다. 즉, 근본적으로 원과 선분 사이에 p3를 그런 식으로 선택하는 것은 부적절한 모양입니다. 선분을 반지름이 무한대인 원의 호라고 생각하면, 그 호의 중심은 분명 아주 멀리 떨어져 있어 충격량 방향은 단순히 법선을 그리면 된다는 논리가 되겠습니다만 그걸로 괜찮을지는 모르겠습니다. 나란한 선분의 충돌은 동일한 논리를 적용하면 논란의 여지가 없이 선형 공간 상 상대 속도의 방향일 거고요. 선분 끝점과 선은 선형 공간상 충돌에서 확인 바와 같을 것 같긴 한데, 저도 많이 헷갈립니다.

선분 끝점과 다른 선분의 경우 이게 맞는지 직관을 얻으려면, 볼펜을 침대 등 푹신한 곳 위에 여러 방향(-, /, |)으로 떨어뜨려 충돌 직후 어느 방향으로 나아가는지 확인해 보세요. 즉, 물체 질량이 무한대일 때 접촉점이 질량중심인 것처럼 계산하는 것과 원과 선분 사이의 충격량 방향을 역시 접촉점을 기준으로 계산하는 것 둘 다 필요해 보입니다.

문제 2. 각운동량을 포함하기

하지만 말 되는 일을 무시할 수는 없습니다. 마찰이 들어가서 원끼리의 충돌에서 토크가 발생한다 해도, 상대적으로 부정확한 시뮬레이션이 크게 티가 나지는 않을 것 같기는 합니다. 하지만 선분이 들어가면 얘기가 달라질 겁니다. 토크가 없으면 없었지 부정확한 시뮬레이션이 발생하면 없느니만 못한 경우가 생길 수 있지 않을까요? 작은 물체 2개가 부딪쳐 날아가면서 약간 회전하는 것은 그렇다 쳐도, 회전하는 물체가 부딪쳐 각각의 선운동량이 발생할 때는 조금 까다로울 수 있습니다.

그나마 다행인 건 어디를 회전의 중심으로 잡아도 결국 맞는 방향으로 돌아갈 수 있다는 점입니다.

직관적으로 보면 실제 회전의 중심은 C고 토크는 G가 만들지만, 회전의 중심을 M(질량중심)이라고 하고 N에 의해 토크가, G와 N에 의해 병진(translation)이 발생한다고 할 수도 있습니다.

이걸 스스로 해결할 수 있을지 모르겠네요(작성 중)