← 목록으로
컴퓨터 속 수학 · 게임 그래픽스

게임 속 세계를 수학으로 그리는 방법

Rendering worlds with a handful of formulas.

게임 속 산맥은 손으로 그린 게 아닙니다 — 노이즈 함수가 빚어냈죠. 구름은 워리·펄린 노이즈, 바다는 사인의 합거스너 파, 3D 미로는 레이 캐스팅이 그립니다. 그래픽 밖에서도 — 실력을 숫자로 바꾸는 ELO 레이팅까지. 게임이라는 가짜 세계가 사실은 몇 개의 공식으로 서 있다는 이야기, 직접 만지며 봅니다.

1펄린 노이즈 — 지형을 빚다

산맥의 높낮이를 만들려면 "부드럽게 울퉁불퉁한 무작위 값"이 필요합니다. 그냥 난수를 뿌리면 지직거리는 노이즈일 뿐이라 지형이 안 되죠. 1983년 켄 펄린이 〈트론〉 작업 중 만든 펄린 노이즈가 답이었습니다(1997년 아카데미 기술상까지 받았죠).

핵심 아이디어: 격자의 각 꼭짓점에 무작위 방향(그래디언트) 화살표를 심고, 임의의 점에서는 네 꼭짓점의 화살표와 "얼마나 방향이 맞는지"를 부드러운 곡선(\(6t^5-15t^4+10t^3\))으로 섞습니다. 값이 격자마다 \(0\)을 지나며 이어져 매끄러운 언덕이 되죠. 여기에 주파수를 2배씩, 진폭을 절반씩 겹쳐 쌓으면(옥타브, fBm) 큰 산에 잔봉우리가 얹힌 진짜 지형이 나옵니다:

\[ \text{fBm}(p) \;=\; \sum_{o=0}^{n-1} \tfrac{1}{2^{o}}\,\text{noise}(2^{o}p). \]

절차적 지형 — 옥타브를 쌓아 산을 만들기

옥타브 = 1 규모 = 4.0
색은 높이 — 바다·모래··바위·눈. 옥타브 \(1\)은 밋밋한 언덕, 늘릴수록 디테일이 프랙탈처럼 얹힙니다. 마인크래프트·〈노 맨즈 스카이〉의 무한 지형이 바로 이 원리예요.

2구름 — 워리 노이즈와 펄린 fBm

구름도 노이즈지만 결이 다릅니다. 뭉게구름은 펄린 fBm에 절댓값을 씌운 "난류(turbulence)"로 몽글몽글하게, 양떼구름·비늘구름은 워리 노이즈로 세포처럼 만듭니다.

워리 노이즈(1996, 스티븐 워리)는 발상이 귀여워요 — 공간에 점(특징점)을 흩뿌리고, 각 위치에서 가장 가까운 점까지의 거리를 값으로 씁니다. 점 근처는 \(0\), 점들 사이는 크고 — 결과는 보로노이 세포 무늬죠. 물결·비늘· 세포·크랙 텍스처가 전부 이 하나에서 나옵니다.

구름 생성기 — 노이즈 방식을 바꿔 보기

구름 양 = 50%
펄린 난류 \(\big|\text{fBm}\big|\)는 몽글한 뭉게구름, 워리 \(1-\)거리는 세포 같은 양떼구름. 임계값(구름 양)으로 하늘 대비 구름의 비율을 조절합니다.

3파도 — 사인의 합에서 거스너 파로

바다의 첫 근사는 사인파입니다. 하지만 사인파 하나는 너무 매끈해요. 그래서 진폭·파장·방향이 다른 사인파를 여러 개 더합니다(푸리에의 정신) — 이러면 제법 바다다워지죠:

\[ y(x,t) \;=\; \sum_i A_i \sin(k_i x - \omega_i t),\qquad \omega_i=\sqrt{g\,k_i}\ (\text{심해 분산관계}). \]

그런데 진짜 파도의 마루는 뾰족하고 골은 넓적합니다 — 사인은 위아래 대칭이라 이걸 못 내죠. 해법이 거스너 파(트로코이드 파): 물 입자가 위아래로만 움직이는 게 아니라 원을 그리게 만들어, 마루로 물을 몰아 뾰족한 봉우리를 세웁니다:

\[ x = x_0 - \sum_i Q_i A_i \sin(k_i x_0-\omega_i t),\qquad y = \sum_i A_i \cos(k_i x_0-\omega_i t). \]

파도 단면 — 사인 합 vs 거스너

가파름 Q = 70%
주황 점은 물 입자. 사인 합에선 위아래로만, 거스너에선 원을 그리며 돌아 마루가 뾰족해지는 걸 보세요. Q를 키우면 더 사나운 파도가 됩니다(\(Q\)가 너무 크면 마루가 말려 들어가 깨져요).

4레이 캐스팅 — 격자로 3D를 흉내내다

1992년 〈울펜슈타인 3D〉는 진짜 3D 엔진이 없던 시절, 2D 격자 지도만으로 3D를 그려 냈습니다. 비결이 레이 캐스팅 — 화면의 세로줄 하나하나마다 플레이어 눈에서 광선을 한 줄기씩 쏘아, 벽에 처음 닿는 거리를 재는 것입니다. 가까운 벽은 높게, 먼 벽은 낮게 그리면(벽 높이 \(\propto 1/d\), \(d\)=거리) 원근이 생기죠.

격자에서는 광선이 격자선을 넘는 순간만 검사하면 되므로(DDA 알고리즘) 아주 빠릅니다. 한 가지 함정 — 모든 광선의 거리를 그냥 쓰면 화면 가장자리가 볼록해지는 어안 왜곡이 생겨서, 시선 방향으로 사영한 "수직 거리"(\(d\cos\theta\))를 써야 벽이 평평해집니다.

미니 레이캐스터 — 걸어 다녀 보기

(화살표 키 · 뷰를 드래그해 둘러보기)
위는 1인칭 뷰(레이캐스팅 결과), 아래 작은 지도는 위에서 본 격자와 쏘아진 광선들. 광선 하나가 화면 세로줄 하나예요. 이 단순한 셈이 FPS 장르의 시작이었습니다.

5쿼터니언과 slerp — 짐벌락 없는 회전

3D 회전을 \(x,y,z\) 축 회전각(오일러 각)으로 다루면 두 축이 겹쳐 자유도를 잃는 짐벌락에 빠집니다. 게임은 대신 쿼터니언 \(q=w+xi+yj+zk\)(사원수, 4차원 단위수)로 회전을 담아요. 두 회전 \(q_A,q_B\) 사이를 부드럽게 이을 땐 slerp(구면 선형보간) — 4차원 구 위의 최단 호를 등속으로 따라갑니다:

\[ \text{slerp}(q_A,q_B;t)=\frac{\sin((1-t)\Omega)}{\sin\Omega}q_A+\frac{\sin(t\Omega)}{\sin\Omega}q_B,\quad \cos\Omega=q_A\!\cdot q_B. \]

카메라 전환, 캐릭터 애니메이션 블렌딩이 전부 이겁니다. (쿼터니언이 회전인지는 벡터를 곱한다는 것의 로터에서 다뤘어요.)

slerp — 두 자세를 등속으로 잇기

t = 0.00
좌표축 삼각대가 시작 자세에서 목표 자세로 slerp로 회전합니다. \(t\)를 고르게 움직이면 회전 속도도 고르게 — 선형보간(lerp)과 달리 중간에 빨라지거나 느려지지 않아요.

6베지어 곡선 — 부드러운 경로

애니메이션 커브, 카메라 경로, 폰트 윤곽, 포토샵 펜툴 — 전부 베지어 곡선입니다. 제어점 몇 개로 곡선을 정의하고, 드 카스텔조 알고리즘으로 그 위의 점을 찾죠: 제어점들을 잇는 선분을 비율 \(t\)로 나눈 점들을 잡고, 그 점들을 다시 \(t\)로 나누고… 반복하면 한 점으로 수렴합니다. 그 점이 곡선 위의 점이에요.

드 카스텔조 — 나누고 또 나누면 곡선이 된다

t = 0.50
네 제어점을 드래그하세요. 회색 선을 \(t\)로 나눠 가는 과정(초록→주황)이 한 점으로 모이고, 그 점의 자취가 파란 곡선입니다.

7충돌 판정 — 분리축 정리

"두 도형이 겹쳤나?"는 물리엔진의 핵심 질문. 볼록 도형이라면 분리축 정리(SAT)가 답합니다 — 두 도형을 어떤 축(방향)에 그림자로 사영했을 때 그림자가 안 겹치는 축이 하나라도 있으면, 두 도형은 안 겹친다. 검사할 축은 각 변의 법선들뿐이고요. 모든 축에서 겹치면 충돌 — 그중 가장 얕게 겹친 축이 서로를 밀어낼 방향(최소 이동 벡터)입니다.

SAT — 겹침과 밀어내기

도형을 드래그해 겹쳐 보세요
두 다각형을 드래그. 겹치면 빨갛게 변하고 주황 화살표가 "이만큼 밀면 떨어진다"는 최소 이동 벡터를 가리킵니다. 안 겹치면 분리축(점선)을 하나 찾아 보여줘요.

8천·밧줄의 물리 — 베를레 적분

깃발·망토·머리카락·밧줄은 질점을 막대(거리 제약)로 이은 것으로 흉내 냅니다. 움직임은 베를레 적분 — 속도를 따로 저장하지 않고 "이전 위치"만으로 관성을 냅니다(\(x_{\text{new}}=2x-x_{\text{old}}+a\,\Delta t^2\)). 그다음 막대 길이를 강제로 되돌리는 보정을 몇 번 반복하면 — 놀랍도록 안정적인 천이 됩니다. 구현이 짧고 안 터져서 게임의 단골이에요.

베를레 밧줄 — 잡아당겨 보기

밧줄의 점을 드래그
위 두 점은 고정(핀). 중력으로 늘어지고, 드래그하면 관성과 거리 제약이 실시간으로 풀립니다. 막대 제약을 여러 번 반복 적용하는 것만으로 "천"이 되죠.

9색을 속이다 — 디더링과 감마

색 단계가 부족하면 하늘 그라데이션에 줄무늬(밴딩)가 집니다. 디더링은 픽셀을 규칙적으로 섞어(베이어 행렬) 눈이 중간색으로 착각하게 만들어 줄무늬를 지워요. 게다가 모니터는 밝기를 비선형으로 내보내서(감마 \(\approx2.2\)), 빛·색 계산은 선형 공간에서 하고 마지막에 감마로 되돌려야 정확합니다 — 안 그러면 반투명· 블러·조명이 미묘하게 틀리죠.

밴딩 vs 디더링 · 감마 보정

감마 = 1.0
위 띠는 4단계로 줄인 그라데이션 — 밴딩 vs 디더링을 비교하세요. 아래 띠는 감마 슬라이더 — \(2.2\) 근처로 맞추면 두 회색을 섞은 중간이 진짜 중간 밝기로 보입니다.

10세계를 자동으로 짓다 — 절차적 생성

레벨을 손으로 안 짜고 알고리즘이 만듭니다(PCG). 미로는 격자를 그래프로 보고 깊이우선 탐색이나 프림 알고리즘으로 벽을 허물어 만들고, 던전은 공간을 반씩 쪼개는 BSP로 방을 배치하며, 물결 함수 붕괴(WFC)는 "이 타일 옆엔 이 타일만"이라는 이웃 규칙을 만족하는 배치를 제약충족으로 풉니다(스도쿠의 사촌이죠). 아래는 DFS로 미로가 자라나는 모습:

미로 생성 — 깊이우선 탐색

크기 = 12
한 칸에서 출발해 안 가 본 이웃으로 벽을 뚫고 나아가다, 막다르면 되돌아옵니다(백트래킹). 모든 칸을 정확히 한 번씩 잇는 신장 트리라 — 어느 두 칸 사이에도 길이 딱 하나예요.

11난수와 셔플의 함정

게임의 "무작위"는 사실 의사난수입니다(LCG·xorshift). 시드가 같으면 똑같이 재현돼서 — 리플레이·스피드런· 맵 시드가 가능하죠. 카드를 섞을 땐 피셔–예이츠라야 모든 순열이 균등하고(순진하게 "아무 둘이나 계속 바꾸기"는 편향됩니다). 그리고 가챠의 천장(pity) — 확률 \(p\)에 \(N\)번째 보장을 붙이면, 기대 뽑기 수가 \(1/p\)보다 확 줄어 최악의 불운을 막아 줍니다.

가챠 천장 — 확률과 기대의 셈

기본 확률 = 0.6% 천장 = 90
막대는 "정확히 \(k\)번째에 나올 확률" 분포 — 천장 \(N\)에서 확률이 몰려 쌓입니다. 천장이 있으면 기대 뽑기가 \(1/p\)보다 작아지고, "몇 번 안에 반드시"라는 보장이 생기죠.

12그래픽 밖에서 — ELO와 그 후예

수학은 화면만 그리는 게 아닙니다. 대전 게임의 실력 매칭도 공식이 합니다. 체스에서 온 ELO 레이팅은 "레이팅 차이가 승률을 정한다"는 한 줄에서 출발해요 — \(400\)점 앞서면 이길 확률이 약 \(91\%\):

\[ E_A \;=\; \frac{1}{1+10^{\,(R_B-R_A)/400}} \quad(\text{A의 기대 승률}). \]

경기 뒤엔 실제 결과와 기대의 차이만큼 점수를 주고받습니다 — \(R_A \leftarrow R_A + K\,(S_A - E_A)\) (\(S_A\): 이기면 \(1\), 지면 \(0\); \(K\): 변동폭). 기대보다 잘하면 오르고 못하면 내리며, 오래 두면 레이팅 차이가 실제 실력 차이로 수렴합니다.

ELO 시뮬레이터 — 실력이 숫자가 되기까지

A의 참실력 우위 = 0
두 선수의 레이팅(초록 A·주황 B)이 경기를 거치며 움직입니다. "참실력 우위"를 주면 — 레이팅 차이가 그 값 근처로 수렴하죠. 한 판씩은 요동치지만, 많이 둘수록 진짜 실력을 드러냅니다.
ELO의 후예 — Glicko와 TrueSkill
ELO의 약점은 "이 레이팅이 얼마나 믿을 만한지"를 모른다는 것입니다. 신규 유저와 만 판 둔 고수의 \(1500\)은 확신도가 전혀 다른데 똑같이 취급하죠. Glicko(마크 글리크먼)는 레이팅에 불확실성(RD)을 함께 추적하는 베이즈 추정으로 이걸 고쳤고 — 안 두면 RD가 커지고(자신 없어지고), 두면 좁아집니다. 마이크로소프트의 TrueSkill은 여기에 팀·다인전까지 확장해(각 실력을 정규분포로 두고 인수 그래프로 갱신) Xbox 매치메이킹의 엔진이 됐어요. 한 줄의 로그가 베이즈 추론으로 자란 셈입니다.

13맺으며

노이즈 함수가 산과 구름을, 삼각함수의 합과 트로코이드가 바다를, 광선 하나가 3D 미로를, 로그 한 줄이 실력의 서열을 그렸습니다. 거기에 쿼터니언이 카메라를 돌리고, 베지어가 길을 긋고, 분리축이 충돌을 잡고, 베를레가 천을 흔들고, 디더링이 색을 속이고, DFS가 미로를 짓고, 천장이 확률을 다독였죠. 게임이라는 가짜 세계는 — 알고 보면 수십 개의 공식이 매 프레임 계산되는 무대였던 겁니다.

여기 쓰인 수학의 뿌리가 더 궁금하다면 — 사인의 합으로 파형을 짓는 이야기는 수학이 울리는 소리, 회전·벡터의 대수는 벡터를 곱한다는 것, 게임을 "풀 수 있나"의 관점은 컴퓨터가 못 푸는 문제보드 게임 페이지로 이어집니다.


참고 자료