에듀테크 프로젝트 대시보드
2D 변환 행렬 (Transformation Matrix)
게임·그래픽 엔진은 도형을 옮기고(이동), 돌리고(회전), 늘이고(크기), 비트는(전단)
일을 끝없이 한다. 이 모든 변환을 딱 한 개의 3×3 행렬로 표현하고, 점 하나에 그 행렬을 곱하기만 하면
변환된 위치가 나온다. 비결은 동차좌표(homogeneous coordinates) — 점 (x, y)를 (x, y, 1)로 한 칸
늘려서, 곱셈만으로는 안 되던 “이동”까지 행렬 곱 하나에 태우는 것이다.
여러 변환은 행렬을 미리 곱해서 하나로 합쳐 두면 (M = T · R · S) 점 수백만 개도 같은 행렬 한 번씩만 곱하면 된다.
아래에서 슬라이더를 움직여 M 이 실시간으로 어떻게 바뀌는지 확인해 보자.
| 변환 | 3×3 행렬 (동차좌표) | 점 (x, y)에 미치는 효과 |
|---|---|---|
| 이동 T(tx, ty) | [1 0 tx] [0 1 ty] [0 0 1] | x' = x + tx, y' = y + ty — 세 번째 열이 없으면 표현 불가 |
| 크기 S(sx, sy) | [sx 0 0] [0 sy 0] [0 0 1] | 원점 기준 확대/축소. s<0 이면 축 반사(거울상) |
| 회전 R(θ) | [cosθ −sinθ 0] [sinθ cosθ 0] [0 0 1] | 원점을 중심으로 반시계 방향 θ 회전. 행렬식 = 1 (넓이 보존) |
| 전단 Sh(k) | [1 k 0] [0 1 0] [0 0 1] | y가 클수록 x를 더 밀어 기울임 (이탤릭체 글꼴이 이 변환) |
M = C · B · A (오른쪽부터 점에 닿는다).[0 0 1] 인 행렬. 직선은 직선으로, 평행은 평행으로 유지된다.T(p) · R(θ) · T(−p) — 원점으로 당겨와 돌리고 되돌린다.M-1 로 되돌린다. 회전의 역은 전치(RT), 크기의 역은 1/s.model · view · projection 행렬. 정점 셰이더가 매 정점마다 이 곱을 한다.import math def mat_mul(A, B): # 3x3 · 3x3 return [[sum(A[i][k]*B[k][j] for k in range(3)) for j in range(3)] for i in range(3)] def translate(tx, ty): return [[1,0,tx],[0,1,ty],[0,0,1]] def scale(sx, sy): return [[sx,0,0],[0,sy,0],[0,0,1]] def rotate(deg): c, s = math.cos(math.radians(deg)), math.sin(math.radians(deg)) return [[c,-s,0],[s,c,0],[0,0,1]] # 이동 → 회전 → 크기 순으로 적용: M = T · R · S M = mat_mul(translate(120, 40), mat_mul(rotate(30), scale(1.5, 1.5))) def apply(M, x, y): return (M[0][0]*x + M[0][1]*y + M[0][2], # z=1 이라 마지막 열이 그대로 더해짐 M[1][0]*x + M[1][1]*y + M[1][2]) pts = [apply(M, x, y) for x, y in polygon] # 정점 전부에 같은 M 한 번씩 # canvas 2D: ctx.setTransform(a, b, c, d, e, f) 도 결국 이 3x3 (마지막 행 고정)