Post Lists

2018년 10월 5일 금요일

17 Putting It All Together

17 Putting It All Together
우리는 어떠한 rigid body의 종류든 재현할 수 있고, 오브젝트들 사이의 충돌들을 탐지할 수 있고, 현실적으로 그러한 충돌들을 해결할 수 있는 완전한 물리엔진을 구성했다. 그것은 큰범위의 여러 게임들에 대해 물리를 작동시킬 수 있다. 이제, 몇 가지 paces를 통해 그것을 넣을 시간이다.

우리가 demonstration application을 통해 작업하기 전에, 우리가 어디에서 왔는지를 보고,물리엔진을 전체적으로 볼 가치가있다.

17.1 Overview Of The Engine
우리가 구성한 물리엔진의 4개의 다른 부분들을 갖는다:

  • force generators (and torque generators)는 게임의 현재 상태를 조사하고, 어떤 오브젝트에 무슨 힘이 적용될 필요가 있는지를 계산한다.
  • rigid-body simulator는 그러한 힘들에 대응하여, rigid bodies의 움직임을 처리한다.
  • collision detector는 빠르게, 오브젝트들 사이와, 한 오브젝트와 level의 움직일 수 없는 부분 사이의 충돌과 다른 contacts들을 찾는다. 그 collision detector는 collision resolver에 의해 사용될 contacts들의 한 집합을 만든다.
  • collision resolver는 contacts들의 한집합을 처리하고, 그것들의 효과를 정확히 묘사하기 위해 rigid bodies의 motion을 조절한다.
이러한 컴포넌트들 각각은 그것 자신의 세부사항과 복잡성을 가지지만, 우리는 그것들을 별개의 units으로 넓게 다룰 수 있다. 이전 컴포넌트들에서 사용되는 두 종류의 내부 데이터가 있다는 것에 유의해라:

  • 그 생성된 forces와 torques는 explicit data structure로 결코 나타내어지지 않는다. 그것들은 그것들이 계산되자마자 직접적으로 적절한 rigid body에 적용된다.
  • Contacts는 collision detector에 의해 생성되고, 함께 저장된다, 그룹으로서 collision resolver에 보내지기 전에.
게임에 있는 오브젝트들을 나타내기 위해, 우리는 세 종류의 데이터가 필요하다:
  • Rendering geometry and materials는 스크린에 있는 오브젝트를보여주기 위해 사용된다. 이것은 보통 물리엔진에 의해 모두 사용되는 것은 아니다, 비록 그것이 매우 간단한 오브젝트들에 대한 collision geometry의 위치를 가질 수 있을지라도.
  • Collision geometry는 한 오브젝트를 나타내는 모양의 간단하게 된 집합이다. 그것은 충돌 탐지를 가속하기 위해서 사용된다. 몇 엔진에서, collision geometry는 polygonal mesh로 구성된다, rendering geometry 처럼. 다른 엔진들에서, 오브젝트들은 타원체와 박스들 같은 primitive shapes의 집합으로 구성된다. 둘 다의 경우에, comprehensive collision detection system이 일반적으로 collision geometry의 한 레벨 이상이 필요할 것이다: 가장 낮은 level은 한 개 또는 그 이상의 bounding volumes에서 포함될 것이다.
  • Rigid-body data는 그 오브젝트의 물리적 특성에 대한 정보를 포함한다. 그것은 position and velocity뿐만 아니라 mass and inertia tensor같은 것들을 포함한다. 우리의 엔진에서, 이것의 대부분은 rigid body class에 캡슐화되어 있다. 게다가, 우리는 표면들의 쌍 사이의 마찰과 그것들의 restitution같은 contact data에 대한 접근권을 가질 필요가 있다.
엔진의 4개의 부분과 두 개의 통신의 내부선이 있고, 이러한 데이터의 세 종류는 물리 시뮬레이션을 제공하기 위해 함께 작동한다. 그림 17.1은 데이터가 그 시스템을 통해 어떻게 지나가는지를 보여준다.

이것은 대부분의 물리엔진의 기본 설계이다, 비록 몇 가지 변형들이 있을지라도.특히, 파이프라인에 부가적인 컴포넌트들을 추가하는 것이 가능하다, cotacts들의 sets을 연결되지 않은 batches로 분할하는 batch processing lagorithm 같은. 몇 엔진들은 또한 파이프라인의 끝에 rigid-body update의 또 다른 단계를 가진다, 특히 그 collision resolution system의 결과가 적용할 forces의 set이라면.

그 전체 물리 파이프라인은 일반적으로 게임 loop에서 단일 호출내에 포함된다. 우리는 쉽게 그 물리 시뮬레이션을 작동시키는데 필요한 모든 것을 추적하는 black-box physics system을 만들 수 있다. 이 책에서, 실제 게임 개발에서 뿐만 아니라, 나는 이것을 하는 것을 피했다. 실제 게임 개발에서, 물리는 그것 자신을 위해서 일어나지 않는다; 그것은게임의 일부이다, 물리 시스템이 필요한 데이터는 어느 곳에서나 필요한 데이터와 겹친다. black-box system은 쉽게 일을 복제할 수 있고, 예를들어 한 오브젝트의 위치가 모두 복사본이 동기화되도록하는 악몽을 유발할 수가 있다.

실제 게임에서, 다른 오브젝트들은 또한 다른 부가적인 데이터가 필요하다. 몇 오브젝트들은 active일지도 모르고, 그래서 AI에 대한 데이터를 요구할지도 모른다. 다른 오브젝트들은 플레이어에 의해 통제될지도 모르고, 동기화를 위한 네트워크 데이터를 요구할지도 모른다. 어떤 오브젝트들은 hit points or value같은 게임 특정한 데이터를 요구할 수 있다. 그러한 복잡성은 물리 데이터가 정확히 초기화되고, 현실적인 오브젝트를 나타내도록 보장하는 것을 어렵게 만든다 (그 inertia tensor는 악명높게 틀리기 쉽다).

새로운 오브젝트들을 정확하 물리로 설정하는 것은 어려울 수 있다. 나의경험에서, 오브젝트들의 물리가 상호작용하여 검증될 수 있는 level-design process의 일부로서 한 간단한 환경을 갖는 것은 매우 중요하다. 그 방식으로, 너가 개발할 때, 너는 그 오브젝트가 그것의 환경에서 제대로 되고 있는지, 그리고 어떠한 중요한 데이터가 초기화되지 않았는지를 확신할 수 있다.

17.2 Using the Physics Engine
우리는 이제 우리의 물리엔진으로 원하는 어떤 것이든 거의 할 수 있다. 이 챕터에서, 나는 너에게 물리에 대한 가장 인기있는 프로그램들 중 몇 가지를 줄 것이다: ragdolls, breakable objects, 그리고 movie-style explosions. 그 과정에서, 우리는 몇 가지 추가적인 기법, force generators, 그리고 그 엔진을 설정하는 방법들을 볼 것이다.

그러나, 이러한 프로그램들에 대한 한 가지 중요한 caveat가 있다. 만약 너가 단일의 목적으로 너의 엔진을 구성한다면 (off-road trucks을 작동시키거나, 예를들어, procedural animation system의 일부로서), 그러면 직접적으로 거기에 도달하는 더 빠른 방법들이 있을지도 모른다.

나는 이러한 효과들에 힘을 부여하기 위해 우리의 generic engine을 사용하는 것에 집중할 것이다. 만약 너가 필요한 모든 것이 single-purpose physics systme이라면, 우리가 필요하지 않은 우리의 코드에 넣은 것들이 있을 것이다. 예를들어, 일반적으로 땅을 떠나지 않는 high-spec racing cars에대해, 너는 모든 rigid-body physics를 생략하고, 그것들의 suspension이 어떻게 움직이고 그것이 어떻게 핸들링하는지에 대한 특별케이스 스프링 코드를 구성할 수 있다.

우리의 접근법은 그 오브젝트의 물리적 근사를 구성하고, 그것을 재현하는 것이다. 가끔씩, 더 좋은 접근법은 요구되는 행동을 처리하고, 명백히 그것을 프로그래밍 한다. 일반 목적 vs special-case dillema는 점점더 고려할 가치가 없게 된다. 현대 게임들은 일반적으로 한 번에 여러가지 효과들을 필요료 한다: 한 운전 게임은 cones and fences를 모델링할 것인데, 그것들이 부서지고 현실적으로 흩뿌려지는 것을 허용한다. 다른 종류의 물리적 행동들이 상호작용할 필요가 있는 상황에서, 완전한 물리엔진을 대체할 것이 없다.

17.2.1 RagDolls
Ragdolls는 현재 인기있는 물리 프로그램이다: 던져질 수 있고, 물리를 사용해서 그것들 자신만의 현실적인 애니메이션을 생성하는 캐릭터이다. 그것들은 procedurla animation으로 가는 더 넓은 움직임의 일부이다: keyframes를 생성하는 예술가가 필요하지 않는 애니메이션.

ragdoll은 일련의 연결된 rigid bodies로 구성되어 있다 (그림 17.2). 이러한 rigid bodies는 "bones"라고 불려진다 (그것들은 대충 skeletal animation에서 사용되는 뼈들과 부합한다, 비록 다른 많은 ragdoll bones와 rendering bones가 있을지라도). 그것들의 가장 복잡한 것에서, ragdolls는 수십개의 뼈를 포함할 수 있다, 유연한 척추와 꼬리를 얻는데 필수적인.

그 뼈들은 joints로 함께 연결되어 있다: 우리가 chapter 7에서 보았떤 것들과 같은 constraints이다. 마지막으로, 어떤 게임에서, force generators가 그 joints에 추가된다. 캐릭터에 비행중에 움직이는 방식을 추가하기 위해서: 그것들의 얼굴을 보호하고, 그것들의 손이 떨어지지 않게 보조하려고 한다.

CD에서 그 ragdoll demo은 그 force generators를 생략했지만, 그 본을 함께 유지하기 위한 joints를 포함한다.

그 constraints들은 contacts로서 구현된다. 그 일반적인 contact generator외에도, joints들의 한 리스트가 고려되고, contacts들이 그것들을 유지하기 위해 생성된다. 그림 17.3은 한 그러한 joint의 세부사항을 보여준다. 그 contact가 두 개의 점들을 함께 유지하는 것에 주목해라. 그 contact는 항상 이러한 두 점들사이에 있을 것이고, 그것들이 정렬되게 보장한다.

그 contact가 정렬에서 벗어나는것을 막기위해, joint에 있는 마찰은 효과적으로 무한이 되어야 한다. 그 joint가 정렬에서 나가지 않도록 하기 위해서, 그 restitution은 0이된다.

코드에서, 우리는 한 joint에 대한 정보를 유지하는 다음의 구조를 갖는다:


이 클래스 내에서, 그 joint의 현재 설정을 기반으로 contacts를 생성하는 checkJoint method가 있다. 이 방식으로, 그것은 collision detector처럼 행동한다: rigid bodies의 상태를 보고, 그에 따라 contacts를 생성한다.

데모에서, joints들을 물리 업데이트동안 순서대로 고려된다:

작동될 때, 이것은 빠르고 효과적인 ragdoll model이다. 그러나, 그것은 가장 안정된 메소드는 아니다. 매우 큰 ragdolls에 대해, 많은 interpenetration resolution iterations가 그것들의 올바른 위치에서 돌아다니지 않도록 하기 위해 필요하다.

{
쉬운 BigBallistic 데모부터 먼저 구현해 보았다. 아직 코드에 고칠점들이 많이 있지만, 일단 작동시켰다는 점에서 이 GIF를 올리고 싶다. 이론을 더 이해하고, 코드를 더 이해하고, 코드를 개선시켜서 완전하게 만들어야 한다.


}


More Complex Joints
ragdoll demo의 접근법은 유용한 joints을 얻을만큼 가능한한 간단하다. Joints들은 물리엔진의 공통된 특징이고, 그래서 그것들은 상당히 복잡할 수 있다. 특히, joints들은 다른 것을기준으로 움직이기 위해 한 오브젝트의 자유를 제거하기 위해서 사용된다.

우리가 사용한 그 joints들은 ("ball-joints"라고 불려지는) 다른 것과 관련하여 선형으로 움직이기 위해 한 오브젝트의 자유를 가져간다. 훨씬 더 움직임을 제한하는 joints들도 또한 있다 : 한 오브젝트의 다른 것과 관련하여 회전을 제한하는 hinges와 한 방향으로만 상대적인 움직임을 허용하는 piston joints.

우리가 만든 엔진에서 이러한 좀 더 유연한 joints들을 구현하는 것은 꽤 솔직히 말해서 편리하지 않다. 내가 여기에서 한 것은, contacts의 관점에서 joints를 나타내려고 한 것인데, 이것은 ball-joints에 대해서 작동하지만, 다른 종류의 joints에 대해서는 매우 어렵다.

이러한 종류의 엔진을 위해 joints를 만들 때, 나는 대략 contacts들을 위해 사용되는 같은 알고리즘을 따르지만 그 필요한 adjustments를 결정하기 위해 다른 테스트들의집합을 사용했다. 예를들어, hinge joint는 그 두 개의 오브젝트들이 얼마나 twisted 되어야 하는지를 체크할 필요가 있고, 그것들을 정렬되게 하기 위해 interpenetration같은 resolution을 구현해야 한다.

contact의 simultaneous resolution을 가진 Force-based engines는 보통 최소한의 추가적인 구현의 노력으로 다양한 범위의 joints를 만드는 것을 쉽게 하는 수학적 구조를 사용한다. 다음 챕터에서, 우리는 이것을 지원하는 알고리즘들을 볼 것이다. 만약 너가 많은 joints들을사용하려 하고, 이 섹션에서 simple contact-based joints들을사용하기 보다 더 광범위 한 것이 필요하다면, bullet을 깨물고, 너의 contact resolution scheme을 업그레이드 시킬 가치가 있을지도 모른다. 그러나, 효율성, 구현의 용이성, 그리고 프로그래머의 정신을 위해서, 간단한 접근법을시도하는게 가치가 있을 것이다.

17.2.2 Fracture Physics
만약 ragdoll physics가 현재의 인기있는 physics 프로그램이라면, 그러면 fracture physics는 그리 멀리 있지 않다. 특히 shooters에서, 플레이어들은 현실적인 방식으로 오브젝트들이 분해되는 것을 보길 원한다: 나무는 쪼개져야 하고, 유리는 박살나야하고, 떨어지는 상자들은 그것들의 내용물을 보이기위해 금가야 한다.

Fracture physics는 너가 원하는 만큼 간단하거나 복잡할 수 있다. 초기 구현은 두 개의 rigid bodies의 집합을 사용했다: 그 전체 오브젝트에 대해서 하나, 그리고 그것의 컴포넌트들에 대해서 다른 하나. 전체 rigid body는 breaking strain value를 가지고 있다: 파괴되기 전에 그것이 받을 수 있는 최대한도의 impulse이다. resolution algorithm의 velocity phase동안, 그 오브젝트에 적용되는 impulse는 그것의 breaking strain과 비교된다. 만약 그 impulse가 너무 크다면, 그 전체 rigid body는 그것의 component objects로 대체된다.

이것은 매우 빠르고, 효율적이고, 구현하기 쉬운 fracture physics이다. 불행하게도, 두 개의 동일한 오브젝트들은 항상 정확히 같은 방식으로 파괴될 것이고, 그 파괴의 패턴은 충격의 위치와 어떤 고나련도 없을 것이다. 그림 17.4는 유리창에서 이 문제를 보여준다.

이것은 한 오브젝트에 대해 몇 가지 가능한 deceompositions을 사용하고, fracture가 시작되었을 때 어떤 것을 사용할지를 결정하여 어느정도 완화될 수 있다. 그러나 플레이어들은 패턴을 찾는데 잘하고, 대부분의 개발자들은 좀 더 유연한 접근법을 원한다.

좀 더 복잡한 fractur physics는 breaking strains의 같은 기본 원리를 사용하지만, 두 개의 좀 더 복잡한 알고리즘들을 추가한다. 그 첫 번째는 날아가고 있는 fractured object의 컴포넌트들을 구성하는 geometric algorithm이다. 그 decomposition method는 material의 타입에 의존한다.

나무를 decomposing하는 것은 길고, 쪼개진 컴포넌트가 필요하다; 유리들은 panes로 쪼지고; safety glass는 작은 nuts로 박살난다; 등등. 일반적으로 이것은 그 오브젝트를 다른 크기의 tetrahedron(4면체)로 분해하고, 이러한 것들의 그룹들을 함께 유지하거나, fracture patterns의 한 집합과 컴포넌트들을 분리시키는 3D boolean 연산들을 사용하여 성취된다. 이 분해의 세부사항은 매우 geometric이고, 이 책을 넘어서는 알고리즘에 의존한다. Schneider와 Ebery [2002] 책을 geometry를 조작하는데 광범위한 알고리즘들을 가지고 있다.

그 두 번째 좀 더 복잡ㅎ나 알고리즘은 정확한 물리 특징을 컴포넌트 오브젝트에게 할당하는 것이다. 특히, 일반적인 fractured shape에 대해 올바른 inertia tensor를 할당하는 것은 사소하지 않은 과정이다. Appendix A는 다양한 일반적인 오브젝트들의 inertia tensor를 계산하는 것의 공식과 알고리즘을 준다. 그러나, 일반적인 모양에 대해, 이러한 것들은 복잡하고, 비효율적일 수 있다. 대부분의 개발자들은 simplification과 간단한 inertia tensors를 가진 geometry가 있는 shattered pieces로 근사한다 : box들은 firm favorite이다.

그림 17.5는 CD에서 fracture demo를 보여준다. 그것은 single large block를 포함하는데, 상대적으로 빽빽하고, 콘트리트 같은 잘 부러지는 재료로 구성되어있다. 너는 그 블럭에 한 공을 조준해서 쏠 수 있다. 그 블럭은 충격에 박살날 것이고, 그 공이 어디에 부딪혔는지에 의존한다. 그 decomposition scheme은 그 블럭은 8개의 컴포넌트들로 분할하고, 그것을 각 방향으로 나눈다. 그 충돌점은 두 충돌의 중심으로서 사용되고, 그 다른 방향은 절반으로 분할된다 ,그림 17.6에서 보여지듯이. 그 결과를 좀 더 현실적으로 만들기 위해서, 그 쪼개지는 것은 랜덤하게 각이 정해진다.

그 geometric division algorithm은 이것처럼 보인다:

이것은 충돌이 block의 YZ 평면에서 발생할 것이라고 가정한다 (그것은 우리의 데모에서 그렇게 발생해야만 한다). 좀 더 완전한 코드는 다른 가능한 충돌 평면에 대해 유사한 알고리즘을 가질 것이다.

최종 pieces는 대충 정사각형이기 때문에, 그것들은 그것들의 inertia tensors를 계싼하기 위해 rectangular blocks처럼 다루어진다. 이것은 간단히 다음처럼 된다.

general-purpose fracture physics system을 만드는 것은 물리 지식 보다 더 많은 geometric processing을 포함한다. 몇 개발자들은 이 루트를 거쳤고, 유사한 기법들을 가진 몇 가지 middleware vendors들이 있다. 그러나 모든 유용한 시나리오들을 잡으려는 것은 적당히 긴 task이다  - 확실히 우리가 만든 그 contact resolution 또는 rigid body algorithms이 긴 만큼

17.2.3 Explosive Physics
폭발은 게임의 가장 초기 시절부터 있어왔고, 첫 번째 물리엔진 프로그램이였다 : smoke와 debris를 만드는 파티클 엔진. 폭발은 적절한 물리와 함꼐 훨씬 더 재미있따; level 주위로 흩뿌려지는 잔해를 보는 것에 대해 어떤 만족감이 있다.

폭발은 custom force generator로 만들기 쉽다. 우리는 간단히 blast point 근처에 있는 오브젝트들에게 한 force를 전하는 force generator를 만들 수 있다. 이것은 연쇄되는 오브젝트들에게 보낼것이지만, 궁극적으로 보기에는 재미없을 것이다. 그것은 두 가지 문제를 가지고 있다. 첫 째로, 그 폭발효과는 꽤 단조롭다 : 오브젝트들은 그냥 날아간다. 둘 째로, forces를 적용하는 것은 오브젝트들이 회전하게끔 하지 않는다.

movie-quality 폭발효과는 세 개의 컴포넌트를 갖고 있다 : 초기 implosion, expanding concussion wave를 가진 전방위 explosion, convection chimney. 이러한 컴포넌트들 각각은 다소 다른 행동을 갖는다.

Implosion
폭발이 처음 발생할 때, 폭발안의 열기는 폭발점 주위에서 한 ball에서 산소를 흡수하고, 그 공기를 이온화할 수 있다 (이것이 섬광이 발생하는 것이다). 압력에서 갑작스럽고 극적인 하락이 발생하고, 거의 공기가 그 틈으로 질주하게 된다. 이것이 implosion stage이고, 그것은 lightning strike가 발생하는 것과 같은 프로세스이다.

이 방식으로 공격을 입히는 "thermobaric(엽압력탄) weapons"라고 불리는 군사 기술이 있다. 이것은 빌딩을 파괴할 수있고 생명체를 황폐화시킬 수 있는 거대한 압력변화와 강력한 compression wave (다음 섹션 참고)을 발생시키기 위해 높은 온도를 사용한다.

적당한 크기의 실제 폭발에서, 이 효과는 간신히 눈치채지고, 심지어 완전히 concussion phase에서는 잃어질 수 있다. 그러나 게임과 영화에 대해, 그것은 좋아보이고, 폭발에게 몇가지 부가된 power를 준다. 특히 geometry-stretching graphical effect과 관련될 때, 더 긴 concussion은 폭발에 tension을 추가할 수 있고, 심지어 어떤 종류의 alien technology를 제안할 수 있다.

그 force generator의 implosion stage는 어떤 threshold radius내에 있는 모든 오브젝트들에게 한 force를 적용한다, 폭발점의 방향으로. 우리는 그 폭발의 모든 세 단계를 한 force generator에 넣을 것이다. 지금까지 그것은 이것 처럼 보인다:

그 implosion은 오직 linear force만을 부과할 수 있다. 그것이 너무 짧기 때문에, 우리는 오브젝트가 회전하는 것을 설정할 필요가 없다.

Concussion Wave
그 concussion wave (또한 "shockwave"라고 불려지는)는 초기 implosion에 의해 촉진된다: 공기가 진공안으로 들어가고, 확장하는 wavefront를 만들어낸다. 이것은 폭발지점 근처에서 탄약과 군수품연료가 그 무기로부터 팽창하여 결합될지도 모른다. 매우 높은 온도의 장치에 대해, 그 wavefront는 불타는 공기를 구성할지도 모른다, "fireball"이라고 알려진 (원자 장치에서의 특징인).

그 concussion wave는 오브젝트들을 폭발 밖으로 던진다. 영화와 게임에서, 공중으로 차들이 날아가고, 캐릭터들이 넘어지는 것에 책임이 있다.

concussion wave의 특징은 그것의 전파이다. 그것은 폭발지점으로 부터 펼쳐지고, 그것이 갈 수록 더 약해진다. water wave의 바깥 edge에 있는 surfer처럼, 가벼운 오브젝트들은 그 concussion wave의 outside edge를 탈 수 있고, 매우 높은 속도로 가속할 수 있다. 그 wave를 잡지 못한 surfer처럼, 대부분의 오브젝트들은 wave boundary에서 초기 boost를 받을 것이고, 그러고나서 wavefront안에서 있을 때 처럼 정상적으로 행동할 것이다.

우리는 blast point로부터 팽창하는 interval 내에 있는 오브젝트들에 forces를 적용하여 우리의 force generator에서 이것을 구현할 수 있다. 그 interval은 충분히 넓어서, 어떠한 오브젝트들도 놓쳐지지 않는다. 그것의 너비는 프레임율과 wavefront의 속도에 의존한다, 그 공식에 따라서



여기에서 s는 wavefront의 속도이고, w는 interval의 width이고, fps는 초당 프레임의 개수이다. 다시 말해서, w는 한 프레임에 그 wave가 이동하는 거리이다. 실제로, 이 peak의 어떤 면에 있는 오브젝트들은 또한 어떤 force를 얻어야 하지만, 더 적은 정도로 얻는다. 그 force equation은



나에게 유용하다고 입증됐다. 그것에서 st는 wavefront의 뒤에 있는 position이다 (즉, 속도 * 시간), k는 파장의 양 끝의 tail-off의 width이고, d는 blast의 중심으로부터 한 오브젝트의 거리이고, f_a는 적용되는 힘이고, f_B는 그 peak blast force이고, 우리는 이것을 한 순간에 계산할 것이다. 그 방정식은 그 파장의 양 끝에서 force의 linear fall-off를 제공한다. 그 force cross section은 그림 17.7에서 보여진다. 그 force가 항상 blast의 중심으로부터 바깥으로 작용한다는 것을 주목해라.

우리는 이 방정식에 대해 peak force를 계산할 필요가 있다. 한 오브젝트에 적용되는 그 force는 그것의 aerodynamic drag와 (compression wave가 우선적으로 공기를 움직이는 효과이기 때문에) 그것의 현재 속도 둘 다에 의존한다. 우리는 가난히 chapter 11의 aerodynamic effects를 사용해서 이것을 할 수 있지만, 만약 너가 그것을 이미 사용하고 있지 않다면, 그것은 아마도 지나친 것이다.

우리는 오브젝트의 속도와 wavefront사이의 차이에 의존하는 한 force를 적용하여 force effect를 근사할 수 있다. 폭발하는 오브젝트들이 움직여졌을 때 회전하도록 하기 위해서, 우리는 그 force를 센터 바깥에서 적용한다. 이것은 그 force generator가 만들어 질 때 각 오브젝트에 대해 random한 off-center point를 선택하는 것만큼 간단하다. 그 같은 점은 프레임마다 오브젝트가 공중에서 jiggling하는 것처럼 보이는 것을 방지하기 위해 사용되어야 한다. 그렇지 않는다면, 오브젝트들은 폭발의 영향 하에서 더 빠르게 회전할 수 있다. 그리고 이상하게 보인다.

concussion wave를 구현하여, 그 explosion force generator는 이것처럼 보인다:

Convection Chimney
그 폭발의 마지막 부분은 한 실제 폭발의 또 다른 할리우드 과장이다. 초기의 폭발로부터 압력효과 뿐만 아니라, 발생된 열은 blast point 위로 convection current(대류)를 설정할 것이다. 대부분의 전통 무기에서, 이것은 경미한 효과이고, 매우 눈치챌만하지 않다. 그러ㅏㄴ, atomic and nuclear weapons에서 중요하고 iconic하다; 그 버섯 구름은 폭발 위험성의 강한 indicator가 되었다. 그것이 드물게 사용되어야 하지만 (한 수류탄이 터지난 뒤의 큰 버섯 구름은 이상해 보인다), 그것은 우수한 무리를 나타네느데 훌륭한 방법이 될 수 있다.

Convection chimney는 폭발 후에 오랜 시간 동안 위로 가는 힘의 아주 작은 양을 제공한다. 땅 위의 가장 가벼운 오브젝트들만을 드는 것은 충분하지 않다. 가벼운 오브젝트들은 concussion wave 이후에 blast point주위에 있지 않을 가능성이 높기 때문에, 개발자들은 일반적으로 그 convection에 반응만하는 추가 파티클들을 도입한다. 이러한 파티클들은 위로 올려질 만큼 충분히 가볍다.

그 convection chimney는 concussion wave와 비슷한 방정식을 갖는다. 그러나 그것은 바깥으로 움직이지 않는다. 그 linear fall-off는 잘 작동한다:



여기에서 w는 chimeny의 width이고, h는 chimney의 최대 높이이고, d_xz는 blast center로부터의 오브젝트 거리인데, XZ plane에서만이다 (왜냐하면 우리는 그 굴뚝이 cylinder shape가 되길 원하기 때문이다), 그리그 d_y는 그 blast point 위에 있는 오브젝트의 높이이다.

그 force는 blast center로부터 직선으로 또 다시 적용되어야 한다. 만약 우리가 그 force를 그냥 윗 방향으로 적용한다면, 그러면 오브젝트들은 굴뚝 위로 상승할 것이고, 그 꼭대기에서 까닥거릴 것이다. 만약 그 힘이 기울어졌다면, 그 특징적인 mushroom cloud 모양이 형성된다. 그 peak force는 concussion wave와 같은 방식으로 계산된다: 그것은 또다른 공기를 움직이는 현상이다. 이 효과를 만들어내는 코드는 이것처럼 보인다:

모든 합쳐진 폭발은 꽤 보기 좋다. 그 explosion demo는 작동준이 세 개의 컴포넌트들을 보여준다 (그림 17.8). 어떠한 조명이나 불 파티클 효과가 없는데, 그것들은 보통 실제 게임 폭발에서 사용될 것이다 (그 둘 중 어떠한 것도 일반적으로 폭발의 물리학으로 주도되지 않는다). 거대한 폭발에 대해, 깔끔한 효과는 오브젝트에 대한 불을 설정하는 것이다 (그 오브젝트의 표면에 불 파티클을 더하여), 그 오브젝트들이 처음에 concussion wave의 범위에 들어갔을 때. 이것은 consuming fireball의 효과를 준다.

17.3 Limitations of The Engine
우리는 쓸만한 물리엔진을 ㄱ성했고, 다른 게임 상황에 있는 paces들을 통해 그것을 넣는 재미를 보았다. 이것은 우리가 상세한 코드로 들어간 만큼 길었다. 이 책의 나머지는 다른 이슈와 접근법에서 좀 더 일반적인 방식을 들여다 본다.

내가 처음에 말했듯이, 우리가 취한 접근법은 좋은 것이다, 구현의 용이성과 시뮬레이션 파워가 좋게 섞여서. 그러나, 궁극적으로 어떤 접근법이든 한계를 가진다. 내가 우리가 진행함에 따라 그 한계를 명확하게 노력했을지라도, 다른 접근법의 이익을 보기전에, 우리의 엔진이 다루기 어려운 그러한 이슈들의 개관을 보는 것은 가치가 있다.

17.3.1 Stacks
오브젝트들의 Large stacks들은 우리의 엔진에서 너무 안정되지 않을지도 모른다. 물론, 우리는 그 stack up을 설정하고, 그것이 잠에 들게 할 수 있고, 두드려 졌을 때 넘어지게 할 수 있지만, 작은 touch는 그것이 jiggling하도록 할 가능성이 높다. 최악에서는, 그것이 그 stack의 꼭대기에 있는 블럭들이 시각적으로 움직이게 하고, edge밖으로 진동하게끔 할 수 있다.

이것은 iterative penetration resolution algorithm에 의해 발생한다. 그 알고리즘은 완전히 그 resolution을 해결한 후의 오브젝트들을 위치시키지 않는다. 한 오브젝트에 대해 (또는 작은 개수의 stacked objects) 이것은 문제가 아니다. large stacks에 대해, 그 에러들은 그것들이 매우 눈치채어질 수 있을 때 까지 증가할 수 있다.

오브젝트들을 sleep에 넣는 것의 신중한 사용은, stacks들이 안정적으로 보이기 위해 만들어질 수 있다는 것을 의미한다. 만약 너가 날려지는 벽이 필요하다면, 이것은 좋은 전략이고, 그 엔진의 한계를 보여주지 않을 것이다.

17.3.2 Reaction Force Friction
우리가 지난 챕터에서 보았듯이, reaction force friction은 한 contact가 resolved될 때 생기지만, 한 contact가 다른 resolution의 부작용으로서 움직여질 때는 그렇지 않다. 이것은 다른 것에 기대고 있는 한 움직일 수 오브젝트가 제자리에 있는 것을 어렵게 만든다. 그 오브젝트들은 서로에게 미끄러지는 것처럼 보인다, 부과된 마찰에 상관없이. 희망되어질 수 있는 가장 좋은 것은 그 sleep system이 그것들이 미끄러지는 것을 멈췩 위해 들어가는 것이다.

이것은 interpenetration resolution algorithm의 또 다른 부작요이다: 그것은 한 접촉의 friction을 신경쓰지 않는다. 다른 것의 penetration resolution을 고려할 때.

17.3.3 Joint Assemblies
stacks이 불안정하게 되도록 하는 그 같은 축적되는 에러들은 또한 rigid bodies의 긴 strings이 joints로 연결될 때, 눈에 띌만한 artifacts를 이끌 수 있다. 프로그램으로 완전한 범위의 joints를 만드는 것 외에도, 우리의 엔진은 각 joint를 연속으로 고려한다. 한 연쇄의 끝에 있는 joints들은 극적으로 다른 것의 adjustments에 의해 영향받을 수 있다.

이것은 몇 가지 joint의 약한 stretching만큼 온화할 수 있다, processing에서 slow down을 통해 (모든 이용 가능한 iterations가 다 써버렸던 processing), 가장 극한의 재앙적인 failuer에서는 직동하게 된다.

Iterative resolution은 rigid bodies의 매우 constrained assemblies에 대해 최상의 옵션은 아니다 (비록 그것이 우리의 ragdoll같은 적당한 grouping을 처리할 수 있을지라도): 만약 이것이 너의 주요 프로그램이라면, simultaneous solver로 가는 것이 최상이다.

17.3.4 Stiff Springs
마지막으로, 우리는 책의 두 번째 파트의 bugbear에 도달했따. Stiff springs는 우리의 full rigid-body engine에 대해 particle engine에 대해 그랬던 것처럼 한 문제이다. 똑같이 같은 이유로. faked force generators를 사용하는 것이 가능하지만, chapter 6에서 했던 것 처럼, 그 문제는 완전히 해결될 수 없다.

17.4 Summary
거의 하나의 게임 물리 엔진으로 처리될 수 있는 어떤 것은 우리가 이 책에서 구성한 물리 엔진으로 처리 될 수 있다. 우리가 이 챕터에서 보았듯이, 게임에서 물리를 위해 인기있는 프로그램을 작동시키기 위해 그 엔진이 사용될 수 있다.

그러나 어떠한 물리엔진도 완벽하지 않다. 우리는 매우 빠른 시스템을 구성했지만, 어떤 정확성을 희생했다, 특히 contacts들이 resolved되는 방법에 대해서.

이 책의 마지막 챕터에서, 우리는 물리 엔진을 구성하는 것을 접근하는 다른 방식들을 볼 것이다. 너는 이러한 것들을 너의 두 번째 물리 엔진을 만드는 것에 대한 영감으로서 사용할 수 있고, 우리가 구성한 엔진을 추가 특징으로 확장할 수 있다.

























댓글 없음:

댓글 쓰기