테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

유체·천·연체 시뮬레이션

강체는 위치 하나와 방향 하나면 상태가 끝나지만, 펄럭이는 망토와 출렁이는 젤리와 피어오르는 연기는 수천, 수백만 개의 값이 서로 밀고 당긴다. 질량-스프링에서 시작해 위치 기반 동역학(PBD, XPBD), 천과 머리카락, 연체와 소성, 나비에-스토크스와 격자 유체, SPH와 FLIP, 바다와 연기, GPU 병렬화, 그리고 게임이 이 모든 것을 속이는 방법까지 작은 시뮬레이션을 직접 돌린 그림으로 따라간다.

목차 (16)
  1. 강체 너머: 입자로 볼까, 격자로 볼까
  2. 질량-스프링 계: 가장 단순한 변형체
  3. 강성과 시간 간격: 명시적, 반암시적, 암시적 적분
  4. 위치 기반 동역학(PBD): 힘 대신 위치를 고친다
  5. XPBD: 반복 횟수와 상관없는 강성
  6. 천과 머리카락: 충돌, 바람, 긴 거리 제약
  7. 연체, 파괴, 소성
  8. 유체의 방정식: 나비에-스토크스를 항별로
  9. 격자 유체: Stable Fluids
  10. SPH: 입자로 푸는 유체
  11. FLIP/PIC와 MPM: 입자와 격자를 섞는다
  12. 물 표면, 연기, 불
  13. GPU 병렬화
  14. 게임의 속임수
  15. 흔한 오해
  16. 핵심 자료

강체 너머: 입자로 볼까, 격자로 볼까

강체 시뮬레이션은 물체 하나를 무게중심 위치, 방향(쿼터니언), 선속도, 각속도 열세 개 남짓한 숫자로 다룬다. 모양이 변하지 않는다는 가정 하나가 문제를 작게 만든다. 강체의 적분, 충돌 판정과 충격량 응답은 게임 물리학 노트에 있다. 이 노트는 그 가정을 버린다. 천은 모양이 매 순간 바뀌고, 물은 아예 정해진 모양이 없다. 그러면 "상태"를 무엇으로 적을지부터 다시 정해야 한다.

방법은 크게 둘이다. 라그랑주(Lagrangian) 표현은 물질 덩어리를 입자나 정점으로 쪼개 그 조각을 따라간다. 입자마다 위치, 속도, 질량을 싣고 다니므로 물질이 움직이는 것(이류)은 공짜다. 대신 "내 근처에 누가 있나"를 매번 찾아야 한다. 천의 정점, 머리카락의 마디, SPH 입자가 이쪽이다. 오일러(Eulerian) 표현은 공간을 고정된 격자로 나누고 각 칸에서 그 자리를 지나가는 속도, 밀도, 온도를 잰다. 이웃이 늘 정해져 있어 미분과 압력 풀이가 쉽지만, 물질이 칸 사이를 옮겨 가는 것을 따로 계산해야 하고 그 과정에서 값이 뭉개진다. 연기와 불, 격자 유체가 이쪽이다.

입자가 흐름을 따라 움직이는 라그랑주 표현과 고정된 격자 칸마다 속도를 재는 오일러 표현의 비교라그랑주: 입자오일러: 격자입자가 위치·속도·질량을 싣고 함께 흘러간다점선 = 지나온 길 · 이류는 공짜, 이웃 찾기가 숙제칸은 제자리, 그 자리를 지나는 속도·밀도를 잰다미분은 쉽고 압력 풀기 좋음, 이류가 숙제
같은 흐름을 두 방식으로 적는다. 왼쪽은 입자가 흐름을 타고 가며 자기 값을 싣는 라그랑주 표현, 오른쪽은 공간에 고정된 칸마다 지나가는 속도를 재는 오일러 표현이다.

현대 기법의 상당수는 둘을 섞는다. FLIP과 MPM은 입자로 물질을 나르고 격자에서 압력과 힘을 푼다. 어느 쪽을 고르든 이 노트의 모든 방법은 결국 "많은 자유도를 작은 시간 간격으로 앞으로 밀어 가는" 문제이고, 무엇을 정확히 하고 무엇을 포기할지의 선택이다.

질량-스프링 계: 가장 단순한 변형체

변형체를 만드는 가장 직관적인 방법은 질점(작은 공)을 스프링으로 잇는 것이다. 스프링 하나는 쉬는 길이 L에서 벗어난 만큼 양 끝을 당기거나 민다. 힘은 훅의 법칙 F = −k(|xb − xa| − L)이고, 진동이 끝없이 이어지지 않게 두 점의 상대 속도에 비례하는 감쇠를 더한다. 매 걸음 모든 스프링의 힘을 더해 각 질점의 가속도를 구하고 적분하면 끝이다. 단진동과 감쇠의 물리는 물리학 노트에 있다.

천을 격자로 만들 때 스프링은 세 종류를 겹친다. 바로 옆 정점을 잇는 구조 스프링은 늘어남을, 대각선으로 잇는 전단 스프링은 마름모꼴로 찌그러지는 것을, 한 칸 건너뛰어 잇는 굽힘 스프링은 종이처럼 접히는 것을 막는다. 굽힘 스프링이 없으면 천이 아무 저항 없이 접혀 젖은 휴지처럼 보이고, 너무 세면 판지처럼 뻣뻣해진다.

5×4 격자 천의 구조 스프링, 전단 스프링, 굽힘 스프링 배치와 개수구조 31개늘어남을 막는다전단 24개비스듬히 찌그러짐을 막는다굽힘 22개접힘을 막는다질점 20개 · 스프링 합계 77개 · 셋을 모두 겹쳐 쓴다
5×4 격자 천의 세 가지 스프링. 개수는 계산값이다. 실제 천은 이 셋을 모두 겹치고 종류마다 강성을 따로 준다.

질량-스프링은 만들기 쉽고 직관적이지만 약점이 둘 있다. 강성 k가 물리적 재료 상수와 바로 이어지지 않아(같은 천도 격자를 촘촘하게 하면 다르게 행동한다) 값을 손으로 맞춰야 하고, 무엇보다 단단한 스프링은 시간 간격을 아주 작게 강요한다. 다음 절이 그 이야기다.

강성과 시간 간격: 명시적, 반암시적, 암시적 적분

스프링 하나에 매달린 질점은 각진동수 ω = √(k/m)로 떨린다. 이를 시간 간격 dt로 나눠 계산할 때 적분 방식에 따라 결과가 갈린다. 명시적(앞으로) 오일러는 지금 속도로 위치를, 지금 힘으로 속도를 옮긴다. 이 방식은 감쇠 없는 진동에서 에너지가 걸음마다 정확히 (1 + ω²dt²)배로 늘어나므로 dt가 아무리 작아도 언젠가 터진다. 반암시적(심플렉틱) 오일러는 속도를 먼저 갱신하고 그 새 속도로 위치를 옮긴다. 순서만 바꿨는데 에너지가 늘지도 줄지도 않고 출렁이며 머문다. 단, dt가 2/ω를 넘으면 터진다. 적분 방식의 일반론은 계산 과학 노트와 게임 개발 › 물리의 적분 절에 있다.

세 적분 방식으로 같은 스프링을 돌렸을 때 에너지가 늘거나 보존되거나 줄어드는 모습10^-210^-1110^110^2에너지 ÷ 처음 에너지명시적 오일러×43반암시적 오일러×0.984암시적(뒤로) 오일러×0.023040걸음 = 2초(두 주기)dt = 0.05초 · 반암시적 오일러가 터지는 경계 dt = 2/ω = 0.318초
주기 1초짜리 스프링을 dt = 0.05초로 두 주기 돌린 에너지(계산값, 로그 눈금). 명시적 오일러는 불어나고, 뒤로 오일러는 같은 비율로 줄어들고, 반암시적 오일러는 1 근처에 머문다.

문제는 천과 머리카락이 "늘어나지 않아야" 한다는 점이다. 거의 늘어나지 않게 하려면 k를 크게 해야 하고, k가 크면 ω가 커져 허용되는 dt가 줄어든다. 질량 0.01kg짜리 질점(천 1m²를 100개 정점으로 나눈 정도)으로 계산하면 다음과 같다. 이렇게 빠른 성분과 느린 성분이 섞여 가장 빠른 성분이 걸음 크기를 정해 버리는 상황을 강성(stiff) 문제라 부른다.

스프링 상수 k (N/m)허용 dt = 2√(m/k)60fps 한 프레임에 필요한 걸음 수
10020.0ms1
10,0002.0ms9
1,000,0000.20ms84

암시적 적분: 큰 걸음과 그 대가

암시적(뒤로) 오일러는 "걸음이 끝났을 때의 힘"으로 속도를 고친다. 미래의 위치를 모르니 걸음마다 연립 방정식을 풀어야 하지만, 대신 dt를 아무리 크게 해도 터지지 않는다. Baraff와 Witkin의 Large Steps in Cloth Simulation(SIGGRAPH 1998)이 천에 암시적 적분과 켤레 기울기법을 써서 큰 걸음을 가능하게 한 대표적인 논문이고, 이후 많은 오프라인 천 시뮬레이터가 이 계열을 따랐다. 대가는 두 가지다. 걸음마다 큰 희소 행렬을 푸는 비용, 그리고 위 그림에서 보듯 에너지가 저절로 빠져나가는 수치 감쇠다. 큰 걸음일수록 천이 꿀 속에서 움직이는 것처럼 둔해진다.

위치 기반 동역학(PBD): 힘 대신 위치를 고친다

게임은 행렬을 풀 시간도, 작은 걸음을 수십 번 돌릴 시간도 없다. Müller 외의 Position Based Dynamics(VRIPHYS 2006)는 발상을 뒤집었다. 스프링 힘을 계산하지 않고, "이 두 점 사이 거리는 L이어야 한다" 같은 제약을 두고 위치를 직접 그 조건에 맞게 옮긴다. 이 생각의 뿌리는 Hitman: Codename 47에 쓰인 Jakobsen의 Advanced Character Physics(베를레 적분과 제약 반복)에 있다.

한 걸음은 세 단계다. ① 예측: 외력만 보고 위치를 먼저 옮긴다(p = x + dt·v + dt²·f/m). ② 제약 투영: 제약을 하나씩 돌며, 어긴 만큼 관련된 점들을 역질량 비율로 나눠 옮겨 그 제약만 정확히 만족시킨다. 하나를 고치면 옆 제약이 다시 어긋나므로 전체를 여러 바퀴(가우스-자이델 반복) 돈다. ③ 속도 갱신: v = (p − x)/dt로 위치 변화에서 속도를 거꾸로 얻는다. 위치가 늘 제약 근처에 머물기 때문에 폭발하지 않고, 충돌도 "바닥 아래로 내려가지 않는다"는 부등식 제약 하나로 끝난다.

세 점짜리 줄이 예측, 제약 투영, 속도 갱신을 거치는 PBD 한 걸음의 단계 그림시작1.0001.0000121. 예측1.0771.0000122. 제약 투영1.0001.0720122. 제약 투영1.0341.0000122. 제약 투영1.0001.0320122. 제약 투영1.0151.0000123. 속도 갱신1.0151.000012빨강 = 길이가 1이 아닌 마디 · 굵은 선 = 방금 고친 마디
1 / 7

시작: 점 0은 못에 박혀 있고(역질량 0), 점 1·2는 속도 0으로 수평에 놓여 있다. 두 마디의 쉬는 길이는 1이다.

위치 기반 동역학 한 걸음을 단계로 넘겨 본다. 점선 원은 걸음 시작 때 위치, 숫자는 마디 길이(쉬는 길이 1)다. 좌표는 모두 계산값이다.

대가는 강성이 반복 횟수와 시간 간격에 따라 바뀐다는 점이다. 반복을 적게 돌면 제약이 덜 만족되어 천이 고무처럼 늘어난다. 논문은 원하는 강성 k를 반복 ns번에 나눠 쓰도록 한 번 반복의 강성을 k' = 1 − (1 − k)1/ns로 보정하는 방법을 제시했다(예: k = 0.5, 반복 10번이면 k' = 0.067). 그래도 dt에 대한 의존은 남는다고 논문 스스로 적었다. 고정 시간 간격을 쓰는 게임에서는 크게 문제 되지 않았지만, 프레임마다 반복 횟수를 바꾸면 재질이 바뀐다.

XPBD: 반복 횟수와 상관없는 강성

Macklin, Müller, Chentanez의 XPBD(MIG 2016)는 PBD에 숫자 둘을 더해 이 문제를 풀었다. 제약마다 강성의 역수인 컴플라이언스 α와, 지금까지 그 제약이 낸 힘의 누적인 라그랑주 승수 λ를 둔다. 반복마다 고칠 양은 Δλ = (−C − α̃λ)/(∇C·M−1·∇CT + α̃), α̃ = α/dt²다. α = 0이면 원래 PBD와 같고(무한히 단단함), α가 크면 제약이 부드럽게 늘어난다. 이 식은 암시적 적분을 한 번의 국소 반복으로 풀어 가는 것과 같아서, 반복을 몇 번 돌든 수렴한 곳의 강성이 같다. 덤으로 λ가 제약에 걸린 힘을 알려 줘서 "힘이 일정 이상이면 끊어지는 관절" 같은 것을 만들기 쉽다.

PBD는 반복 횟수에 따라 진동 주기가 달라지고 XPBD는 반복 횟수와 상관없이 같은 주기로 진동하는 비교+0.50−0.5PBD 반복 1주기 1.045초PBD 반복 20주기 0.238초XPBD 반복 1·20주기 0.634초점선 = 해석해주기 2π√(mα) = 0.628초0초2초늘어난 길이(쉬는 길이 1 기준)
거리 제약 하나에 매달린 질점을 1.5에서 놓았다(질량 1, dt = 1/60초, 계산값). PBD는 반복 1번과 20번에서 주기가 네 배 넘게 달라진다. XPBD(α = 0.01)는 반복 1번과 20번이 정확히 겹치고 해석해 주기에 가깝다. 진폭이 조금씩 주는 것은 암시적 풀이의 수치 감쇠다.

그 뒤 Macklin 외의 Small Steps in Physics Simulation(SCA 2019)은 큰 걸음 하나에 반복 n번을 쓰는 것보다 걸음을 n개로 쪼개 각각 반복 1번을 쓰는 편이 오차와 감쇠가 훨씬 작다는 것을 보였다. 지금의 XPBD 구현은 대개 이 "작은 걸음(substep)" 방식으로 돈다.

천과 머리카락: 충돌, 바람, 긴 거리 제약

PBD 천은 정점을 입자로, 구조·전단 스프링을 거리 제약으로, 굽힘을 이웃 삼각형 사이 각도 제약(또는 한 칸 건너 거리 제약)으로 바꾼 것이다. 실제 천은 거의 늘어나지 않지만 쉽게 구부러지므로, 늘어남 제약은 단단하게(α ≈ 0), 굽힘은 부드럽게 준다.

충돌과 자기 충돌

몸과의 충돌은 보통 캡슐과 구 몇 개로 단순화한 충돌체에 대해 "표면 밖에 있어라"는 부등식 제약으로 처리한다. 어려운 것은 자기 충돌이다. 천이 접히면 천끼리 부딪치는데, 모든 정점과 삼각형 쌍을 검사할 수 없으니 공간 해시로 가까운 쌍만 찾고, 천에 얇은 두께를 줘 입자끼리 그 거리 안으로 들어오지 못하게 한다. 한 걸음에 두께보다 멀리 움직이면 서로 뚫고 지나가 엉킨 상태가 되므로, 걸음을 잘게 쪼개거나 속도를 제한한다. 넓은 판정과 좁은 판정의 일반론은 게임 개발 › 물리에 있다.

바람

바람은 공기를 풀지 않고 삼각형마다 힘을 준다. 삼각형의 법선 n, 넓이 A, 바람과 천의 상대 속도 vrel로 F ∝ A·(vrel·n)·n 정도를 주면, 바람을 정면으로 받는 면만 밀리고 바람과 나란한 면은 그대로라 깃발이 펄럭이는 모양이 저절로 나온다. 여기에 시간에 따라 흔들리는 노이즈를 곱해 돌풍을 만든다.

머리카락, 로프, 긴 거리 제약

머리카락과 로프는 마디를 거리 제약으로 이은 사슬이다. 문제는 사슬이 길면 고정점에서 끝까지 제약을 한 바퀴 도는 동안 수정이 한 마디씩만 전해져, 반복이 적으면 줄 전체가 고무줄처럼 늘어난다는 것이다. Kim, Chentanez, Müller-Fischer의 Long Range Attachments(SCA 2012)는 게임 캐릭터의 옷이 대개 어깨나 허리 같은 애니메이션된 부위에 붙어 있다는 점을 이용한다. 각 입자가 붙은 점에서 "쉬는 상태의 거리보다 멀어지지 않는다"는 한쪽 방향 제약을 하나씩 더하면, 반복 몇 번만으로도 전체가 늘어나지 않는다. 머리카락에는 Müller, Kim, Chentanez의 Fast Simulation of Inextensible Hair and Fur(VRIPHYS 2012)처럼 뿌리에서 끝으로 가며 각 마디를 앞 마디 쪽으로 당겨 한 바퀴 만에 길이를 맞추는 follow-the-leader 방식도 쓰인다.

반복이 적은 PBD 줄은 늘어나고 긴 거리 제약이나 많은 반복을 쓰면 쉬는 길이를 지키는 비교반복 2번길이 ×1.168반복 2번 + LRA길이 ×1.008반복 30번길이 ×1.008쉬는 길이0.5초 뒤 모습 · 줄은 수평에서 출발해 아직 흔들리는 중이다
열 마디 줄(전체 1m)을 수평에서 놓고 0.5초 뒤의 모습(계산값). 반복 2번이면 16% 넘게 늘어나고, 같은 반복 2번에 긴 거리 제약을 더하면 끝점이 쉬는 길이 안에 묶인다. 반복 30번이면 비용을 열다섯 배 들여 비슷한 결과를 얻는다.

연체, 파괴, 소성

젤리, 근육, 고무공처럼 부피를 가진 변형체는 천보다 제약이 하나 더 필요하다. 표면만 스프링으로 이으면 풍선처럼 쭈그러들기 때문이다. PBD 계열에서는 사면체 메시를 만들고 각 사면체의 부피 제약을 더하거나, 닫힌 표면 전체의 부피를 하나의 제약으로 둔다.

형상 일치(shape matching)

Müller 외의 Meshless Deformations Based on Shape Matching(SIGGRAPH 2005)는 연결 정보 없이 점 구름만으로 연체를 만든다. 매 걸음 쉬는 모양을 회전과 이동만으로 지금 점들에 가장 잘 겹친 위치(목표)를 구하고, 각 점을 목표 쪽으로 강성만큼 끌어당긴다. 가장 잘 맞는 회전은 점들의 상관 행렬을 극분해해 얻는다(2차원에서는 각도 하나의 닫힌 꼴). 목표가 언제나 쉬는 모양과 합동이므로 어떤 상황에서도 터지지 않는다는 것이 장점이고, 물리 재료 상수와 바로 이어지지 않는 것이 단점이다.

찌그러진 점들에 쉬는 모양을 회전과 이동으로 맞춘 목표 위치와 점을 끌어당기는 화살표쉬는 모양 q지금 점 x(찌그러짐)목표 g = R·q + c회전 R = 3.6°x ← x + s·(g − x) · 강성 s(0~1)만큼 목표로 당긴다 · 가운데 점 = 무게중심 c
찌그러진 점들(빨강)에 쉬는 모양을 돌리고 옮겨 맞춘 목표(파랑, 계산값). 화살표 방향으로 강성 비율만큼 당기면 모양이 되살아난다. 이 회전과 무게중심은 강체의 회전·위치이기도 하다.

유한 요소법(FEM) 개요

재료의 실제 성질(영률, 푸아송 비)로 행동해야 할 때는 유한 요소법을 쓴다. 물체를 사면체로 나누고, 사면체가 쉬는 모양에서 얼마나 늘고 비틀렸는지(변형 기울기)를 재서 탄성 에너지를 구하고, 그 에너지의 기울기가 각 정점에 걸리는 힘이 된다. 같은 재료면 메시를 바꿔도 같은 행동을 한다는 것이 질량-스프링과의 결정적 차이다. 회전이 크면 단순한 선형 모델이 부풀어 오르는 문제가 있어 회전을 빼고 계산하는 공회전(corotational) 방식이나 비선형 재료 모델을 쓴다. 유한 요소법의 수학은 계산 과학 노트에 있고, XPBD도 사면체 FEM 에너지를 제약으로 바꿔 풀 수 있다.

소성과 파괴

소성은 탄성 한계(항복점)를 넘은 만큼 "쉬는 모양 자체"를 옮겨 적는 것이다. 철판이 찌그러진 채로 남는 이유다. 시뮬레이션에서는 요소의 변형이 항복값을 넘으면 그 초과분만큼 쉬는 길이나 쉬는 모양을 갱신한다. 파괴는 변형이나 제약 힘(XPBD의 λ)이 한계를 넘을 때 제약을 지우거나 메시를 쪼개는 것이다. 재료가 왜 그렇게 행동하는지는 재료과학 노트에, 게임에서 미리 잘라 둔 보로노이 조각으로 파괴를 연출하는 방법은 게임 개발 › 물리에 있다.

탄성, 항복, 소성 변형, 영구 변형, 파괴로 이어지는 응력-변형률 경로0.00.10.20.30.4변형률(늘어난 비율)응력항복① 탄성② 소성: 쉬는 길이가 옮겨 간다③ 영구 변형 0.15④ 파괴(변형률 0.40)0 → 0.25 당김 → 0.15까지 놓음 → 다시 당김 · 소성 변형이 0.3을 넘으면 끊긴다
완전 소성 막대 하나의 응력-변형률 경로(계산값). 항복까지는 원래대로 돌아오지만, 넘으면 쉬는 길이가 옮겨 가 힘을 빼도 영구 변형이 남고, 소성 변형이 한계를 넘으면 끊어진다.

격자 유체: Stable Fluids

Jos Stam의 Stable Fluids(SIGGRAPH 1999)는 그때까지 불안정해 실시간에 쓰기 어렵던 유체 풀이를 "어떤 시간 간격에서도 터지지 않게" 만들었다. 방정식을 항별로 쪼개 한 걸음에 차례로 적용한다. 힘 더하기 → 이류 → 확산 → 압력 투영이다. 게임 개발자용으로 짧은 코드와 함께 다시 쓴 글이 Real-Time Fluid Dynamics for Games(GDC 2003)다.

확산: 암시적으로 푼다

확산은 각 칸이 이웃과 값을 나누는 과정이다. 명시적으로 풀면 한 걸음에 이웃으로 넘기는 비율 a = ν·dt/dx²가 1/2을 넘는 순간 값이 칸마다 부호를 바꾸며 불어난다. Stam은 이를 "걸음이 끝난 뒤의 값으로 이웃과 나눈다"는 암시적 식으로 바꿔 풀었다(논문 코드에서는 가우스-자이델 반복, 아래 그림은 삼중 대각 행렬을 바로 푼 결과). 그러면 a가 아무리 커도 값이 음수가 되거나 불어나지 않는다.

명시적 확산은 큰 걸음에서 진동하며 터지고 암시적 확산은 큰 걸음에서도 매끈하게 퍼지는 비교처음최댓값 1.00명시적 a=0.4 ×30최댓값 0.38암시적 a=6 ×2최댓값 0.44명시적 a=0.6 ×20최댓값 0.66칸 0칸 39 · 양 끝은 벽명시적은 a ≤ 1/2일 때만 안정 · 암시적은 a가 커도 양수이고 총량이 그대로다
40칸 막대의 1차원 확산(계산값). 같은 총 확산량을 명시적 a = 0.4 서른 걸음과 암시적 a = 6 두 걸음으로 풀면 비슷한 결과가 나온다. 명시적 a = 0.6은 스무 걸음 만에 진동하며 터진다(그림 밖으로 잘림).

이류: 거슬러 올라가 읽는다

이류는 값을 흐름에 실어 옮기는 단계다. 칸의 값을 앞으로 밀어 보내는 대신, Stam은 준라그랑주(semi-Lagrangian) 방식으로 거꾸로 묻는다. "이 칸에 지금 도착한 물질은 dt 전에 어디 있었나?" 칸 중심에서 속도를 거슬러 따라가 그 자리의 옛 값을 이웃 칸에서 보간해 읽는다. 보간한 값은 이웃 값들 사이에 있으므로 새 최댓값이 옛 최댓값을 넘을 수 없고, 그래서 시간 간격이 커서 한 걸음에 여러 칸을 건너도 터지지 않는다. 대가는 보간할 때마다 조금씩 값이 뭉개지는 수치 확산이다. 연기가 금세 흐릿해지는 이유이고, 이를 줄이려고 고차 보간이나 MacCormack 같은 보정법, 뒤에 나오는 FLIP을 쓴다.

준라그랑주 이류는 큰 걸음에서도 안정하지만 언덕이 뭉개지고 중앙 차분 명시적 이류는 진동하며 터지는 비교처음봉우리 1.00정답(20칸 이동)봉우리 1.00준라그랑주 C=0.5 ×40봉우리 0.54준라그랑주 C=2.5 ×8봉우리 0.83중앙 차분 C=0.5 ×40봉우리 2.48흐름 → 오른쪽 · 준라그랑주는 터지지 않지만 보간할 때마다 뭉개진다
1차원 주기 격자에서 언덕을 20칸 옮긴다(계산값). 준라그랑주는 쿠랑 수 0.5(한 걸음에 반 칸)로도 2.5로도 안정하지만 봉우리가 낮아진다. 같은 일을 중앙 차분 명시적 공식으로 하면 진동하며 불어난다.

압력 투영: 발산을 빼낸다

힘과 이류를 거친 속도장은 비압축 조건을 어긴다. 어떤 칸에는 들어오는 것보다 나가는 것이 많다. 투영은 각 칸의 발산을 재고, 이웃 칸과의 압력 차가 그 발산을 정확히 지우도록 하는 압력을 푸아송 방정식으로 구한 뒤, 압력 기울기를 속도에서 뺀다. 수학적으로는 어떤 속도장이든 "발산 없는 부분"과 "어떤 함수의 기울기"의 합으로 유일하게 쪼갤 수 있다는 헬름홀츠-호지 분해이고, 투영은 뒤의 것을 버리는 일이다. 압력은 보통 가우스-자이델이나 야코비 반복, 큰 격자에서는 전처리 켤레 기울기법이나 다중 격자법으로 푼다. 아래 그림은 Bridson의 강의 노트가 권하는 엇갈린(MAC) 격자로 계산했다. 속도를 칸 면에, 압력을 칸 중심에 두면 칸을 드나드는 양을 바로 잴 수 있다.

퍼져 나가며 도는 속도장에서 압력 투영으로 발산 성분을 빼면 도는 흐름만 남는 모습과 반복 횟수별 남은 발산투영 전투영 후(200번 반복)→남은 발산(RMS) 0번 2.7e+0 · 5번 3.8e-1 · 20번 2.7e-2 · 50번 1.7e-3 · 200번 1.1e-9벽에 수직인 속도는 0 · 화살표는 칸 중심 속도(양옆 면의 평균)
8×8 엇갈린 격자에서 퍼져 나가며 도는 속도장(왼쪽)을 투영하면 퍼져 나가는 성분이 빠지고 벽 안에서 도는 흐름만 남는다(오른쪽, 계산값). 아래 숫자는 반복 횟수별 남은 발산이다. 반복을 아끼면 물이 조금씩 줄거나 불어난다.

SPH: 입자로 푸는 유체

SPH(smoothed particle hydrodynamics)는 유체를 입자 구름으로 보고, 어떤 점의 값을 근처 입자 값의 가중 평균으로 정한다. 가중치를 주는 함수가 커널 W(r, h)로, 거리 r이 반경 h를 넘으면 0이 되고 3차원 공간에서 적분하면 1이다. 입자 i의 밀도는 ρi = Σ mj·W(|xi − xj|, h), 압력은 상태 방정식 p = k(ρ − ρ0)로 밀도가 쉬는 밀도 ρ0보다 높으면 밀어 내는 값이 된다. 간격 1인 고른 격자에 질량 1인 입자를 놓고 h = 2인 poly6 커널로 재면 밀도가 1.010로, 정답 1에 가깝게 나온다.

Müller, Charypar, Gross의 Particle-Based Fluid Simulation for Interactive Applications(SCA 2003)는 용도마다 커널을 달리 쓰는 실시간 SPH를 제시했다. 밀도에는 거리 제곱만으로 계산되는 poly6, 압력에는 spiky, 점성에는 라플라시안이 늘 양수인 별도 커널이다. 이유는 아래 그림의 오른쪽에 있다. poly6의 기울기는 가운데에서 0이라, 입자가 겹칠수록 오히려 밀어 내는 힘이 사라져 입자가 뭉친다. spiky는 가까울수록 더 세게 민다.

poly6와 spiky 커널의 값과 기울기 모양 비교. poly6 기울기는 가운데에서 0이고 spiky 기울기는 가운데에서 가장 크다값 W(r): 밀도 합에 쓴다0r = h기울기 |∇W|: 압력 힘에 쓴다0r = hpoly6 봉우리 r = h/√5spiky: 가까울수록 더 세게 민다poly6: 겹치면 오히려 0poly6 = 315/(64πh⁹)·(h²−r²)³spiky = 15/(πh⁶)·(h−r)³
poly6와 spiky 커널의 값(왼쪽)과 기울기 크기(오른쪽). 각 곡선을 자기 최댓값으로 나눠 모양만 비교했다(계산값, h = 1). 두 커널의 3차원 적분이 1인지는 테스트가 확인한다.

SPH는 튀는 물, 물보라처럼 표면이 쪼개지는 장면에 강하고 경계 처리가 자연스럽다. 약점은 비압축이 근사라는 점이다. 상태 방정식의 k를 키우면 덜 눌리지만 강성 문제가 다시 생겨 dt가 작아진다. 그래서 반복으로 밀도를 맞추는 PCISPH, IISPH, DFSPH 같은 변형과, 밀도 조건을 PBD 제약으로 바꾼 위치 기반 유체가 나왔다. 이웃 찾기는 셀 크기 h인 공간 해시 격자로 한다. Macklin 외의 Unified Particle Physics(2014)는 천, 강체, 유체, 로프를 모두 같은 입자와 PBD 제약으로 풀어 서로 섞이게 했다.

FLIP/PIC와 MPM: 입자와 격자를 섞는다

격자는 압력 풀이에 좋고, 입자는 이류에 좋다. PIC(particle-in-cell)는 둘을 합친다. 입자가 속도를 들고 다니다가, 매 걸음 근처 격자로 속도를 옮기고(가중 평균), 격자에서 힘과 압력을 풀고, 다시 입자로 속도를 가져온다. 문제는 옮길 때마다 평균을 내니 작은 소용돌이가 사라진다는 것이다. FLIP(fluid-implicit-particle)은 격자의 새 속도를 그대로 가져오지 않고, 격자에서 "바뀐 만큼"만 입자 속도에 더한다. Zhu와 Bridson의 Animating Sand as a Fluid(SIGGRAPH 2005)가 이를 그래픽스의 비압축 유체에 가져왔고, 지금 영화의 물 시뮬레이션 상당수가 이 계열이다.

입자와 격자 사이를 오갈 때 PIC는 운동 에너지를 잃고 FLIP은 지키는 비교00.51FLIP 100% 100%FLIP 95% 53%PIC 5%운동 에너지(처음 = 1)0입자 → 격자 → 입자 8번PIC: 격자 속도를 그대로 가져온다 · FLIP: 입자 속도에 격자 속도의 변화량만 더한다
입자 48개의 속도를 16칸 격자로 옮겼다 되가져오기를 여덟 번(계산값). 격자에서 아무 일도 하지 않았으니 바른 답은 에너지 그대로다. PIC는 첫 번에 벌써 크게 잃고, FLIP은 그대로다. 순수 FLIP은 잡음이 쌓이기 쉬워 실무에서는 PIC를 조금 섞는다.

이 실험에서 PIC는 한 번 옮긴 것만으로 운동 에너지의 13%만 남는다. 실제 장면에서는 격자 해상도에 비해 입자가 많고 속도장이 매끄러워 이렇게 극적이지 않지만, 방향은 같다. 그래서 FLIP 95% + PIC 5%처럼 섞어 잡음과 감쇠 사이에서 균형을 잡고, 각운동량을 보존하도록 고친 APIC 같은 변형도 쓴다.

MPM(material point method)은 같은 입자-격자 구조에 연속체 역학을 얹는다. 입자가 속도뿐 아니라 변형 기울기(얼마나 늘고 비틀렸는지)를 들고 다니고, 격자에서 응력을 계산한다. 탄성, 소성, 파괴를 한 틀에서 다룰 수 있어 눈, 모래, 진흙, 반죽처럼 고체와 액체 사이의 재료에 강하다. Stomakhin 외의 A Material Point Method for Snow Simulation(SIGGRAPH 2013)이 그래픽스에서 MPM을 널리 알린 논문이다. 격자가 자기 충돌과 쪼개짐을 자동으로 처리해 주는 대신 계산이 무거워 아직은 주로 오프라인 VFX에서 쓴다.

물 표면, 연기, 불

얕은 물과 높이장 파도

호수나 웅덩이처럼 수면만 보이면 3차원 유체를 풀 필요가 없다. 수면을 2차원 격자의 높이장으로 두고, 각 칸의 높이가 이웃 평균으로 끌려가는 파동 방정식을 풀면 물결이 퍼지고 벽에서 되돌아온다. 칸마다 높이와 수직 속도만 들고 있어 GPU에서 수십만 칸을 매 프레임 돌릴 수 있다. 쿠랑 수 c·dt/dx가 1을 넘으면 터진다는 조건만 지키면 된다. 높이 대신 칸 사이의 물 흐름까지 다루는 얕은 물 방정식은 물이 흘러 넘치는 장면에 쓴다. 게임에서 이런 물결을 렌더링하는 연출은 게임 개발 › 이펙트의 수면 물결 절에 있다.

가운데 솟은 물이 두 파도로 갈라져 퍼지고 벽에서 반사되는 1차원 높이장 시뮬레이션 스냅숏0걸음30걸음60걸음90걸음120걸음물의 양(칸 높이 합) 5.000 → 5.000 · 양 끝은 벽
1차원 높이장 물(계산값). 가운데 솟은 물이 두 파도로 갈라져 퍼지고, 벽에 닿아 되돌아온다. 칸 높이의 합(물의 양)은 걸음마다 정확히 보존된다.

FFT 바다(Tessendorf)

넓은 바다는 시뮬레이션하지 않고 통계로 합성한다. Jerry Tessendorf의 강의 노트 Simulating Ocean Water는 바다 표면을 서로 다른 파장과 방향의 사인파 수만 개의 합으로 보고, 파장별 크기는 해양학의 관측 스펙트럼(필립스 스펙트럼 등)에서, 시간에 따른 움직임은 깊은 물의 분산 관계 ω = √(g·k)에서 가져온다. 긴 파도일수록 빠르다. 파장 10m 파도는 주기 2.53초, 속도 4.0m/s이고, 100m 파도는 12.5m/s로 달린다. 이 합을 FFT 한 번으로 계산하므로 수십만 개 성분도 프레임마다 다시 더할 수 있고, 결과는 이음매 없이 바둑판처럼 이어 붙일 수 있다. 노트 서문은 Waterworld와 Titanic의 바다를 이 계열 작업의 선구로 든다.

바람 속도에 따른 필립스 스펙트럼 곡선과 가장 센 파장, 파장별 깊은 물 파도 주기1m10m100m1000m5m/s · 23m10m/s · 91m15m/s · 204m깊은 물 주기 T = √(2πλ/g): 1m → 0.8초 · 10m → 2.5초 · 100m → 8.0초파장(로그 눈금)
바람 세기별 필립스 스펙트럼(각 곡선의 최댓값 = 1, 계산값). 바람이 두 배가 되면 가장 센 파도의 길이는 네 배가 된다. 10m/s 바람에서는 약 91m 파도가 가장 세다.

위 그림의 곡선은 방향 성분을 뺀 크기다. 실제로는 바람 방향과 나란한 파도만 살리는 방향 항을 곱하고, 수평으로 출렁이는 성분(뾰족한 물마루)과 파도 꼭대기의 거품을 더한다. 게르스트너 파도와 바다 렌더링 연출은 게임 개발 › 이펙트에 있다.

연기와 불

연기와 불은 Stable Fluids 격자 위에 스칼라장 몇 개를 더 실어 나른 것이다. 밀도(연기의 짙기), 온도, 연료를 같은 속도장으로 이류하고, 온도가 주변보다 높은 곳에 위로 향하는 부력을 준다. 수치 확산 때문에 사라지는 작은 소용돌이는 와도 가둠(vorticity confinement)으로 되살린다. 소용돌이의 중심을 찾아 그 둘레의 회전을 북돋는 가짜 힘이다. 불은 연료가 타며 열과 연기를 만들고 온도가 서서히 식는 규칙을 더하고, 렌더링 때 온도를 흑체 색으로 바꾼다.

격자 연기와 불 시뮬레이션의 한 프레임: 힘, 속도 이류, 압력 투영, 스칼라 이류, 반응과 식기힘 더하기부력 ∝ 온도 − 주변와도 가둠(소용돌이)바람, 폭발속도 이류속도장이 자기를실어 나른다압력 투영발산 0으로고친다스칼라 이류밀도, 온도, 연료를같은 속도로 옮긴다반응·식기연료 → 열·연기온도는 서서히 식는다한 프레임(속도장 u와 스칼라장 ρ·T·연료)렌더링: 밀도는 빛을 가리는 정도, 온도는 흑체 색으로 바꿔 볼륨 레이 마칭한다.게임에서는 낮은 해상도 격자로 돌리고 잔무늬는 노이즈와 텍스처로 덧칠한다.
격자 연기·불 한 프레임의 순서. 가운데 압력 투영이 가장 비싸다. 같은 틀에 넣는 장의 종류와 반응 규칙만 바꿔 연기, 불, 폭발을 만든다.

GPU 병렬화

격자 유체는 GPU와 궁합이 좋다. 칸마다 같은 계산을 하므로 칸 하나를 스레드 하나에 맡기면 된다. 이류는 칸마다 독립이고, 압력 풀이는 순서에 묶인 가우스-자이델 대신 이전 값만 읽는 야코비 반복을 쓴다. 수렴은 느리지만 수천 칸을 동시에 고칠 수 있어 결과적으로 빠르다. Mark Harris의 GPU Gems 38장은 압력에 야코비 반복을 수십 번 쓰도록 권한다.

PBD는 까다롭다. 두 제약이 같은 입자를 동시에 고치면 서로의 결과를 덮어쓴다. 해결책은 둘이다. 하나는 그래프 색칠로, 같은 입자를 공유하지 않는 제약끼리 묶어 한 묶음을 병렬로 풀고 묶음 사이에서만 순서를 지킨다. 다른 하나는 야코비식으로 각 제약의 수정량을 입자별로 더해 두었다가 개수로 나눠 한꺼번에 적용하는 것이다. 수렴은 느리지만 색칠이 필요 없다. 병렬 프로그래밍의 일반론은 병렬 프로그래밍과 HPC 노트, GPU 구조는 GPU 노트에 있다.

격자 천의 구조 스프링을 같은 점을 공유하지 않는 네 묶음으로 색칠한 그림묶음 1: 제약 15개묶음 2: 제약 14개묶음 3: 제약 12개묶음 4: 제약 8개묶음 하나를 한꺼번에(병렬) 풀고묶음 사이에서만 차례를 지킨다제약 49개 → 순서대로 49번 대신 4번의 병렬 단계
6×5 격자 천의 구조 스프링을 앞에서부터 탐욕 색칠하면 네 묶음이 된다(계산값). 같은 묶음끼리는 점을 공유하지 않으므로 묶음 하나를 GPU 스레드 여럿이 동시에 풀어도 안전하다.

SPH와 FLIP은 이웃 찾기가 병목이다. 입자를 공간 해시의 셀 번호로 정렬해 같은 셀 입자가 메모리에 붙어 있게 하면 캐시와 메모리 대역폭을 덜 쓴다. 격자로 입자 값을 옮기는 단계는 여러 입자가 같은 칸에 쓰므로 원자적 덧셈을 쓰거나, 칸 입장에서 주변 입자를 모아 읽는 방식으로 바꾼다.

게임의 속임수

게임에서 화면의 천과 물 대부분은 시뮬레이션이 아니다. 프레임 예산 16.7ms(60fps) 안에 렌더링, AI, 게임 물리까지 들어가야 하므로 "보는 사람이 차이를 모르는 가장 싼 방법"을 고른다. 시뮬레이션은 그 가운데 하나의 선택지다.

보이는 것흔한 속임수실제 시뮬레이션은 언제
망토, 치마, 깃발뼈대(본)를 몇 개 심어 애니메이션하거나, 뼈대마다 스프링을 단 "흔들림 본"으로 출렁임만 흉내 낸다주인공 옷처럼 화면을 오래 차지하고 몸과 닿는 경우. 그래도 몸에 붙은 부분은 애니메이션이 정한다
머리카락머리카락 다발 메시에 뼈대 사슬 몇 줄. 시뮬레이션은 뼈대 수십 개만낱가닥 렌더링을 하는 고사양 캐릭터. 가닥 일부만 풀고 나머지는 보간한다
폭발, 연기, 불미리 계산한 시뮬레이션을 텍스처 여러 장으로 구운 플립북을 파티클에 붙인다캐릭터가 지나가면 연기가 갈라지는 등 상호작용이 보여야 할 때. 낮은 해상도 3D 격자를 쓴다
바다, 호수정점 셰이더에서 사인파나 게르스트너 파도 몇 개를 더하거나, FFT 높이장 텍스처를 타일로 반복한다배가 만드는 물결, 물이 넘쳐 흐르는 장면. 근처만 높이장이나 얕은 물로 푼다
물 튀김, 피파티클과 데칼컷신이나 VFX 영상. 오프라인 FLIP이나 SPH를 돌려 메시나 캐시로 굽는다

이 표의 오른쪽 열에서도 "굽기(baking)"가 자주 나온다. VFX와 시네마틱에서는 몇 시간짜리 오프라인 시뮬레이션을 돌려 정점 애니메이션이나 볼륨 캐시로 저장하고, 게임 안에서는 그것을 재생만 한다. 실시간이 필요한 것은 플레이어의 입력에 반응해야 하는 부분뿐이다. 반응의 느낌(타격감, 흔들림)을 조절하는 이야기는 게임 개발 › 조작감에 있다.

흔한 오해

  • "시간 간격을 줄이면 무조건 정확해진다." 명시적 오일러는 dt를 줄여도 감쇠 없는 진동에서 에너지가 계속 는다. 늘어나는 속도가 느려질 뿐이다. 안정성은 dt만이 아니라 적분 방식과 강성의 조합으로 정해진다.
  • "암시적 적분은 정확하다." 암시적 오일러는 안정할 뿐 정확하지 않다. 큰 걸음에서는 에너지가 빠져 모든 것이 둔해지고, 그 감쇠를 재질의 성질로 착각하기 쉽다.
  • "PBD의 강성 값은 재료의 단단함이다." 원래 PBD의 강성은 반복 횟수와 시간 간격에 따라 효과가 달라진다. 반복 횟수를 성능 옵션으로 바꾸면 천의 재질이 바뀐다. 물리적 의미가 필요하면 XPBD의 컴플라이언스를 쓴다.
  • "유체 시뮬레이션은 나비에-스토크스를 정확히 푼다." 그래픽스의 유체는 수치 확산, 근사 압력, 낮은 해상도로 물리적으로 꽤 틀린 답을 낸다. 목표는 그럴듯한 움직임이고, 그래서 와도 가둠 같은 가짜 힘을 일부러 더한다. 공학용 전산 유체 역학(CFD)과는 목적과 검증 방식이 다르다.
  • "SPH 입자 하나가 물 분자 하나다." 입자는 물의 작은 덩어리를 대표하는 표본이다. 입자 수를 늘리면 해상도가 오를 뿐 분자 수준에 가까워지는 것이 아니다.
  • "게임의 물과 천은 다 시뮬레이션이다." 대부분은 뼈대 애니메이션, 플립북, 정점 셰이더 파도, 구운 캐시다. 실시간 시뮬레이션은 상호작용이 보여야 하는 곳에만 아껴 쓴다.
  • "반복을 더 돌리면 늘어남이 사라진다." 긴 사슬에서는 수정이 반복 한 번에 한 마디씩만 전해져 반복 비용 대비 효과가 낮다. 긴 거리 제약, 작은 걸음 쪼개기, 다중 격자처럼 구조를 바꾸는 편이 훨씬 싸다.

핵심 자료

강체와 충돌 응답은 게임 물리학 노트, 수치 적분과 유한 요소법은 계산 과학 노트, 벡터와 행렬은 게임 개발 수학 노트에 있다. 처음 직접 만들어 보려면 Ten Minute Physics의 천 예제와 Stam의 GDC 2003 글부터 따라 하는 것을 권한다.

자료종류요지링크
Ten Minute Physics강의 영상·예제PBD를 만든 Matthias Müller의 10분짜리 강의 모음. 천, 자기 충돌, 연체, 오일러 유체, FLIP 물, 높이장 물, 불까지 브라우저에서 돌아가는 짧은 JavaScript 예제와 함께 보여 준다.Matthias Müller
Fluid Simulation (SIGGRAPH 2007 Course Notes)무료 강의 노트Bridson과 Müller-Fischer의 강의 노트. MAC 격자, 이류, 압력 투영, 표면 추적, 높이장 근사까지 그래픽스 유체의 표준 입문서다.UBC (PDF)
Stable Fluids논문(1999)Jos Stam. 준라그랑주 이류와 압력 투영으로 시간 간격과 상관없이 터지지 않는 유체 풀이를 처음 제안했다.University of Toronto (PDF)
Real-Time Fluid Dynamics for Games발표 논문(GDC 2003)Stable Fluids를 게임 개발자용으로 줄인 글. 2차원 밀도·속도 풀이를 짧은 C 코드로 처음부터 끝까지 보여 준다.University of Toronto (PDF)
Position Based Dynamics논문(2006)Müller 외. 힘 대신 위치를 직접 제약에 맞춰 고치는 방법. 예측, 제약 투영, 속도 갱신의 틀과 반복 횟수 보정이 여기서 나왔다.Matthias Müller (PDF)
XPBD: Position-Based Simulation of Compliant Constrained Dynamics논문(2016)Macklin 외. 제약마다 라그랑주 승수와 컴플라이언스를 두어 강성이 반복 횟수와 시간 간격에 끌려가지 않게 했다.Matthias Müller (PDF)
Simulating Ocean Water강의 노트Jerry Tessendorf. 게르스트너 파도, 분산 관계, 필립스 스펙트럼과 FFT로 바다 높이장을 만드는 방법. 영화와 게임 바다의 출발점이다.Clemson University (PDF)
Fast Fluid Dynamics Simulation on the GPU책 한 장(GPU Gems)Mark Harris. Stable Fluids를 프래그먼트 셰이더로 옮기고 압력을 야코비 반복으로 푸는 법. GPU 유체의 고전이다.NVIDIA Developer
University Physics Volume 1, 14장 유체 역학무료 교과서밀도와 압력, 부력, 연속 방정식, 베르누이 방정식, 점성과 난류를 대학 교양 수준으로 다룬다. 이 노트의 물리 바탕이다.OpenStax