- length units을 변경하기위해서는 b2_lengthUnitsPerMeter를 수정해야한다. b2_user_settings.h에 있는 `B2_USER_SETTING`를 통해 병합충돌을 피할 수 있다. ([b2_settings.h](https://box2d.org/documentation/b2__settings_8h.html))
@@ -614,13 +697,13 @@ if (state1[0] == b2_removeState)
}
```
### **Distance**
### 4.3.3. **Distance**
- b2Distance 함수는 두 shape 사이의 거리를 계산하는데 사용할 수 있다.
- distance function은 [b2DistanceProxy](https://box2d.org/documentation/structb2_distance_proxy.html)로 변환하려면 두 shape 모두 필요하다.
- 반복호출에 대해 distance function을 warm start하는데 사용되는 일부 캐싱도 있다.
### **Time of impact**
### 4.3.4. **Time of impact**
- 만일 두 shape가 빠르게 움직이는 경우 단일 time step에서 서로를 터널링할 수 있다.
- b2TimeOfImpact 함수는 두 개의 움직이는 shape가 충돌하는 시간을 결정하는 데 사용된다.
...
...
@@ -641,13 +724,651 @@ if (state1[0] == b2_removeState)
- 만일 고정 회전(fixed rotations)을 사용하면, shape cast를 수행할 수 있다.
- 이 경우, the time of impact function은 모든 충돌을 놓치지 않는다.
## **Dynamic Tree**
## 4.4. **Dynamic Tree**
-
-[b2DynamicTree](https://box2d.org/documentation/classb2_dynamic_tree.html)는 많은 shape를 효율적으로 구성하는데 사용된다.
## **Broad-phase**
- 이 클래서는 어떤 shape인지 모르지만, 사용자 데이터 포인터가 있는 AABBs(axis-aligned bounding boxes)에서 작동한다.
# links
- dynamic tree는 계층적 AABB 트리이다.
- 트리의 각 내부 노드에는 두개의 자식을 가진다.
- 리프노드는 단일 사용자 AABB(single user AABB)이다.
- 트리는 퇴화 입력(degenerate input)의 경우에도 균형을 유지하기 위해 회전을 사용한다.
- 트리 구조는 효율적인 ray casts 그리고 영역 쿼리를 허용한다.
- 예를 들어, scene에 여러 shape가 있을 수 있다. 여기서 ray casst를 수행하려면, brute force 방법으로 각 shape에 대해 ray cast 하는 방법을 사용할 수 있다.
- 이런 방법은 비효율적이다. (shape가 서로 떨어져 있을 경우)
- 그러므로 dynamic tree를 유지하고, 이 tree에 대해 raycast를 수행하여 많은 개수의 shape를 스킵할 수 있다.
- region query: tree를 사용하여 쿼리 AABB와 겹치는 모든 리프 AABB를 찾음.
- 많은 shape를 스킵할 수 있기 때문에 빠르다.
- 일반적으로 이 트리를 직접 사용하지 않는다.
- b2World 클래스를 사용하여 레이 캐스트 및 지역 쿼리를 수행한다.
## 4.5. **Broad-phase**
- 물리 단계에서 충돌처리는 narrow-phase와 broad-phase로 나눌 수 있다.
- narrow-phase: shape 쌍에서 접점을 계산
- N개의 shape: N\*N/2 개의 쌍에 대해 narrow-phase를 수행해야한다.
- b2BroadPhase 클래스는 이러한 쌍을 관리하기 위해 dynamic tree를 사용하여 부하를 줄인다.
- 이것은 narrow-phase 호출의 수를 크게 줄여준다.
- broad-phase: 일반적으로 직접 상호작용하지 않는다.(내부적으로 box2D가 생성하고 관리)
- b2BroadPhase는 Box2D의 시뮬레이션 루프에 맞게 설계되었다.
# 5. **Dynamics Module**
- 다이나믹 모듈은 Box2D의 가장 복잡한 부분이다.
- 대부분 사용자가 상호작용하는 모듈.
- Common과 Collision 모듈 위에 있는 모듈
- 아래와 같은 클래스를 가지고 있다.
- fixture
- rigid body
- contact
- joint
- world
- listener
- 클래스 사이에 많은 종속성이 있다. (다른 클래스를 참조)
## 5.1. **Bodies**
- position 과 velocity를 가지고 있다.
- forces, torques, impulses (힘, 토크, 충격)을 bodies에 적용할 수 있다.
- Body의 종류: static, kinematic, dynamic
- body는 fixtures(shapes)의 척추
- bodies는 fixture를 운반하면서 world에서 움직인다.
- Body는 항상 강체이다.
- 즉, 동일한 강체에 부착된 fixtures는 서로에 대해 상대적으로 움직이지 않고, 서로 충돌하지 않는다.
- fixtures에는 collision geometry 와 밀도(density)가 있다.
- 일반적으로 body는 fixtures에서 mass 속성을 얻는다.
- 그러나 body를 만든 후 mass 속성을 override할 수 있다.
- 일반적으로 생성한 모든 bodies에 대해 pointers을 유지한다.
- 그러므로 body position을 쿼리하여 그래픽 개체의 위치를 업데이트할 수 있다.
- 또한 포인터에 대한 작업이 완료되면 파괴할 수 있다.
### 5.1.1. **b2_staticBody**
- 시뮬레이션에서 움직이지 않음
- 무한한 mass를 가진것 처럼 동작
- mass와 inverse mass값 == 0
- 사용자가 수동적으로 이동 가능
- 속도 == 0
- 다른 static, kinematic body와 충돌하지 않는다.
### 5.1.2. **b2_kinematicBody**
- 속도에 따라 시뮬레이션 중에 움직임
- forces에 반응하지 않음
- 수동적으로 움직일 수 있지만 일반적으로 속도를 설정하여 이동시킴
- 무한한 mass를 가진것처럼 동작하지만
- mass와 inverse mass 값 == 0
- 다른 static, kinematic과 충돌하지 않는다.
### 5.1.3. **b2_dynamicBody**
- 완전히 시뮬레이션되는 body
- 사용자가 수동으로 이동할 수 있지만, 일반적으로 forces에 따라 움직임
- 어떠한 body와도 충돌 가능하다.
- 0이 아닌 질량을갖는다
- 만약 0으로 설정하면 자동적으로 1kg의 질량을 갖고 회전하지 않는다.
### 5.1.4. **Body Definition**
- body를 생성하기 전에 body definition을 생성해야한다. ([b2BodyDef](https://box2d.org/documentation/structb2_body_def.html))
- 초기화 하는데 필요한 데이터를 가진다.
- 이 정의에서 body로 데이터를 복사한다.
- 정의에 대한 포인터는 유지하지 않는다.
- 정의를 재활용하여 여러 body를 생성할 수 있다.
#### 5.1.4.1. **Body Type**
- static, kinematic, and dynamic.
- 나중에 이를 변경하는것인 비용이 비싸므로 생성시에 설정
- 필수적이다.
```cpp
b2BodyDefbodyDef;
bodyDef.type=b2_dynamicBody;
```
#### 5.1.4.2. **Position and Angle**
- 생성시 body위치를 초기화
- world 원점에서 생성하고, body를 움직이는것보다 성능이 좋다.
- 원점에서 여러 body를 생성하면 성능이 저하된다.
- body's origin: Fixtures 그리고 joints은 body 원점을 기준으로 부착된다.
- 질량 중심 위치(cenger of mass): 부착된 shape의 질량분포(mass distribution)에서 결정되거나 [b2MassData](https://box2d.org/documentation/structb2_mass_data.html)로 명시적으로 설정할 수 있다.
- Box2D의 내부 계산의 대부분은 질량 중심 위치를 사용한다.
- 예를들어, b2Body는 질량중심에 대한 선형속도를 저장한다.
- body의 각도를 라디안 단위로 지정할 수 있으며, 이는 질량중심위치의 영향을 받지 않는다.
- 나중에 mass 속성들을 변경하면, body의 질량중심이 이동할 수 있지만, 원점 위치는 변경되지 않고, 부착된 shapes 과 joints 또한 이동하지 않는다.
```cpp
b2BodyDefbodyDef;
bodyDef.position.Set(0.0f,2.0f);// the body's origin position.
bodyDef.angle=0.25f*b2_pi;// the body's angle in radians.
```
- rigid body는 참조 프레임이다.
- 해당 프레임에서 fixtures 및 joints를 정의할 수 있다.
- 이것들은 local 프레임에서 절대 움직이지 않는다.
#### 5.1.4.3. **Damping**
- bodies의 world 속도를 줄이기 위해 사용된다.
- friction은 접촉할 때 발생함(damping과 다름)
- 마찰을 대체 할 수 없음, 두가지 모두 사용해야함.
- Damping 매개변수는 0~ INF 사이
- 0: 감쇠가 없음
- INF: 전체 감쇠
- 일반적으로 0 과 0.1 사이의 값을 사용한다.
```cpp
b2BodyDefbodyDef;
bodyDef.linearDamping=0.0f;
bodyDef.angularDamping=0.01f;
```
- Damping은 안정성과 성능에 대한 근사치
- 작은 감쇠값: timestep 과 무관
- 더 큰 감쇠값: timestep 에 따라 효과가 달라짐
#### 5.1.4.4. **Gravity Scale**
- 단일 body의 중력을 조절 (증가하면 안정성이 떨어짐)
```cpp
// Set the gravity scale to zero so this body will float
b2BodyDefbodyDef;
bodyDef.gravityScale=0.0f;
```
#### 5.1.4.5. **Sleep Parameters**
- 시뮬레이션 횟수가 적을 수록 좋기 때문에 body를 중단하게 함.
- Box2D가 body(or group)이 정지했다고 판단하면 body는 CPU 오버헤드가 거의 없는 절전상태에 들어간다.
- awake 상태의 body와 충돌하면 깨어나게된다.
- Bodies에 연결된 joint 나 접점이 파괴된 경우에도 body가 깨어난다.
- 수동으로 깨울 수 있다.
- Body 정의에서 잠을 잘 수 있는지 와 생성할 때의 상태를 지정할 수 있다.
```cpp
b2BodyDefbodyDef;
bodyDef.allowSleep=true;
bodyDef.awake=true;
```
#### 5.1.4.6. **Fixed Rotation**
- 캐릭터와 같은 강체가 회전하지 않게 하기 위한 설정
- 하중이 가해져도 회전하지 않는다.
```cpp
b2BodyDefbodyDef;
bodyDef.fixedRotation=true;
```
- 이 플래그는 회전 관성(rotational inertia) 그리고 그 역(inverse)이 0으로 설정되도록 한다.
#### 5.1.4.7. **Bullets**
- 이산 시뮬레이션에서 강체는 한 timestap에서 더 많이 이동할 수 있다.
- 터널링에 관한 것
- 기본적으로 Box2D는 연속 충돌 감지(CCD)를 사용하여 dynamic이 static을 터널링하는 것을 방지한다.
- 이전 위치에서 새 위치로 shape는 sweeping하여 수행한다.
- 엔진은 sweeping동안 새로운 충돌을 찾고, 충돌시간(TOI)을 계산한다.
- body가 첫번째 TOI로 이동된 다음, solver가 하위 단계를 수행하여 전체 timestep을 완료한다.(하위 단계 내에서 추가 TOI이벤트가 있을 수 있다.)
- 일반적으로 ccd는 dynamic에서 사용되지 않는다.
- 이는 성능을 합리적으로 유지하기 위해 수행된다.
- 일부 게임에서 dynamic body에 ccd가 필요할 경우가 있다. (ex. 고속 총알을 dynamic body에, 이 경우 ccd가 없으면 뚫릴 수 있음)
- 빠르게 움직이는 객체는 bullets이라는 라벨을 붙일 수 있다.
- bullet은 static, dynamic body 모두에 ccd를 수행한다.
```cpp
b2BodyDefbodyDef;
bodyDef.bullet=true;
```
- 이 플래그는 dynamic body일 경우에만 유효하다.
#### 5.1.4.8. **Activation**
- 충돌이나 역학(collision or dynamics)에 참여하지 않을 수 있다.
- 이 상태는 body가 다른 body에 의해 깨어나지 않고, body의 fixture가 broad-phase에 배치되지 않는다는 점을 제외하고는 sleep과 유사하다.
- 이와 같은 결합으로 bouncy floor가 아니더라도 bouncy ball을 만들 수 있다.
-[b2Contact::SetRestitution](https://box2d.org/documentation/classb2_contact.html#a685a1c4cfca30c379c402e20e04723b6)을 사용하여 기본 혼합을 override할 수 있다.
- b2ContactListener callback 에서 수행된다.
- 다중 접촉에 대해서 복원은 대략적인 시뮬레이션을 수행한다.
- Box2D가 반복 솔버를 사용하기 때문.
- Box2D는 충돌 속도가 작은 경우에도 비탄성충돌을 사용한다. (jitter를 방지하는데 사용 b2_velocityRhreshold)
### 5.2.5. **Filtering**
- collision filtering을 사용하면 fixtures 사이의 충돌을 방지할 수 있다.
- 예를들어, 자전거를 타는 캐릭터, 자전거가 지형과 충돌, 캐릭터가 지형과 충돌하기를 원하지만 캐릭터와 자전거가 충돌하지 않게(겹쳐져야하므로)
- 범주 및 그룹을 사용하여 이러한 충돌 필터링을 지원한다.
- Box2D는 16개의 충돌 범주를 지원한다.
- 각 fixture에 대해 카테고리를 지정할 수 있다.
- 또한 이 fixture가 충돌할 수 있는 다른 카테고리를 지정할 수 있다.
- 예를 들어, 멀티플레이어 게임에서 모든 플레이어는 서로 충돌하지 않고 몬스터는 서로 충돌하지 않지만, 플레이어와 몬스터는 충돌하게 지정 가능하다.
- 이것은 비트 마스킹으로 수행된다.
```cpp
b2FixtureDefplayerFixtureDef,monsterFixtureDef;
playerFixtureDef.filter.categoryBits=0x0002;
monsterFixtureDef.filter.categoryBits=0x0004;
playerFixtureDef.filter.maskBits=0x0004;
monsterFixtureDef.filter.maskBits=0x0002;
```
- 충돌이 발생하는 규칙은 다음과 같다.
```cpp
uint16catA=fixtureA.filter.categoryBits;
uint16maskA=fixtureA.filter.maskBits;
uint16catB=fixtureB.filter.categoryBits;
uint16maskB=fixtureB.filter.maskBits;
if((catA&maskB)!=0&&(catB&maskA)!=0)
{
// fixtures can collide
}
```
- 충돌 그룹을 사용하면 통합 그룹 인덱스를 지정할 수 있다.
- 동일한 그룹 인덱스를 가진 모든 fixture가 항상 충돌(양수 인덱스)하거나 충돌하지 않도록(음수 인덱스) 할 수 있다.
- 이것은 일반적으로 자전거 부품과 같이 관련성이 있는 항목에 사용된다.
- 아래의 예에서 fixture1 과 fixture2는 항상 충돌하지만 fixture3과 4는 절대 충돌하지 않는다.
```cpp
fixture1Def.filter.groupIndex=2;
fixture2Def.filter.groupIndex=2;
fixture3Def.filter.groupIndex=-8;
fixture4Def.filter.groupIndex=-8;
```
- 다른 그룹 인덱스의 fixture간의 충돌은 카테고리 및 마스크 비트에 따라 필터링된다.
- 즉, 그룹 필터링은 카테고리 필터링보다 우선순위가 높다.
- 추가적으로 알아야하는 필터링은 다음과 같다.
- static body에 붙은 fixture는 오직 dynamic 과 충돌
- kinematic body에 붙은 fixture는 오직 dynamic 과 충돌
- 같은 body에 붙은 fixtures는 결코 서로 충돌하지 않는다.
- 추가적으로 joint로 연결된 body의 fixture간의 충돌을 선택적으로 활성화/비활성화 할 수 있다.
- 때때로 fixture가 이미 생성된 후에 filtering을 변경해야할 수 있다.
-[GetFilterData](https://box2d.org/documentation/classb2_fixture.html#ad956250d9f684a407992ec178320127e), [SetFilterData](https://box2d.org/documentation/classb2_fixture.html#a2c5e0d12c174927a4ad550459be334ad)를 사용하여 b2Filter 구조를 가져오고 설정할 수 있다.
- 필터 데이터를 변경해도 다음 time step까지 접촉점(contacts)이 추가되거나 제거되지 않는다. (world class)
2.[b2ContactListener::BeginContact](https://box2d.org/documentation/classb2_contact_listener.html#a35148fc56fb9eac12077200fbd928f65) and [b2ContactListener::EndContact](https://box2d.org/documentation/classb2_contact_listener.html#afb3059058e5c47903a3947c2eef5826b)