본문으로 건너뛰기
김신건의 로그

물리 시뮬레이션 (Physics Simulation)

· 수정 · 📖 약 4분 · 1,480자/단어 #algorithm #math #physics
physics, 물리 시뮬레이션, 운동 방정식, 충돌 처리, physics-simulation

정의

물리 시뮬레이션 (Physics Simulation) 은 뉴턴 역학의 운동 방정식 (F=ma, 속도, 가속도) 을 수치적으로 적분하여 시간 경과에 따른 물체의 위치와 속도를 계산하는 기법. 게임 엔진, 로봇 공학, 과학 계산에서 실제 물리 현상을 모의하는 데 사용.

문제 상황과 동기

N 개의 물체가 있고, 각 물체는 위치, 속도, 가속도를 가진다. 매 시간 단계마다 힘을 받아 가속도가 결정되고, 속도와 위치가 갱신된다. 추가로 물체 간 충돌을 감지하고 반응해야 한다.

  • naive: 매 시간 단계마다 모든 물체 쌍을 확인. O(N^2) 충돌 검사. N=1000 이면 10^6 번 거리 계산, 초당 60 프레임이면 6·10^7 연산. 느림.
  • 핵심 통찰: 시간을 작은 dt 로 이산화하고, 각 단계에서 상태 (위치, 속도) 를 갱신. 공간 분할 (grid, quadtree) 로 충돌 검사를 O(N log N) 으로 가속.

시각화

시뮬레이션 루프 흐름

flowchart TD
    A["초기화: 위치 p, 속도 v, 질량 m"] --> B[시뮬레이션 루프]
    B --> C["힘 계산: 중력 + 외부힘"]
    C --> D["가속도 a = F / m"]
    D --> E["속도 갱신: v += a * dt"]
    E --> F["위치 갱신: p += v * dt"]
    F --> G{"충돌 감지"}
    G -->|충돌 있음| H[충돌 반응 처리]
    H --> I{"종료 조건 도달"}
    G -->|충돌 없음| I
    I -->|계속| B
    I -->|종료| J[결과 반환]

핵심 아이디어

Euler 적분: 현재 상태 (위치 p, 속도 v) 에서 다음 상태로 진행.

a = F / m                    (뉴턴 제2법칙)
v_new = v + a * dt           (속도 갱신)
p_new = p + v_new * dt       (위치 갱신)

Verlet 적분: 속도를 명시적으로 저장하지 않고, 이전 위치를 기억. 스프링이나 천 시뮬레이션에서 더 안정적.

p_new = 2 * p - p_old + a * dt^2

충돌 감지: 원형 물체는 거리 비교. 축 정렬 경계 상자 (AABB) 는 각 축 범위 겹침 확인.

충돌 반응: 운동량 보존. 두 물체가 충돌하면 속도를 교환하거나, 반발 계수 (restitution) 를 곱해 에너지 손실 표현.

알고리즘

simulate(bodies, forces, dt, gravity):
    for each body in bodies:
        a = (forces[body] + gravity) / mass[body]
        v[body] += a * dt
        p[body] += v[body] * dt
    
    for i = 0 to N-1:
        for j = i+1 to N-1:
            if collides(bodies[i], bodies[j]):
                resolve_collision(bodies[i], bodies[j])

탄성 충돌 반응 공식

1D 탄성 충돌에서 운동량과 에너지 보존:

m1, m2: 충돌하는 두 물체의 질량
v1, v2: 충돌 전 속도

v1' = (m1 - m2) / (m1 + m2) * v1 + 2*m2 / (m1 + m2) * v2
v2' = 2*m1 / (m1 + m2) * v1 + (m2 - m1) / (m1 + m2) * v2

비탄성 충돌은 반발 계수 e 도입:

v_rel' = -e * v_rel    (e=1: 완전 탄성, e=0: 완전 비탄성)

적분 방법 비교

방법장점단점추천 상황
Euler구현 단순에너지 증가, 큰 dt 불안정학습, 프로토타입
Semi-implicit Euler안정적, 단순정밀도 낮음게임 물리
Verlet에너지 보존 우수속도 직접 저장 불가스프링, 천
RK4고정밀도연산 4배궤도 역학, 과학 계산

TIP

게임에서는 Semi-implicit Euler 가 안정성과 속도 균형이 좋음. v 갱신 후 새 v 로 p 를 갱신.

구현

// 1D 낙하 + 바닥 충돌, Euler 적분
#include <bits/stdc++.h>
using namespace std;
int main() {
  double y = 300, v = 0, g = -9.8, dt = 0.1;
  double ground = 400, restitution = 0.8;
  int steps = 50;
  
  for (int i = 0; i < steps; i++) {
      v += g * dt;
      y += v * dt;
      
      if (y >= ground) {
          y = ground;
          v = -v * restitution;
      }
      
      cout << fixed << setprecision(2) << "t=" << i*dt 
           << " y=" << y << " v=" << v << "\n";
  }
  return 0;
}
stdin
초기: y=300, v=0, g=-9.8, dt=0.1, restitution=0.8
결과
t=0.0 y=300.00 v=0.00
t=0.1 y=299.95 v=-0.98
t=0.2 y=299.80 v=-1.96
t=0.3 y=299.55 v=-2.94
t=0.4 y=299.21 v=-3.92

복잡도

항목
상태 갱신 (N 물체)O(N)
충돌 감지 (naive)O(N^2)
충돌 감지 (spatial hash)O(N log N)
충돌 반응O(1) per collision
전체 (per frame)O(N) ~ O(N^2)

변형 / 활용

  • Verlet 적분: 속도 명시 저장 없음. 천, 스프링 시뮬레이션에 안정적.
  • RK4 (Runge-Kutta 4차): 더 높은 정확도. 계산 비용 4배.
  • Impulse-based 충돌: 운동량 보존으로 정확한 반응.
  • Penalty method: 침투 깊이에 비례한 복원력. 간단하지만 부정확.
  • Spatial partitioning: Grid, Quadtree, BVH 로 충돌 검사 가속.

공간 분할 전략

충돌 검사를 O(N²) 에서 줄이는 세 가지 주요 방법:

flowchart LR
    A["N 개 물체"] --> B{"공간 분할 방법"}
    B -->|정적 그리드| C["O(N) 구축 / O(1) 셀 조회"]
    B -->|Quadtree| D["O(N log N) 구축 / 밀도 적응"]
    B -->|BVH| E["O(N log N) 구축 / 계층적 구조"]
    C --> F[후보 쌍만 정밀 검사]
    D --> F
    E --> F
    F --> G["전체 O(N log N) 수렴"]
  • 정적 그리드: 물체 크기가 균일할 때 최고. 셀 크기 = 물체 최대 반지름 * 2.
  • Quadtree: 밀도 불균형 분포에 유리. 군집 + 희소 혼재 시나리오.
  • BVH: 게임 엔진 표준. 동적 물체와 복잡한 형상에 강함.

함정

1. dt 너무 크면 불안정 (tunneling)

dt 가 크면 물체가 한 프레임에 벽을 뚫고 지나갈 수 있다. 연속 충돌 감지 (CCD) 필요.

2. 부동소수점 오차 누적

오래 시뮬레이션하면 위치 오차가 누적. 주기적으로 정규화 필요.

3. 충돌 반응 후 중복 충돌

물체가 벽에 박혀 있으면 매 프레임 충돌 감지. 충돌 상태 플래그 필요.

4. 적분 방법 선택 오류

RK4 가 항상 더 좋다는 오해. dt 가 작으면 Euler 와 큰 차이 없고, 4배 연산 낭비. 목적에 맞는 방법 선택 필요.

5. 동시 다중 충돌 순서 문제

N 개 물체가 동시에 충돌할 때 처리 순서가 결과를 바꿈. impulse accumulation 방식으로 한 프레임의 모든 충돌을 모아서 한 번에 처리.

WARNING

복잡한 물리 시뮬레이션에서 부동소수점 오차 누적 + 잘못된 dt 선택 + 충돌 처리 순서 문제가 복합될 경우, 물체들이 서로 붙어버리거나 폭발적으로 튀어 나가는 현상이 발생한다. 각 문제를 독립적으로 진단하고 수정해야 한다.

BOJ 연습 문제

번호제목정답률링크
BOJ 14503로봇 청소기(수집 안 됨)kokoa-lab
BOJ 15685드래곤 커브(수집 안 됨)kokoa-lab
BOJ 16234인구 이동(수집 안 됨)kokoa-lab
BOJ 17144미세먼지 안녕!(수집 안 됨)kokoa-lab

참고

이 글의 용어 (4개)
기하 (Geometry) 기본algorithm
정의 Computational Geometry 는 점, 선, 다각형 등 기하 객체를 컴퓨터로 처리하는 알고리즘 분야. PS 에서는 2D 평면 위의 정수 좌표 가 주로 다루어지며,…
너비 우선 탐색 (BFS)algorithm
정의 너비 우선 탐색 (Breadth-First Search, BFS) 는 그래프 G=(V, E) 에서 시작 정점 s 로부터 가까운 정점부터 순서대로 방문하는 알고리즘. 큐 (F…
스위핑 (Sweeping)algorithm
정의 스위핑 (Sweeping) 은 시간 또는 공간 축 위의 이벤트를 정렬한 뒤, 한 방향으로 훑으며 상태를 갱신해 문제를 푸는 기법입니다. 선분 교차, 구간 합집합, 최대 겹침…
시뮬레이션 (Simulation)algorithm
정의 시뮬레이션 (Simulation) 은 문제에서 제시한 규칙을 그대로 코드로 옮겨 한 단계씩 따라가는 알고리즘. 복잡한 로직보다 정확한 구현과 엣지 케이스 처리 가 핵심. P…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기