Post Lists

2018년 10월 3일 수요일

15 Resting Contacts and Friction

15 Resting Contacts And Friction
지금까지, 나는 contacts와 collisions이라는 용어를 상호교환 해가면서 써왔다. 그 충돌 탐지기는 닿고있는 (즉, contact에 있는) 또는 관통해 있는 오브젝트들의 쌍을 찾는다. 그 collision resolution algorithm은 물리적으로 믿을만한 방식으로 이러한 오브젝트들을 조작한다.

이 시점부터, 나는 두 용어 사이의 구분을 할 것이다: contact는 오브젝트들이 닿고있거나 또는 관통해 있는 어떤 location이다; collision은 contact의 한 유형이고, 그 오브젝트들이 함께 속도를 가지고 움직이는 것이다 (이것은 또한 어떤 물리 시스템에서 "impact"라고 불려진다). 이 챕터는 conatct의 또 다른 유형을 소개한다: resting contact. 이것은 관련된 오브젝트들이 떨여저서 움직이지도 않고, 함께 움직이지도 않는 한 contact이다.

완정성을 위해서, contact의 세 번째 유형이 있다. separating contact인데, 거기에서 관련된 오브젝트들은 이미 떨어져서 움직이고 있다. separating contact에서 어떠한 종류의 velocity resolution을 수행할 필요가 없다, 그래서 그것은 종종 무시된다.

우리가 이 지점까지 보아온 충돌들은 상대적으로 다루기에 쉽다: 그 두 오브젝트들은 간단히 충돌하고, 그러고나서 다시 각자 갈 길을 간다. contact의 지점에서, 우리는 충돌에서 contact가 collision에서 separating contact로 바꾸기 위해 발생시키는 impulse를계산한다 (만약 restitution의 계수가 0보다 더 크다면) 또는 resting contact로 바꾸는 (만약 그것이 정확히 0이라면)

두 오브젝트들이 더 오랜 시간 동안 contact에 있을 때(즉, 단일 physics update보다 더 길게), 그것들은 resting contact를 가진다고 말해진다. 이 경우에, 그것들은 분리되어 유지될 필요가 있다. 각 오브젝트가 정상적으로 행동하는 것을 보장하면서.

15.1 Resting Forces
한 오브젝트가 서로에게 resting할 때, 뉴턴의 운동의 세 번째이자 마지막 법칙이 들어오게 된다. Newton 3은 다음과 같이 명시한다: "모든 action에 대해, 동등하고 반대의 반작용이 있다." 우리는 이미 두 오브젝트들을 포함하는 충돌에 대해 chapter 14에서 이 법칙을 사용했다. 우리가 한 오브젝트에서 impulse를 계산할 때, 우리는 두 번째 오브젝트에 반대 방향으로 같은 impulse를 적용했다. 오브젝트들과 움직일 수 없는 환경사이의 충돌들은 환경의 어떤 움직임이 너무 작아서, 그것이 안전하게 무시될 수 있다는 가정을 사용했었다. 현실에서, 한 오브젝트가 땅 위에서 튕길 때, 그 전체 땅 또한 튕긴다: 같은 충격이 지구에게 적용되는 중이다. 물론, 그 지구는 너무 무거워서, 만약 우리가 지구가 격을 움직임의 양을 처리하려한다면, 그것은 사라질만큼 작아서, 그래서 우리는 그것을 무시한다.

우리가 resting contacts에 대해 이야기 할 때, 유사한 프로세스가 발생한다. 만약 한 오브젝트가 땅 위에서 resting하고 있을 때, 그러면 중력의 force가 그것을 땅으로 잡아당기려고 한다. 우리는 이 force를 weight로서 느낀다: 중력이 한 무거운 오브젝트에게 적용시키는 force는 크다. 명백하지 않은 것은, 그 땅 위의 오브젝트를 유지시키는 equal and opposite force이다. 이것은 "reaction force"라고 불려지고, Newton 3은 우리에게, 그것이 정확히 같은 weight라고 말해준다. 만약 이 reaction force 있지 않다면, 그러면 그 오브젝트는 땅 아래로 가속할 것이다. 그림 15.1은 이 reaction force를 보여준다.

두 오브젝트들이 resting contact에 있고, 가속하지 않을 때, conatct 점에서의 균형있는 forces들이 있다. 한 오브젝트가 다른 것에 적용시키는 어떤 force는 equal reaction force가 다시 충족되어질 것이다. 만약 이 균형있는 forces들이 존재하지 않는다면, 그러면 두 오브젝트들은 가속하기 시작할 것이다. 우리는 뉴턴의 운동 제 2법칙을사용해서 그 가속을 처리할 수 있다, 각 오브젝트에서의 total force를 (reaction forces를 포함하여) 처리한 후에.

여기에서 circular process의 어떤 것이 있는데, 그것은 우리에게 몇 가지 이슈를 준다. 만약 reaction forces가 필요할만큼 크다면 (우리는 rigid bodies가 결코 바스러지거나, 응축되지 않을 거라고 가정한다), 그리고 가속도가 적용되는 total forces에 의존한다면, 우리는 어떻게 그 reaction forces가 실제로 어떤 시간에 얼마나 큰 지를 계산할 수 있는가? 그림 15.1에서의 간단한 상황에서, 이것은 문제가 아니지만, 고등학교와 학부 수학에서, 그 문제는 결코 언급되지 않는다. 많은 상호작용하는 오브젝트들이 있고, 특히 마찰이 있는 복잡한 시나리오에 대해, 그것은 우리가 보게 되듯이,중요하다.

땅과 한 오브젝트 사이의 reaction force는 real force라는 것에 유의해라. 그것은 한 impulse가 아니다: 속도에서의 변화가 없다. 지금까지 우리의 collision resolution system에서, 우리는 오직 impulses만을 적용했다. 이 reaction force는 같은 방식으로 나타내어질 수 없다. 우리는 그것을 좀 더 완전히 고려할 필요가 있다.

15.1.1 Force Calculations
resting contacts의 가장 명백한 접근법은 reaction forces를 계산하는 것이다. 그 방식으로, 우리는 우리의 rigid bodies의 움직임의 equations에 그 힘을 추가할 수 있다(section 10.3에서의 D'Alembert의 원리를 사용해서). 우리가 적용하는 regular foces를 따라, reaction forces를 작동시켜서, 그 body를 정확히 행동할 것이다.

많은 물리 시스템들은 정확히 이것을 한다. contacts들의 한 집합이 주어진다면, 그것들은 그 오브젝트들이 함께 사고하지 않도록 할 reaction forces의 한 집합을 생성하려고 한다. colliding contacts에 대해, 그것들은 두 방법들 주우 하나를 사용한다: 그것들은 우리가 chapter 14에서 보았던 같은 impulse method를 쓰거나; 또는 그것들은 한 impulse가 간단히 한 작은 moment of time에 대해 적용된 한 force라는 사실을 사용한다 - 만약 우리가 그 시간을 안다면 (즉, physics update의 duration), 그러면 그 impulse는 one-off force로 바뀔 수 있고, 다른 forces처럼 같은 방식으로 resolved될 수 있다.

만약 너가 정확히 매번 reaction forces를 계산할 수 있다면, 이 접근법은 괜찮다. 한 오브젝트가 땅 위에서 resting하는 것 같은 간단한 상황에 대해, 이것은 매우 쉽다. 그러나 그것은 급격히 복잡해진다. 그림 15.2는 쌓여진 오브젝트들을 보여준다. 이 stack에서 많은 internal reactionforces들이 있다. stack의 밑바닥에 있는 reaction forces는 stack의 꼭대기에 있는 reaction forces에 의존한다. 한 contact에 적용될 필요가 있는 forces들은 크게 시뮬레이션에서 완전히 다른 위치에 있는 contacts에 의존할지도 모른다, 그것들 사이의 공통된 오브젝트들이 없이.

reaction forces를 계산하기 위해서, 우리는 지난 챕터의 것처럼 iterative algorithm을사용할 수 없다. 우리는 좀 더 global view를 가져야만 하고, 한 수학적 구조에서 모든 force interations를 나타내고, one-for-all solution을 만들어야 한다. 대부분의 경우에 이것은 처리될 수있고, 그것은 가장 commercial physics middleware packages의 mathematical core이다. 우리는 우리가 chapter 18 도달 했을 때, 사용된 기법들을 볼 것이다.

몇 가지 경우에, 특히, resting contacts에 friction이 있을 때, 어떠한 해결책도 없다. reaction froces의 조합은 해결될 수 없다. 이것은 종종 그 시뮬레이션이 현실에서 발생할 수 없는 상태로 들어갈 때 발생한다 (numerical calculation errors 또는, 시간을 또한 stepping과 contact의 정확한 시간을 놓친 것 때문에). 그 컴퓨터는 글자그대로 불가능한 문제를 풀려고 하는 것이다.

그 같은 문제는 또한 우리가 완벽히 rigid bodies를 가정하기 때문에 발생할 수 있다, 거기에서, 현실에서 모든 오브젝트들은 어느 정도로 compressed 될 수 있다. 그리고 마지막으로, resting contact처럼 보이는 것은 현실에서 충돌일 때 발생할 수 있다. 만약 너가 거친 표면을 따라 한 오브젝트를 미끄러지게 한다면, 예를들어, 너는 갑자기 그것이 공중으로 튀어오르게 할 수 있을지도 모른다. 이것은 땅 과의 resting contact처럼 보이는 한 contact가 현실에서, a patch of high friction에 대한 충돌일지도 모르기 때문에 발생한다.

이러한 상황들 각각은 reaction forces의 한 집합을 얻는 수학을 해결하는데 문제를 이끈다. Special-case code 또는 tailored solving algorithms들이 불가능성을 탐지하고, 그것들에 다르게 반응하는데 필요하다 (일반적으로, 어떤 종류의 한 impulse를 도입하여).

만약 이것이 복잡하게 들린다면, 그것이 실제로 복잡하기 때문이다. 운 좋게도, 훨씬 더 간단한 (비록 다소 덜 정확할지라도) 솔루션이 있다. forces를 사용하여 모든 contacts를 resolving하는 것보다 (즉, collision impulses를 forces로 바꾸는 것), 우리는 반대의 것을 할 수있고, resting contacts를 충돌인 것처럼 다룰 수 있다.

15.2 Micro-Collisions
Micro-collisions는 일련의 impulses로 reaction forces를 대체한다: update당 한 개씩. impulse가 signel moment of time에서 적용되는 한 힘으로서 생각될 수 있는 것과 같은 방식으로, 한 force는 한 전체의 일련의 impulses로 생각되어질 수 있다. 10fN의 한 force를 한 오브젝트에 대해 10번의 updates에 적용시키는 것은 각 update당 fNs의 impulses를 적용하는 것과 같다.

각 time step에서 reaction forces의 한 집합을 계산하기 보다, 우리는 우리의 impulse resolution system이 impulses를 적용하는 것을 허용한다. 그림 15.3은 이것을 실제로 보여준다. 그 블럭은 땅위에서 resting할 것이다. 각 프레임에서 (잠시동안 interpenetration은 무시하고), 그 블럭은 가속하고, 그래서 그것은 땅으로의 한 속도를 가진다. 그 velocity resolution system은 그 속도를 제거하는데 필요한 impulse를 계산한다.

이러한 작은impulses는 가끔씩 "micro-collisions"라고 불려진다. 그것들의 사용은 reaction forces를 생성하는데 잘 알려진 기법이지만, 불안정한 시뮬레이션을 만들어내는데 충분치 않은 명성으로부터 고통을 겪는다.

만약 너가 chapter 14의 물리엔진을 작동시킨다면, 너는 오브젝트들에 서로에게 가라앉지 않는 것을 볼 것이다, 비록 작동중인 reaction force가 없을지라도. Micro-collisions는 이미작동중에 있다: 각 업데이트에서, 오브젝트들은 속도를 쌓고 있고, 결국 vecotiy resolution algorithm이 contacts들을 충돌로서 다루고 그 velocity를 없애게 된다.

resting contacts를 충돌로서 다루는 것의 두 가지 중요한 문제들이 있다. 그 첫 번째는 충돌들이 bounce하는 방식과 관련이 있다. contact point에서 separation speed가 closing speed의 고정된 비율로서 반대 방향으로 계산되는 것을 회상해라. 이 비율은 restitution의 계수이다.

만약 우리가 그림 15.3에서 보여지는 것과 같은 한 contact를 가진다면, rigid-body가 업데이트 된 후에, 땅으로 가는 속도가 축적될 것이다. 그 velocity resolution process동안, 이 velocity는 제거될 것이고, 그 desired 최종 velocity는 다음 처럼 될 것이다



여기에서 v_s는 충돌이 처리되기 전의 속도이고, v'_s는 처리 후에 같은 속도이고, c는 restitution 계수이다.

그래서 velocity가 업데이트 사이의 interval의 course동안 무엇을 축적하든지, 그것은 작은 "bounce"가 발생하도록 야기시킬 것이다. 만약 땅 위에 있는 우리의 sphere가 높은 c 값을 가진다면, 그 아래로 가는 속도는 위로가는 속도를 발생시킬 것이다.

그러나, 현실에서, 그 아래로 가는 속도는 결코 축적될 기회를 갖지 않는다. 그 sphere는 실제로 땅으로 가속할 수 없다. 그것이 축적하는 속도는 물리적으로 불가능하다. 이것은 resting contacts가 진동하는 것처럼 보이게 하는 효과를 갖는다. 그 오브젝트들은 함께 가속하고, collision algorithm이 그것들에게 separating velocity를 주게하는 속도를 축적시킨다. 땅 위에 있는 구는 gravity가 그것을 다리 아래로 끌어 당길 때 까지 튀어오른다. 그리고 거기에서 다시 그것은 튕기게 된다. 그것을 결코 rest에 고정되지 않을 것이지만, 진동하는 것처럼 보일 것이다.

restitution을 낮게 설정하는 것은 도움이 될 것이지만, 모델링될 수 있는 상황의 종류를 제한한다. 좀 더 유용한 솔루션은 두 변화를 만드는 것을 포함한다:


  • 우리는 이전 rigid-body update에서 가속도로부터 축적되어질 수 있는 어떤 속도를 제거한다.
  • 우리는 artifically하게, 매우 낮은 속도와 관련된 충돌에 대한 restitution 계수를 줄ㄹ인다.
독립적으로, 이러한 것들 각각은 몇 가지 시뮬레이션에 대해 vibration problem을 해결할 수 있지만, 여전히 다른 것들에서 문제를 보여줄 것이다. 그것들은 가능한한 함께 좋아질 것이다.

15.2.1 Removing Accelerated Velocity
이전 frame의가속도에 의한 속도를 제거하기 위해, 우리는 각 rigid-body update에서의 가속도를 추적할 필요가 있다. 우리는 rigid body에 대한 새로운 data member로 이것을할 수 있다. 그리고 그것은 계산된 linear acceleration을 저장한다. 그 rigid-body update routine은 그러고나서 모든 힘과 중력에 의해 생성된 가속도의 변수에 기록을 유지하도록 수정된다:


우리는 linear and angular acceleration 둘 다에 대한기록을 유지하도록 이것을확장할 수 있다. 이것은 좀 더 정확하게 만들 것이지만, 대부분의 reaction forces는 gravity (항상 linear한)에 의해서 만들어지기 때문에, 그 추가 계산은 보통 어떤 시각적 이득을 주지 않는다. 사실, 몇 몇 개발자들은 지난 frame에서 추가된 속도를 계산할 때, 중력을 제외한 어떤 force는 무시하는것을 선택한다. 이것은 그 계산을 여전히 더 간단하게 만든다, 우리가 acceleration data member로부터 직접적으로 중력에 의한 가속도를 읽을 수 있기 때문이다.

우리가 한 contact에 대해 속도에서의 desired change를 계산할 때, 우리는 가속도로부터 유발된 속도를 뺀다, contact normal의 방향으로:




그 desired change in velocity는 다음으로 변경된다


이 간단한 adjustment는 땅 위에서 resting하는 오브젝트들에시각적 vibration의 양을줄인다. 오브젝트들은 stacks와 같은 tight groups에 있을때, 그 vibration은 돌아올 수 있다. 그 문제를 해결하기 위해, 우리는 두 번째 단계를 수행할 것이다 - restitution 계수 줄이기.

우리는 이 챕터의 나중에 가속도에 의한 발생된 속도로 돌아올 것이다. 우리는 resting contact에서 friction이 있는 한 문제를 해결하기 위해 이 종류의 또 다른 계산이 필요할 것이다.

15.2.2 Lowering The Restitution
우리가 이전 섹션에서 만들었던 변화는 효과적으로 contacts에서의 restitution을 줄인다. 속도를 줄이기 전에, 우리는 closing velocity보다 더 큰 separating velocity를 가진 충돌을 갖는다: 그 오브젝트들은 그것들이 resting하기 시작했을 때 심지어 분리되어 눌려진다. 이것은 1 이상의 restitution 계수가 있을 때 발생한다. 그 계수가 작을수록, bounce가 덜할 것이다.

그 가속도 보상은 홀로 작동할 수 없을 때,우리는 수동으로 vibration을 막기 위해 restitution 계수를 낮출 수 있다. 이것은 매우 간단한 방식으로 된다:

우리는 좀 더 정교한 방법을 사용할 수 있는데, 거기에서 restitution은 스케일링 된다, 더 작은 속도에 대해서는 더 작게, 하지만 그 버전은 여기에서 실제로 꽤 잘 작동한다. 만약 너가 오브젝트들이 느려질 때 bouncing과 sticking 사이의 보이는 변화를 본다면, 그 속도 제한을 줄이려고 시험삼아 해보아라 (나는 내 엔진에서 약 0.1의 값을 사용한다). 만약 이것이 vibration을 도입한다면, 그러면 그 scaling approach는 너에게 유용할지도 모른다.

15.2.3 The New Velocity Calculation
resting contacts에 대해 두 기법들을 합쳐서, 우리는 우리의 adjustVelocities method에 다음의 코드를 갖게 된다:

나는 이 연산을 calculateDesiredDeltaVelocity에 위치시켰따, 그리고 그것은 calculaeInternals method의 일부로서 호출된다. velocity resolver가 가장 심각한 collisions를 찾도록 매번 수행되는 계산을 갖는 것보다 이것이 더 선호된다.

이 접근법은 cyclone physics engine에서 거의 모든 눈에 보이는 vibrations를 제거한다. 우리가 다음 챕터에서 만날 최적화 기법들 중의 하나는 그 나머지를 제거한다.

15.3 Types of Friction
나는 이 책 전체에서 마찰을 몇 번 언급해왔고, 이제 그것을 다룰 시간이다.

Friction은 한 오브젝트가 움직이거나, 다른것과 접촉해서 움직일 때 발생되는 force이다. 두 오브젝트들이 아무리 부드러워 보일지라도, microscopically하게, 그것들은 거칠고, 이러한 작은 protrusions(돌출부)는 서로를 잡게되고, 상대적인 motion 또는 motion beginning에 대한 저항에서 감소를 발생시킨다.

Friction은 또한 drag의 작은 부분에 대해 책임이 있다, 공기 분자가 한 오브젝트의 표면을 움직이려 할 때. (Drag는 많은 다른 요소들을 갖는다, turbulence(난류), induced pressure, 그리고 오브젝트와 공기 분자 사이의 충돌 같은 것들).

마찰의 두 가지 형태가 있다: static and dynamic. 그것들은 다소 다른 방식들로 해동한다.

15.3.1 Static And Dynamic Friction
정적 마찰은 한 오브젝트가 정지했을 때 움직이는 것을 막는 force이다. ground에서 resting하고 있는 한 블럭을 고려해라. 만약 그 블럭이 어떤 힘이 주어진다면, 블럭과 땅사이의 마찰은 이 힘에 저항할 것이다. 이것은 reaction force의 한 종류이다: 너가 더 밀 수록, 더 많은 마찰이 밀어낸다. 그러나, 어떤 지점에서, 그 pushing force는 friction에 대해 너무 많아서, 그 오브젝트가 움직이기 시작한다.

static friction은 오브젝트가 움직이는 것을 막기 때문에, 그것은 가끔 "stiction(정지마찰)"로 불려진다. 그 정적 마찰력은 contact점에서의 물질과 reaction force에 의존한다:



여기에서 r는 contact normal의 방향에 있는 reaction force이고, f_static은 생성된 friction force이고, u_static은 static firction의 계수이다.

friction 계수는 contact에 있는 material properties를 단일 숫자에 캡슐화한다. 그 값은 두 오브젝트에 의존한다; 그것은 간단히 한 오브젝트에 대한 계수를 다른 것에 대한 계수에 더해서 생성될 수 없다. 사실, 그것은 경험에 의한 양이다: 그것은 실험에 의해 발견되고, 확실하게 계산되어질 수 없다.

물리 reference book에서, 너는 종종 다른 물질의 쌍에 대한 마찰 계수의 테이블을 발견할 것이다. 게임 개발 환경에서, 한 특별한 contact에 대한 계수는 좀 더 종종 guesswork or trial and error의 결과이다. 나는 appendix B에서 유용하다고 발견한 마찰 계수의 한 테이블을 포함시켰다.

이전의 공식이 부등식이라는 것에 유의해라: 그것은 <= 기호를 사용한다. 이것은 마찰력의 크기가 u|r|를 포함하여 거기까지 될 수 있다는 것을 의미한다. 사실, 이 한계까지, 그것은 정확히 그 오브젝트에 발휘된 힘과 같다. 그래서 static friction force에 대한 전체 식은 다음과 같다

 whichever is smaller in magnitude,

여기에서 f_planar contact의 평면에서만 그 오브젝트에 대한 total force이다, contact normal의 방향에 있는 resulting force가 reaction force를 발생시키기 때문이다. 그 reaction force와 planar force는 적용되는 total force로부터 계산되어질 수 있다:



여기에서 widehat(d)는 contact normal이고, f는 발휘되는 total force이고,



다시 말해서, resulting planar force는 contact normal의 방향의 컴포넌트가 제거된 total force이다. 방정식에서, 이 컴포넌트는 reaction force를 더해서 제거된다, 그리고 그 reaction force는 contact의 방향에 있는 힘과 동일하고 반대방향이고, 그러므로 그것을 상쇄 시킨다.

normal reaction force에 대한 static friction의 의존은 중요한 결과이다. 그것은 rock climbers가 다른 벽에 그들의 등을 대고 밀어서 수직 slope를 걸어가게 해준다 - reaction force에서의 증가는 증가된 마찰을 의미한다. 충분히 push해라, 그러면 너의 무게를 극복할 충분한 마찰이 있을 것이고, 너가 떨어지는 것을 막을 것이다.

이전 방정식의 또 다른 중요한 특징은, 마찰이 땅과 접촉해있는 지역에 의존하지 않는다는 것이다. 더 큰 발을 가진 rock climber는 더 잘 붙어있는것이 아니다. 다소 비직관적임에도 불구하고 (적어도 나에게는), 이것은 운이 좋다, 왜냐하면 우리 엔진의 어디에서도, 우리는 contact area의 사이즈를 고려하지 않기 때문이다. Contact area는 오브젝트들이 contact point에서 변형할 수 있는 경우에 중요하게 된다 (tire models이 즉시 떠오른다), 하지만, 그것들은 매우 복잡하고 이 책의 범위를 넘어선다. 그래서 우리는 기본 공식만을 고수할 것이다.

땅에 있는 우리의 block으로 돌아가서: 우리가 좀 더 많은 힘을 발휘할수록, 마찰은 우리가 u_static|r|에 도달할 때까지 밀어낼 것이다, 그것은 static friction의 한계이다. 만약 우리가 마찰로 force input을 증가시킨다면, 그 마찰력은 갑자기 떨어지고, 우리는 dynamic friction에 들어가게 된다.

Dynamic Friction
"kinetic friction"이라고 또한 불려지는, Dynamic friction은 static friction과 유사한 방식으로 행동하지만, 다른 마찰 계수를 가진다.

contact에 있는 오브젝트들이 서로를 기준으로 움직일 때, 그것들은 일반적으로 microscopic level에서 contact를 떠난다. 그림 15.4는 여러반 강화된 static dynamic friction
을 보여준다. 그 오브젝트가 움직이기만 한다면, 각 오브젝트에서의 거칠기는 밀접하게 맞물리지 않는다, 그래서 dynamic friction은 덜 강력한 힘이 된다.

Dynamic firction은 항상 다음의 방정식을 따른다



여기에서 u_dynamic은 dynamic friction 계수이다. friction의 방향이 변했다는 것을 유의해라. planar force에 반대 방향으로 행동하기보다 (static friction에 대해 헀던 것 처럼), 그것은 이제 오브젝트의 속도와 반대 방향으로 작동한다. 이것은 중요하다: 만약 너가 한 정지한 오브젝트에 힘을 주는 것을 멈춘다면, 그러면 그 마찰력은 즉시 또한 멈출 것이다. 만약 너가 움직이는 오브젝트에 한 force를 주는 것을멈춘다면, 마찰은 멈추지 않을 것이다: 그 오브젝트는 dynamic friction에 의한 중단으로 느려질 것이다.

static friction처럼, dynamic friction 계수는 다른 물질의 조합에 대한 몇 가지 물리 레퍼런스 책에서 발견될 수 있다.

실제로 static and dynamic friction을 구분하는 것은 게임 물리엔진에서 드물다. 그것들은 generic friction value로 합쳐지는 경향이 있다. 그 오브젝트가정지할 때, 그 마찰은 static friction으로 작동하고, 어떤 발휘된 힘에 반대하여 작동한다. 그 오브젝트가 움직일 때, 그 마찰은 dynamic friction으로 작동하고, 움직임의 방향과 반대로 작동한다.

우리가 이 챕터에서 개발할 마찰 모델은 이 모델을 따를것이고, 두 가지 마찰 유형들을 한 값으로 통합할 것이다. 다음에 나오는 것에서, 나는 우리가 static friction을 어디에서 사용하는지와, 그것이 dynamic인지를 지적할 것이다. 그래서 너는 만약 너가 필요하다면 단일 값을 두 개의 값으로 대체할 수 있다.

Rolling Friction
dynamic simulation에서 중요한 한 가지 더 마찰의 종류가 있따. Rolling friction은 한 오브젝트가 다른 것을 따라 구를 때 발생한다. 그것은 가장 흔히 racing simulations에 대해 high-quality tire models를 위해 사용된다 (racing games보다는 motor-racing teams에의해 수행되는 시뮬레이션의 의미로).

나는 rolling friction을 포함하는 포괄적인 타이어 모델을 가진 게임을 위한 물리엔진을 만나보지 못했다. 그러나 나는 그것을 포함하는 게임이 아닌 물리엔진과 작업했다. 그러나, 우리는 게임 프로그램에 집중하기 때문에, 나는 책의 나머지동안 rolling friction을 무시할 것이다.

15.3.2 Isotropic And Anisotropic Friction
우리가 인지할 필요가 있는 마찰의 유형 사이의 한 개의 추가적인 구분이 있다: friction은 isotropic하거나 anisotropic 둘 중 하나이다. Isotropic friction은 모든 방향에 대해 같은 계수를 갖는다. Anisotropic friction은 다른 방향에 다른 계수를 갖는다.

그림 15.5는 위에서 땅 위에 있는 한 블럭을 보여준다. 만약 그것이 처음 방향에서 눌려진다면, 그러면 그 마찰력은 u_a의 계수를 갖을 것이다; 만약 그것이 두 번째 방향으로 눌려진다면, 그러면 그 마찰력은 u_b의 계수를 갖을 것이다. 만약 u_a = i_b가 갖다면, 그러면 그 마찰은 isotropic이다; 그렇지 않다면 anisotropic이다.

상당히 대닷의 게임 시뮬레이션들은 isotropic friction을 처리할 필요가 있다. 사실, 내가 사용한 대부분의 엔진들은 purely하게 isotropic하거나, 프로그래머가 anisotropic friction을 얻기위해 추가적인 hoop를 통해 점프하도록 했다. 심지어 그러고나서, anisotropic friction model은 매우 간단하게 된다. 우리는 이 책에서 isotropic friction만을 고수할 것이다.

15.4 Implementing Friction
물리 시뮬레이션에 마찰을 도입하는 것은 존재하는 물리가 어떻게 구현되었는지에 의존한다. 우리의 경우에 resting contacts에 대해 micro-collisions를 갖는 impulse-based engine을 가지고 있다. 이것은 우리가 resting contacts에서 normal reaction force를 계산하지 않는 다는 것을 의미한다. 게다가, 우리는 믿을만한 행동을 생성하기 위해 contacts의 힘보다는 impulses를 도입했다.

이것은 우리가 이제까지 보았던 마찰 방정식을 직접적으로 가지고 오는 것을 어렵게 한다: 우리는 reaction force에 대해 계산을 갖지 ㅇ낳고, 우리는 contact point에 힘을 적용시키는 쉬운 방법을 가지고 있지 않다(우리의 엔진에서 현재 물리 업데이트에 대한 forces들은 충돌 탐지가 시작하기 전에 적용된다는 것을 기억해라).

만약 너가 force-based engine과 작업한다면, 특히 모든 contacts에 대해 reaction forces를 계산하는 것, 그러면 마찰은 계산에서 또 다른 force가 될 수 있고, 그래서 우리가 봤던 방정식들은 직접적으로 적용될 수 있따. 비록 이것은 더 간단하게 들릴지라도, 그 요구되는 힘을 계산하는 것을 훨씬 더 어렵게 만드는 결과들이 있다. 나는 chapter 17에서 friction-specific force calculation으로 돌아갈 것이다. 이 단계에서, 우리가 마찰을 impulses로 변환해야만 한다는 것을 주목하는 것은 간단히 가치가 있다, 비록 우리가 force-only route를초기에 겪었을지라도, 그것은 마찰을 더 쉽게 만들지는 않을 것이다.

15.4.1 Friction As Impulses
우리의 시뮬레이션에서 마찰을 다루기 위해서, 우리는 처음에 마찰이 impulses와 속도의 관점에서 무엇을 하는지를 이해해야만 한다.

정적 마찰은 한 force가 body에 적용될 때 움직이는 것을 막는다. 그것은 contact plane에 있는 그 오브젝트의 속도가 0으로 유지하기 위해 작동한다.

우리의 시뮬레이션에서, 우리는 속도가 축적되는 것을 허용하고, 그러고나서 우리는 micro-collision으로 그것을 제거한다. 우리는 collision velocity를 따라서, sliding velocity를 제거하여 static friction을 재현할 수 있따. 우리는 이미 contact normal의 방향으로 그 오브젝트의 속도를 조절한다. 우리는 다른 두 개의 contact direction으로 유사한 것을 할 수 있다(즉, contact의 평면에 있는 방향들). 만약 우리가 각 방향에 대해 contact normal에 대해 했던  것처럼 같은 process를 겪는다면, 우리는 이러한 방향에 있는 속도가 0이 되도록 보장할 수 있다. 이것은 정적 마찰의 효과를 줄 것이다.

속도의 변화에 대해 단일 값을 갖는 대신에, 우리는 이제 contact coordinates로 표현되는 한벡터를 갖는다:


real deltaVelocity; // ... Calculate this as before ...


glm::vec3 deltaVelocityVector(deltaVelocity, 
-contactVelocity.y, -contactVelocity.z);

나는 이것을 처리하는 resolution algorithm에서 필요한 변화에 대해 다시 돌아올 것이다.

이 접근법은 모든 sliding을 없앨 것이다. 그러나 정적 마찰은 한계를 가진다: 그것은 오직 오브젝트들이 maximum force까지 미끄러지는 것을 방지한다. 충돌을 다룰 때, 우리는 어떤 forces를 갖지 않고, 오직 속도만을 가진다. 우리가 어떻게 제거될 수 있는 속도의 최대양을 결정할 수 있는가?

속도가 impulse에 관련된 것을 기억해라:



여기에서 g는 impulse이고, m은 질량, dot(p)는 속도이다. 그래서, 만약 우리가 우리가 제거할 필요가 있는 속도의 양을 안다면, 우리는 그것을 제거하는데 요구되는 impulse를 계산할 수 있다.

같은 방식으로, impulse는 짧은 시간 주기동안 발휘되는 한 force이다:



여기에서 f는 force이고, t는 time이다. 속도를 제거하는데 요구되는 impulse와 update의 duration을 고려한다면,우리는 그 속도를제거하는데 요구되는 force를 계산할 수 있다.

그 방정식은 여전히 normal reaction force를 요구한다. 이것은 같은 방식으로 계산되어질 수 있지만, contact normal를 바라본다. 그 normal reaction force는 근사적으로 contact normal의 방향으로 제거되는 속도의 양으로부터 계산되어질 수 있다.

만약 contact normal에서 속도의 desired change가 v라면, 그러면 그 reaction force는 다음으로 근사되어질 수 있다



우리가 이미 가진 velocity resolution algorithm은 velocity에서 desired change를 성취하는데 필요한 impulse를 계산하는 것을 포함한다. 이 impulse는 초기에 contact coordinates에서 발견된다. 우리는 impulses에서 작업할 것이기 때문에, 우리는 그 이전 방정식을 마찰 방정식과 합칠 수 있고, 다음을 갖게 된다



여기에서 Delta-g_normal은 contact normal의 방향에 있는 impulse이다 (즉, 우리가 현재 우리의 velocity resolution algorithm에서 계산하는 impulse). 이러한 impulse values들이 스칼라라는 것에 유의해라. 이것은 우리에게 우리가 static friction으로 적용할 수 있는 total impulse를 말해준다. 코드에서 이것은 이것처럼 보인다:


glm::vec3 impulseContact;

// ... Find the impulse required to remove all three componets of
// velocity (we'll return to this algorithm later) ...

real planarImpulse = real_sqrt(impulseContact.y * impulseContact.y +
impulseContact.z * impulseContact.z);

// CHeck whether we're within the limit of static friction.
if(planarImpulse > impulseContact.x * friction)
{
     // Handle as dynamic friction.
}

Dynamic friction은 impulse의 y와 z 컴포넌트들로 처리될 수 있다. 그것들의 결합ㅂ된 사이즈가 정확히 u * x impulse의 크기가 되도록 하기 위해서이다.


impulseContact.y /= planarImpulse;
impulseContact.z /= planarImpulse;

impulseContact.y *= friction * impulseContact.x;
impulseContact.z *= friction * impulseContact.x;

planarImpulse로 나누느 것은 y와 z 컴포넌트들을 스케일링하는데, 그것들이 단위 크기를 갖기 위해서이다; 이것은 그것들의 크기를 없애는 반면 그것들의 방향을 유지하기 위해 된다. 그것들의 크기는 마찰 방정식에 의해 주어진다 - friction * impulseContact.x. 그 방향을 크기로 곱하는 것은 각 컴포넌트에 대해 새로운 값들을 준다.

15.4.2 Modifying The Velocity Resolution Algorithm
이전 섹션에서, 나는 우리가 contact plane에서 velocity를제거하는데필요한 impulses를 어떻게 계산하는지에 대해 glossed 했다. 우리는 이미 contact normal에대해 이것을하는 코드를 가지고 있고, 우리는 간닫ㄴ히 이것을 다른 방향에 대해 복사할 수 있다.

불행하게도, 매우 길어져서, 이것은 잘 작동하지 않을 것이다. 한 방향에 있는 한 impulse는 한 오브젝트가 회전하게끔 할 수 있고, 그것의 contact point는 완전히 다른 방향으로 움직이기 시작할 수 있다. 우리가 contact normal의 방향에 있는속도에만 관심이 있는 한, 이것은 중요하지 않다. 이제 우리는 동시에 모든 세 개의 방향을 다룰 필요가 있고, 우리는 한 방향에 있는 impulse가 다른 방향으로 contact의 속도를 증가시킬 수 있다는 사실을 고려해야할 필요가 있다. 세 개의 속도를 resolve하기 위해, 우리는 동시에 각각에 대해 reesolution algorithm을 처리할 필요가 있다.

그 resolution algorithm은 이전처럼 다음의 단계들을 갖는다:


  1. 우리는 contact를 기준으로 하는 좌표에서 작업한다: 이것은 대부분의 수학을 더 간단하게 만든다. 우리는 이러한 새로운 좌표셋으로 변환시킬 transform matrix를 만든다.
  2. 우리는 단위 impulse당 각 오브젝트에서 contact point의 속도에서의 변화를 처리한다. impulse가 linear and angular motion을 발생시킬 것이기 때문에, 이 값은 둘 컴포넌트 다 고려할 필요가 있다.
  3. 우리는 우리가 보고 싶은 (다음 단계에서) 속도변화를 알 것이다. 그래서, 우리는 어떤 주어진 속도 변화를 생성하기 위해 필요한 impulse를 발견하기 위해 마지막 단계의 결과를 invert한다.
  4. 우리는 contact point에서 separating velocity가 무엇이 되어야 하는지를, closing velocity가 현재 무엇인지, 그 둘 사이의 차이가 무엇인지를 처리한다. 이것은 desired change in velocity이다.
  5. velocity에서의 변화로부터, 우리는 생성되어야 할 충격을 계산할 수 있다.
  6. 우리는 그 impulse를 linear and angular components로 분할하고, 그것들을 각 오브젝트에 적용한다.


우리는 5와 6사이에 새로운 단계를 삽입했었따, impulse가 static friction 방정식을 쓰는지, 그렇지 않으면 dynamic friction을 사용해서.

Step 2는 수정을 요구한다. 현재, 그것은 contact normal의 방향에서의 unit impulse를 고려하여 change in velocity를 처리한다. 우리는 이제 모든 세 개의 contact directions를 다루고 있다. 우리는 세 개의 contact directions에 있는 impulses의 어떤 조합이든지를 고려하여, 속도의 변화를 계산할 필요가 있다. 그 impulse는 contact coordinates에서 한 벡터로 표현될 수 있다:


glm::vec3 contactImpulse;

그 x 컴포넌트는 contact normal의 방향에 있는 impulse를 나타내고, y와 z component는 contact의 평면에 있는 impulse를 나타낸다.

step 2의 결과는 한 행렬이 될 것이다: 그것은 한 벡터(the impulse)를 또 다른 벡터 (resulting velocity)로 변환할 것이다. 이 행렬로, 그 알고리즘의 나머지는 간단하다. step 3에서, 우리는 행렬의 inverse를 찾을 것이다(즉, desired change in velocity를 요구되는 impulse로 바꾸는 행렬), 그리고 step 5에서 우리는 contactImpulse vector를얻기위해 desired velocity vector를 변환할 것이다.

그래서 우리는 어떻게 그 행렬을 계산하는가? 우리는 section 14.2.2에서 보았던 같은 단계를 따른다. 우리는 angular motion의 결과로서의 속도 변화를 계산하고, 그 속도 변화를 linear motion의 결과로 계산한다.

Velocity from Angular Motion
section 14.2.2에서, 우리는 impulse로부터 rotation-derived velocity를 계산하는 알고리즘을 보았었다:


glm::vec3 torquePerUnitImpulse = glm::cross(relativeContactPosition, contactNormal);

glm::vec3 rotationPerUnitImpulse = inverseInertiaTensor * torquePerUnitImpulse;

glm::vec3 velocityPerUnitImpulse = glm::cross(rotationPerUnitImpulse, relativeContactPosition);

glm::vec3 velocityPerUnitImpulseContact = glm::transpose(contactToWorld) * velocityPerUnitImpulse;

그 첫 번째 단계는 contact normal의 방향에서 unit impulse에대해 torque의 양을 계산한다. 그 두 번째 단계는 이 torque를 inertia tensor를 사용하여 velocity로 변환한다. 그 세 번째 단계는 contact point의 linear velocity를 resulting rotation으로부터 계산한다. 그리고 마지막 단계는 그 속도를 다시 contact coordinates로 변환한다.

첫 번째 단계에서, contact normal을상요하기 보다, 우리는 contact의 모든 세 방향을 사용할 필요가 있다: 그 basis matrix. 그러나 만약 그 contact normal이 한 행렬로 대체된다면, 어떻게 우리는 외적을 수행할 수 있는가?

그 답은 외적의 대안의 formation에 있다. 한 벡터를 행렬로 변환하는 것은 한 벡터를 준다는 것을 기억해라. 한 벡터의 외적은 또한 한 벡터를 준다. 우리가 벡터 곱의 행렬 형태를 만들 수 있다는 결과가 나타난다.
한 벡터에 대해



벡터곱 v X x는

행렬 벡터곱과 동일하다:




이 행렬은 "skew-symmetric" 행렬이라고 불려지고, 외적에 대한 중요한 결과는 외적이 대응되는 skew-symmetric matrix를 곱하는 것과 같다는 것이다.

왜냐하면, 우리가 보았듯이, v X x = -x X v와 같기 때문이다; 그리고 만약 우리가 이미 v의 skew symmetric version을 가지고 있다면, 우리는 x X v를 x의 행렬 형태를 구성하는 것 없이 계산할 수 있다. 그것은 간단히



사실, 우리는 우리의 알고리즘의 첫 번째 단계에서의 외적을 impulse를 torque로 바꾸는 것으로 생각할 수 있다. 우리는 방정식 10.1로부터, 한 force vector가 contact point와 외적을 취하여 torque vector로 될 수 있다는 것을 안다:



(이것은 방정식 10.1이다).

그 skew symmetric matrix는 이 변환으로 생각되어질 수 있다, 힘을 torque로 바꾸는.

한 matrix의 컴포넌트들을 벡터로부터 설정하는 능력을 갖는 것은 유용하다. 그래서 우리는 Matrix3 class에 편리한 함수를 추가한다:


이제 우리는 같은 단계들을 전체 basis matrix로 처리할 수 있다:

여기에서 그 같은 행렬은 계산의 중간 단계를 위해 재사용된다, chapter 14처럼.

우리가 효과적으로 역이세ㅓ 하는 것은 world coordinates에서 모든 계산을 수행하는 것이다 (즉, 우리는 impulse를 velocity로 바꾸는 행렬을 갖게 될 것이다, 월드 좌표에 있는 둘 다) 각 each body에 대해. 그러고나서 우리는 그 두 개의 결과를 함게 더하고나서, 이 행렬의 기저를 바꾸는데, 그것이 impulse를 contact 좌표의 velocity로 바꾸기 위해서이다. section 9.4.6에서 우리가 행렬의 기저를 다음으로 바꾼다는 것을 회상해라.



여기에서 B는 기저 행렬이고, M은 변환될 행렬이다. 이것은 B가 회전 행렬일 때만 BMB^t와도 동일하다 (contactToWorld matrix에 대해서). 그러므로 그 코드의 마지막 세줄이 이렇게 된 것이다.

Velocity from Linear Motion
지금까지, 우리는 오직 회전에 의해 발생되는 속도 변화를 가졌다. 우리는 또한 impulse로부터의 linear velocity의 변화를 포함시킬 필요가 있다. 이전처럼, 이것은 간단히 inverse mass에 의해 주어진다:



이것은 다시 한 벡터(impulse)에서 다른 벡터(velocity)로 바꾸는 transformation이다. 우리가 속도의 linear and angular 컴포넌트들을 결합하는 한 행렬을 가질 것이기 때문에, inverse mass를 한 행렬로 표현하는 것은 유용할 것이다, 우리가 이미 가진 angular matrix에 더해질 수 있게 하기 위해서이다.

이것은 간단히 될 수 있따. 한 벡터를 스칼라양 k로 곱하는 것은 그것을 다음의 행렬로 바꾸는 것과 같다



너는 벡터 곱을 해서 이것을 수동으로 체크할 수 있다.

linear motion과 우리가 이미 가진 angular motion과 합치기 위해서, 우리는 행렬의 대각선 성분에 inverse mass를 더할 필요가 있다.

15.4.3 Putting It All Together
우리는 이제 우리가 isotropic friction을 지원하는데 필요한 모든 수정을 합칠 준비가 되었다. 이러한 수정은 오직 contact의 applyVelocityChange method에 만들어진다.: 그것들은 모두 micro-collision으로서 처리된다. 마지막 코드는 이렇게 보인다:


15.5 Friction And Sequential Contact Resolution
이 챕터에서의 수정으로, 우리의 물리엔진은 큰 도약을 했다. 그것은 이제 모든 종류의 contacts와 isotropic friction을 가진 rigid bodies를 모델링할 수 있따.

몇 가지 우리가 볼 수 있는 lingering하는 안정성 문제들이 여전히 있고, 우리가 기대할 수 있는 성능에서의 큰 증가가 있다. 우리는 다음 챕터에서 이러한 것들 둘 다 볼 것이다.

이 단계에서, 우리는 또한 물리학에 대하 micro-collision approach의 피할 수 없는 주된 한계를 볼 수 있따. tweaking의 어떠한 양도 이것이 완전히 사라지게 할 수 없을 것이다.

그림 15.6은 전형적인 상황을 보여주는데, 두 개의 박스들이 서로 접촉해 있다. 그 박스들 중 어떠한 것도 움직이지 않고, 모든 contacts들이 매우 높은 마찰을 갖는다 (그것이 무한이라고 가정하자: static friction은 결코 극복될 수 없다).

시퀀스의 첫 번째 부분에서, 그 박스들은 resting contact에 있다; 두 번째 부분에서, 그것들은 중력의 결과로 다소 관통한다. 세 번째 부분에서 그것들은 그것들의 관통을 해결시키는데, linear and angular component가 resolution에 들어간다. 시퀀스의 네 번째 부분에서, 그 contact resolution은 완전하다.  시퀀스의 두 번째 라인에서 첫 번째에서 세번째 부분은 같은 프로세스의 또 다른 반복을 보여준다: interpenetration, penetration resolution, and contact resolution.

시간이 흐름에 따라, 박스가 떨어져서 움직있다는 것은 명백하다. 그것들은 미끄러지고 있따, 비록 그것들이 무한의 마찰을 가지고 있을지라도. 우리가 시퀀스의 마지막 부분에 도달할 즈음에, 그림에서 그 꼭대기에 있는 박스는 너무 멀리 움직여서, 더 이상 밑에 있는 박스에게 지지를 받을 수 없고, 떨어지기 시작한다.

이것은 sequential contact resolution scheme에 의해 발생한다. 그 resolution algorithm이 contact A를 고려하고 있는 동안, 그것은 contact B를 고려할 수 없다. 그러나 우리가 마찰을 가질 때, B에서의 마찰 계수는 contact A가 어떻게 해결되어야 하는지에 대한 영햐을 갖는다. minor adjustment의 어떠한 양도 이 문제를 해결하지 못할 것이다: 그것을 해결하기 위해, 우리는 contacts들을 동시에 처리할 필요가 있거나, contact-sensitive penetration resolution을 수행하기 위해 많은 특별 케이스 코드를 만들 필요가 있다.

실제로, 이것은 중대한 문제가 아니다, 만약 너가 블럭들의 스택을 쌓지 않는다면. 심지어, 이 경우에, 우리가 다음 챕터에서 구현할 sleeping system이 그 미끄러지는 것인 플레이어가 그 스택을 흩뜨려 놓은 후에 발생하도록 보장한다. 만약 너가 조금 두드리기에 안정적인 오브젝트들의 큰 stacks을 만들 필요가 있다면, 너는 chapter 18에 있는 simultaneous resolution approaches 중ㅇ 하나 또는 fracture physics를 사용할 수 있다, 그것은 chapter 17에서 설명된다.

15.16 Summary
Resting contacts는 마치 그것들이 아주 작은 bouncing contacts인 것처럼 다뤄질 수 있다: 그 contact interpenetration은 해결되고, closing velocity는 작은 impulse를 적용하여 killed된다.

한 시뮬레이션 프레임의 전체 duration을 한 instant of impulse로 제거하여, 우리는 간단히 엔진에 마찰을 추가할 수 있었다. 마찰의 효과는 그 impulse를 수정한다, 그것이 contact에 있는 오브젝트들에 적용되기 전에. 이것은 간단하고 마찰에 대한 강력한 접근법이지만, 문제가 없는 것은 아니다. micro-collisions를 사용하여 static and dynamic friction사이의 차이를 보여주는 것은 훨씬 더 어렵다 (사실, 우리는 계수를 한 값에 통합하여 그 문제를 피했다).

micro-collisions를 사용하여 재현된 contacts가 가진 또 다른 문제는, 그것들이 다소 진동하는 것처럼 보일 수 있다는 것이다. 이것은 우리의 현재 엔진 구현이 직면하는 안정성의 문제중의 하나이다. chapter 16에서, 우리는 전반적으로 안정성을 볼 것이고, 우리의 엔진의 현실성을 개선할 것이다. 그러고나서, 우리는 코드가 불필요한 작업을 덜 하도록 하여 그것의 성능을 개선시키는 방법을 볼 것이다.














댓글 없음:

댓글 쓰기