Computer Graphics/ALEngine
FT_Newton: Initialization, Integrate, Broad Phase - (3)
Banjosh
2025. 1. 10. 13:11
이번 글에서는 팀원이 구현한 부분인 Initialization, Integrate, 그리고 Broad Phase 단계를 간단히 살펴보려 한다. 물리 엔진의 큰 틀에서 이 단계들은 초기화와 첫 번째 물리 연산 루프에 해당한다.
Initialization - World
물리 엔진의 초기화 단계는 물리 연산이 이루어질 환경을 설정하는 과정이다. 이 중에서도 가장 중요한 World 클래스 설계부터 살펴보자.
World 클래스
class World
{
public:
World(uint32_t size, App &app);
~World();
void startFrame();
void runPhysics();
// ...
ContactManager contactManager;
App &app;
private:
std::vector<Rigidbody *> rigidbodies;
};
- contactManager: 충돌을 처리하는 객체. 나중에 충돌 처리 단계에서 자세히 다룰 예정이다.
- rigidbodies: 모델들의 물리 처리를 위한 정보를 저장.
- startFrame(): 각 프레임마다 힘과 토크를 초기화.
- runPhysics(): 물리 루프를 실행.
Rigidbody 클래스
Rigidbody는 물리 엔진에서 모델을 대표하는 객체로, 아래와 같이 설계되어 있다.
class Rigidbody
{
public:
// ...
protected:
static int32_t BODY_COUNT;
World *world;
Transform xf;
glm::vec3 linearVelocity;
glm::vec3 angularVelocity;
glm::mat3 inverseInertiaTensorWorld;
glm::mat3 inverseInertiaTensor;
glm::mat4 transformMatrix;
glm::vec3 forceAccum;
glm::vec3 torqueAccum;
glm::vec3 acceleration;
glm::vec3 lastFrameAcceleration;
std::vector<Fixture *> fixtures;
std::queue<glm::vec3> forceRegistry;
Sweep sweep;
BodyType type;
float inverseMass;
float linearDamping;
float angularDamping;
float gravityScale;
int32_t xfId;
int32_t m_flags;
int32_t m_islandIndex;
int32_t m_bodyID;
ContactLink *m_contactLinks;
};
속도, 질량, 댐핑, 중력 등 물리 엔진에서 필요한 속성들이 모두 포함되어 있다. 여기서 특히 주목할 부분은 xf(Transform)와 Fixture이다.
- xf (Transform):
- 모델의 위치(position)와 회전(rotation) 정보를 포함한다.
- 위치는 glm::vec3, 회전은 glm::quat로 표현된다.
- rigidbody의 위치와 각도가 물리 엔진에 의해 변경되면, 이를 외부에서도 반영하기 위해 xfId를 통해 업데이트한다.
- Fixture:
- 충돌 정보를 가지는 객체로, 하나의 rigidbody에 여러 개의 fixture가 존재할 수 있다.
- fixture는 서로 충돌하지 않으며, narrow phase에서 충돌 감지에 사용된다.
Fixture 클래스
class Fixture
{
public:
// ...
protected:
Rigidbody *body;
Shape *shape;
float density;
float friction;
float restitution;
std::vector<FixtureProxy *> proxies;
};
- shape: 충돌 범위를 나타내며, sphere, box, cylinder 등 다양한 형태가 가능.
- density, friction, restitution: 충돌에 필요한 물리적 속성.
- proxies: Broad Phase 트리의 노드와 AABB 정보에 접근하기 위한 데이터.
Physics Loop - Integrate
Integrate는 world에서 runPhysics()를 통해 실행되는 첫 단계로, world 내부의 rigidbody를 순회하며 다음 과정을 수행한다.
- calculateForceAccum()
- 누적된 힘과 토크를 각각 하나로 압축.
- integrate()
- 압축된 힘과 토크를 사용해 rigidbody의 속도, 각속도, 위치, 각도를 업데이트.
- synchronizeFixtures()
- 업데이트된 물리 속성을 기준으로 AABB 범위가 변했는지 확인.
- AABB를 벗어난 경우, 트리의 노드 정보를 업데이트하고 필요 시 트리의 루트를 변경해 밸런싱 작업을 수행.
AABB (Axis-Aligned Bounding Box): 물체의 범위를 x, y, z 축을 따라 정렬된 박스로 표현하는 방식.
Physics Loop - Broad Phase
Broad Phase는 1차적으로 충돌 가능성을 감지하는 단계다. 다음 과정을 통해 진행된다.
- AABB 업데이트
- Integrate의 synchronizeFixtures() 단계에서 AABB가 변경된 노드들만 순회.
- 움직이지 않은 물체는 확인하지 않는다.
- 충돌 쌍 등록
- Broad Phase 트리를 통해 충돌 가능성이 있는 AABB 쌍을 찾아 Narrow Phase로 전달.
이로써 Broad Phase에서 충돌 쌍을 Narrow Phase로 넘기게 되며, 이후 Solve 단계에서 처리된다.
다음 글에서는 이 과정을 기반으로 내가 맡은 Narrow Phase와 Solve 단계를 어떻게 구현했는지에 대해 자세히 다뤄볼 예정이다.