상세 컨텐츠

본문 제목

FT_Newton: Initialization, Integrate, Broad Phase - (3)

Computer Graphics/FT_Newton

by 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를 순회하며 다음 과정을 수행한다.

  1. calculateForceAccum()
    • 누적된 힘과 토크를 각각 하나로 압축.
  2. integrate()
    • 압축된 힘과 토크를 사용해 rigidbody의 속도, 각속도, 위치, 각도를 업데이트.
  3. synchronizeFixtures()
    • 업데이트된 물리 속성을 기준으로 AABB 범위가 변했는지 확인.
    • AABB를 벗어난 경우, 트리의 노드 정보를 업데이트하고 필요 시 트리의 루트를 변경해 밸런싱 작업을 수행.

AABB (Axis-Aligned Bounding Box): 물체의 범위를 x, y, z 축을 따라 정렬된 박스로 표현하는 방식.


Physics Loop - Broad Phase

Broad Phase는 1차적으로 충돌 가능성을 감지하는 단계다. 다음 과정을 통해 진행된다.

  1. AABB 업데이트
    • Integrate의 synchronizeFixtures() 단계에서 AABB가 변경된 노드들만 순회.
    • 움직이지 않은 물체는 확인하지 않는다.
  2. 충돌 쌍 등록
    • Broad Phase 트리를 통해 충돌 가능성이 있는 AABB 쌍을 찾아 Narrow Phase로 전달.

이로써 Broad Phase에서 충돌 쌍을 Narrow Phase로 넘기게 되며, 이후 Solve 단계에서 처리된다.

다음 글에서는 이 과정을 기반으로 내가 맡은 Narrow PhaseSolve 단계를 어떻게 구현했는지에 대해 자세히 다뤄볼 예정이다.

 

 

관련글 더보기