회전 후 이동과 이동 후 회전은 다르다
Transformations와 이동 변환 노트에는 행렬 그림과 GLM 조각이 있다. 이미지의 수식을 복제하지 않고 2D 점을 동차 좌표로 확장해 순서를 계산한다. 3D의 4×4 행렬도 같은 원리다.
이 글은 열벡터를 오른쪽에 놓는 규약이다. p' = T R S p는 S, R, T 순서다. 행렬을 메모리에 행 우선으로 저장하는 것과 수학적으로 행벡터를 쓰는 것은 별개다. 코드의 저장 방식만 보고 곱셈 순서를 뒤집지 않는다.
점과 방향에 마지막 성분을 붙이는 이유
점은 (x,y,1), 방향은 (dx,dy,0)으로 나타낸다. 아래 이동 행렬을 곱하면 점에는 이동량이 더해지고 방향에는 더해지지 않는다.
이 추가 성분은 동차 좌표를 위한 수학적 표현이다. 실제 월드가 공간 축 네 개를 갖는다는 뜻은 아니다. 3D의 평행이동은 원래 3D 벡터 공간에서 원점을 보존하는 선형변환이 아니며 아핀변환이다. 이를 동차 좌표로 확장하면 4×4 행렬 곱으로 표현할 수 있다. 노션의 ‘나머지 한 차원으로 이동한다’는 메모는 이 표현 방식으로 구분해 읽는다.
T = [1 0 tx] R(90°) = [0 -1 0] S = [sx 0 0]
[0 1 ty] [1 0 0] [ 0 sy 0]
[0 0 1] [0 0 1] [ 0 0 1]
회전은 x가 오른쪽, y가 위인 2D에서 반시계 90°로 정했다. Unity의 월드 yaw와 부호를 비교할 때는 먼저 기준축과 바라보는 방향을 맞춘다. GLM에서는 초기 행렬을 glm::mat4(1.0f)처럼 항등으로 명시해 미초기화 값에 기대지 않는다. GLM 행렬 변환 문서
직접 실행하기
다음을 matrix.mjs로 저장해 Node.js에서 실행한다. 배열은 읽기 쉽게 행 단위로 적었고, 함수는 수학적으로 행렬×열벡터를 계산한다.
const apply = (m, v) => m.map(row => row.reduce((s, n, i) => s + n * v[i], 0));
const T = [[1,0,2], [0,1,0], [0,0,1]];
const R = [[0,-1,0], [1,0,0], [0,0,1]];
const p = [1,0,1];
console.log('rotate then move', apply(T, apply(R,p)));
console.log('move then rotate', apply(R, apply(T,p)));
console.log('direction', apply(T, [1,0,0]));
rotate then move [ 2, 1, 1 ]
move then rotate [ 0, 3, 1 ]
direction [ 1, 0, 0 ]
첫 경우는 원점에서 회전한 점 (0,1)을 오른쪽으로 2 이동한다. 두 번째는 먼저 (3,0)이 된 점을 원점 주위로 회전한다. 위치가 다른 것은 계산 오류가 아니라 회전할 때의 위치가 다르기 때문이다.
실습과 풀이
- 점
(2,1)을 중심 c=(1,1) 주위로 90° 회전한다. 풀이:T(c) R T(-c) p를 사용한다. 중심을 빼면 (1,0), 회전하면 (0,1), 중심을 더하면 (1,2)다. 중심을 더하는 것만으로는 이 순서가 되지 않는다. - x를 2배 늘리는 S와 90° 회전의 순서를 바꾼다. 풀이: p=(1,0)일 때 RSp=(0,2), SRp=(0,1)이다. 비균일 스케일과 회전은 일반적으로 교환되지 않는다.
- 방향에 w=1을 잘못 붙인다. 풀이: 이동량까지 더해져 방향이 바뀐다. 또한 비균일 스케일 아래의 법선은 일반 방향과 달라 역전치 행렬과 정규화를 검토해야 한다.
프로젝트 연결과 확인 범위
2026년 10월 17일 본문의 JavaScript를 추출해 Node.js 24.15.0에서 실행했고, 표시한 입력의 출력과 일치했다. 이 확인은 독립 수치·응답 모델의 해당 예제 입력을 대상으로 한다.
장비 소켓·캐릭터 자식 객체에서 로컬 기준과 월드 기준을 구분할 때 같은 계산이 필요하다. 여기서는 DCB의 Transform을 교체하지 않았다. 원문과 LearnOpenGL Transformations를 대조했고 수치 코드를 새로 구성했다. GLM C++ 빌드·GPU 출력·비균일 스케일 법선 화면은 미검증이다. 작성에 AI를 사용했다.
이어 읽기
전체 학습 순서 · 다음 글: 카메라의 기준축과 LookAt 행렬 만들기