Post Lists

2019년 1월 20일 일요일

Custom Physics Engine - Part 1 : Impulse Resolution

http://www.randygaul.net/2013/03/27/game-physics-engine-part-1-impulse-resolution/
Randy Gaul의 자료 번역. Box2D Lite를 기반으로 한 것 같다.

======================================
Personal Update
~~

Game Physics High Level Detail
게임 물리 엔진은 shapes가 특정한 방식으로 움직이도록 하기 위해 몇 가지 기능을 수행한다. 이것을 주장하기 위해, 누군가는 다음과 같이 말할 수 있다: 물리 엔진은 움직이는 bodies의 자유도를 제거하고, 이러한 부과된 규칙들을 강화한다.

여기에서부터, 명시될 때 까지, 그렇지 않으면 나는 특정하게 물리 엔진 내에서 convex rigid bodies에 대해 말할 것이다. rigid body는 implicitly하게 rigid한 shape이다; 그 엔진은 자연스럽게 shape를 구성하는 점들의 한 집합의 deformation을 지원하지 않는다. 이 implicit 정의를 사용하여, 그러한 도형을 다루는 것 뒤에 있는 수학은 직관적이고 효율적으로 구현될 수 있다.

여기에 custom 물리 시스템이 제공할지도 모르는 몇 가지 기능들의 짧은 리스트가 있따. 엔진이 rigid bodies를 사용하는 것을 가정한다:

  • 충돌 탐지
  • 충돌 해결
  • 선형 움직임, 회전 그리고 적분(integration)
  • Raycasting
  • Islanding/Sleeping/Portals
  • Friction simulation
  • Spatial Partitioning/Bounding volumes
  • Fracturing/Splitting
  • Multi-part Bodies
  • 다양한 유형의 도형들
  • 고급 수학 제약 (joints, motors, contact constraints, 등)
이 자료 시리즈에서, 나는 내 시간대로 위의 주제들 모두에 대해 말할 것이다. 나는 적은 시간에 물리와 물리엔진에 대해 많이 배웠고, 내가 배운 것을 문서화하여, 나의 이해가 강화되기를 바란다. 또한 내가 얻은 것을 다른 사람들이 성취하도록 도와주기를 바란다. 나는 다른 이로부터 도움 없이 내가 아는 만큼 배우지 않았다. 그래서 같은 것을 하기를 원하는 것은 당연하다.

위의 기능 리스트의 대부분을 이용하는 오픈소스 물리 엔진의 가장 좋은 예시는 Erin Catto의 Box2D이다. 이 자료 시리즈의 나머지는 내가 스스로 쓴 물리 엔진을 세부적으로 다룰 것이다. 물론 말하지 않을 내가 선택한 다른 방법들이 있다. 

Architecture
물리엔진을 구성하는 두 개의 주된 오브젝트들이 있다: shapes and bodies. 한 body는 한 물리 오브젝트의 intrinsic properties를 정의하는 data의 package이다. 다른 flags 또는 설정과 함께 density, restitution(elasticity), friction coefficients, inertia tensors 같은 특성들은 그 body내에 저장되어야 한다. 이러한 데이터는 shape definition과 고립될 수 있는 특성이다. 그 shape 그 자체로는 pointer를 통해 body와 함께 포함된다.

shape definition은 한 physics object가 어떤 일종의 shape를 나타내는지를 정의한다. 어떤 물리 엔진은 한 body에 여러 shapes를 붙일 수 있따. 그리고 그것은 fixtures라고 언급된다. 한 shape는 그 shape 그 자체를 정의하는데 요구되는 어떤 데이터를 저장하고, 그 shape에 작동하는 다양한 함수들을 제공한다. 예를들어 line or point intersection 테스트 또는 bounding volume 생성.

body와 shape는 함께 물리 오브젝트를 나타낸다. 그리고 이 자료 시리즈의 끝에서, 그것은 다른 물리 오브젝트들과 많은 흥미로운 상호작용을 수행할 수 있을 것이다.

모든 bodies는 scene or world라고 알려진 것 내에 포함되어야만 한다. 나는 이 오브젝트를 scene이라고 부른다. 그 scene은 모든 살아있는 오브젝트들의 한 list를 포함할 뿐만 아니라, scene으로부터 bodies를 넣거나 제거하는 기능을 포함한다. 그 scene은 또한 shape or ray queries를 처리하는 callbacks을 가져야 한다. 한 query는 어떤 bodies가 point or ray같은 것과 교차하는지를 보기 위해 체크한다.

그 scene은 step이라고 불려지는 한 가지 특정한 함수를 가진다. 그 함수는 single delta time (dt)에 의해 그 scene이 흘러가게 한다. 이 step function은 적분으로 모든 오브젝트들을 시간에서 흐르게 한다. 그 적분 단계는 오브젝트들의 속도, 위치, 그리고 가속도를 사용하여 그것들의 다음 위치를 결정하기 위해 오브젝트들을 앞으로 움직인다.

그 step동안, 충돌이 탐지되고 그러고나서 해결된다. 종종 어떤 종류의 한 broadphase가 가능한 충돌을 탐지하기 위해 사용된다. 그리고 비싼 충돌 연산이 정말 필요할 때만 사용된다.

이러한 구성의 모든 것은 너의 물리 엔진의 상요자가 세 개의 주된 연산을 걱정하게 한다: bodies의 생성과 제거, 그리고 scene을 stepping. 나머지는 자동화되고, 물리 시스템의 내부사항에 내에서 다뤄진다.

마지막 중요한 isolated system은 broadphase일 것이다. 충돌 탐지에서 두 개의 중요한 단계들이 있다: broad and narrow phases. 그 narrow phase는 두 shapes가 교차하는지를 결정하는 것이다. 그 broad phase는 두 도형들이 가능하게 교착하는지를 결정한다. 그 broadphase는 교차 쿼리가 매우 빠르고 간단하게 되도록 구성되어야 한다. AABB가 완벽하게 충분할 것이다.

그 broadphase가 어떤 오브젝트가 아마 충돌할지를 고르기만 한다면, 그것은 그것들을 narrow phase에 보낸다. 그 narrow phase는 두 오브젝트들이 충돌할지 안할지를 결정하기 위해 좀 더 집중적인 연산을 수행한다. 이것에 대한 전반적인 점은 narrow phase가 사용되어야만 하는 횟수의 양을 줄이는 것이다. 왜냐하면 그것이 비싸기 때문이다.

일단 그 narrow phase가 충돌할 것이라고 발견하기만 한다면, 추옫ㄹ에 대한 정보가 모아지고, manifold라고 불려지는 작은 컨테이너테 위치된다. 왜 그것이 manifold라고 불려지는지 묻지마라. 왜냐하면 나도 모르고, 어느 느구도 모르는 것처럼 보인다. 그 manifold는 세 가지 중요한 정보를 포함한다:
  • 충돌 관통 깊이
  • 해결되어야 할 방향
  • contact points
정보의 이러한 것들이 penetration을 해결하기 위해 사용되는 공식에 채워지기 위해 사용된다. 그리고 단일의 미지수를 풀기위해 채워진다: resolution vector의 크기. 여기에 작은 그림이 있다:

이 충돌 정보를 구성했던 두 오브젝트에 대한 포인터 또는 handles를 저장하는것은 또한 유용하다. 이것은 어떤 유용한 함수들이 그 manifold object에 직접적으로 배치되게 한다 : solve and resolve. Solve는 충돌 정보 세 가지를 모으는 함수가 될 것이다. 만약 어떤 contact points가 발견되지 않는다면, 충돌은 없다. 만약 contact points가 발견된다면, 그러고나서 resolving은 두 오브젝트가 적분후에 교차하지 않도록 만들 resolution operation을 수행한다.

Velocity
복잡한 물리 조작이 오브젝트의 속도에 수행된다. 오브젝트들의 위치를 직접 조작하려 하는 것은 매우 어렵다. 왜냐하면 그것은 linear하지 않다는 문제를 제기하기 때문이다. 속도에 대한 미분된 position 방정식을 사용하여, 그 문제는 따라서 간단하게 된다. 대ㅜㅂ분, 우리는 velocity manipulation만을 다룰 것이다.

Impulse Resolution in 2D (No Rotation or Friction)
충돌을 해결하는 행동은 인터넷에서 잘 다뤄지지 않는 것이다. 어떤 흩어진 문서와 세부사항들이 있다, 비록 그 정보가 항상 찾기에 쉽지 않을지라도. 내가 아는 대부분의 것은 다른 사람과 이야기해서 이지만, 나는 대부분의 사람들이 그런 기회를 가지지 않을 것을 안다. 바라건데, 이 자료가 간단한 물리 엔진을 이해하고 구성하는 강한 자료를 제공하기르 ㄹ바란다.

코딩하기에 가장 어려운 부분은, 내 생각으로는 충돌 해결이다. 충돌 탐지와 broadphase에 대한 수 많은 정보들이 존재하고, 따라서 한 물리엔진의 이러한 부분을 만드는 것은 너무 어렵지 않다. 충돌 탐지에 대한 어떤 자료들은 Christer Ericson의 Real-Time Collision Detection과 Ian Millington의 Game Physics Engine Development이다. 나는 이 책 둘다 가지고 있다.

contact manifolds를 생성하고 그러한 manifolds를 해결하는 것은 대부분의 프로그래머들이 발목잡히는 것이다. 그래서 그것을 해결해보자.

contact resolution의 가장 좋은 유형은 impulse resolution이다. impulse resolution 뒤에 있는 아이디어는 너의 contact manifold를 취하고, 한 오브젝트의 현재 velocity에 더해지는데 사용될 단의 velocity vector에 대해 해결하는 것이다. 이것은 그것이 다른 오브젝트와 다음 프레임 동안 충돌하지 않게 만들기 위해서이다. impulse resolution과 시작하는 이유는 그것이 시작하기 쉽고 간단하다는 것이다. 좀 더 복잡하고 고급 기법들은 너에게 impulse resolution을 어쨋든 이해하는 것을 요구한다.

~~~

Penetration Resolution
부동 소수점 에러 때문에, energy가 항상 시스템으로부터 시간이 지남에 따라 잃어질 것이다. 그러하듯이, 오브젝트들은 쉬기 시작할 때, 그것들은 서로 중력에 의해 가라앉을 것이다. 어떻게 해결하는가? 그 해결책은 실제로 그 오브젝트들을 직접 움직여서 남은 penetration을 수동으로 다루는 것이다. 이것은 오브제그들이 서로 가라앉는 것을 방지할 것이다. 비록 어떤 에너지도 시스템에 더하지 않으면서.

관통을 해결하기 위해, 간단히 manifold normal의 반대 방향으로 각 오브젝트를 움직여라. 그러나 그렇게 하는 것에 대한 기술이 있다. 만약 너가 그 관통을 매 프레임마다 100% 해결한다면, 다른 오브젝트들 아래에 있는 오브젝트들은 내가 말한 naive penetration resolution scheme 때문에 난폭하게 jitter할 것이다. 이것을 해결하기 위해, 남은 penetration의 퍼센티지 만큼 해결하려고 해라, 아마도 20 ~ 80%.

추가적으로 너는 만약 impulse가 적용된 후에 관통 깊이가 어떤 constant arbitrary (but small) threshold보다 높다면 관통을 해결하길 원한다. 만약 그 관통이 이것 아래라면, 오브젝트를 움직이지 말아라.

penetration resolution의 이 방법은 linear projection이라고 불려진다. 여기에 C++ 코드 가 있다.

댓글 없음:

댓글 쓰기