3차원 회전 변환 행렬 (유도하는 방법)
게임 프로그래밍을 포함한 3D 그래픽스에서 변환은 매우 중요한 개념이다. 최근에는 상용엔진이 많이 보급되어서 직접 변환값을 계산하지 않고 엔진에서 제공해주는 간단한 함수들 만으로도 원하는 위치에 원하는 회전상태와 크기로 물체를 출력할 수 있게됐다. 하지만 이 엔진들이 제공해주는 간단한 함수들의 내부에는 모두 변환이라는 개념을 포함하고 있기 때문에 엔진을 단순히 사용하는 것을 넘어서 그 원리를 이해하거나 혹은 상용엔진으로 부터 독립적인 3D그래픽을 만들고자 한다면 반드시 짚고 넘어가야할 내용이다.
대부분 수학에서는 벡터를 다룰때 열벡터를 사용하지만, 여기에서는 행벡터를 사용하고자 한다. 열벡터를 사용할 경우 수학으로 표기할때 가독성이 좋고, 행벡터로 표기할 경우 변환행렬들을 추상화 한 후 합성행렬을 구하는 과정에서 가독성이 높다. 원칙적으로는 열벡터를 사용하던지 행벡터를 사용하던지 하나의 방법을 일관적으로 사용한다면 문제되지 않는다.
이번 글에서는 변환 중에서도 상대적으로 복잡한 회전변환에 대한 설명과 공식 유도를 다뤄볼 예정이다. 회전 변환을 다루기에 앞서서 먼저 스케일 변환과 이동 변환을 정리하면 다음과 같다.
스케일 변환
2차원에서의 스케일 변환S(sx,sy)를 동차좌표계 행렬로 표현하면 다음과 같이 나타낼 수 있다. (3차원은 sz를 추가해서 4×4행렬로 표현 하면 된다.)
S(sx,sy)=(sx000sy0001)
(xy1)(sx000sy0001)=(sx⋅xsy⋅y1)
이동 변환
2차원에서 이동 변환T(tx,ty)를 동차 좌표계 행렬로 표현하면 다음과 같이 나타낼 수 있다. (3차원은 tz를 추가해서 4×4 행렬로 표현 하면 된다.)
T(a,b)=(100010txty1)
(xy1)(100010txty1)=(x+txy+ty1)
스케일 변환과 이동 변환, 동차좌표계에 대한 추가적인 설명이 필요하다면 이 글을 참고하자.
회전 변환
회전 변환은 이동변환이나 스케일 변환처럼 직관적이지 않아서 조금 구체적으로 다뤄볼 예정이다.
2차원에서 회전 변환
우선 2차원에서의 회전 변환을 먼저 살펴보자. 원래의 좌표가 (x,y)인 점 P가 있을때, 이 점을 θ만큼 회전한 점 P′의 좌표는 (x′,y′) 라고 하자. 원점에서 원래의 좌표 (x,y)에 선분을 그으면, 이 선분은 어떤 길이 r을 가지고 x축과 이루는 어떤 각도 ϕ를 가질 것이다.

이때 점 P의 x좌표와 y좌표를 r과 ϕ로 표현하면 다음과 같을 것이다.
x=rcosϕ y=rsinϕ
점 P를 θ만큼 회전한 점 P′의 x′좌표와 y′좌표를 r과 ϕ, θ로 표현하면 다음과 같다.
x′=rcos(ϕ+θ) y′=rsin(ϕ+θ)
이를 삼각함수의 덧셈 정리를 활용해서 풀어 쓸 수 있다. 참고로 삼각함수의 덧셈 정리는 다음과 같다.
cos(a+b)=cosacosb−sina sinb sin(a+b)=sinacosb+cosasinb
이를 x′,y′에 적용해 보자.
x′=(rcosϕ)cosθ−(rsinϕ)sinθ=xcosθ−ysinθ y′=(rcosϕ)sinθ+(rsinϕ)cosθ=xsinθ+ycosθ
이렇게 표현할 수 있다. 이를 동차행렬 식으로 정리 해보자.
(xy1)(cosθsinθ0−sinθcosθ0001)=(xcosθ−ysinθxsinθ+ycosθ1)
이렇게 2차원에서 회전에 대한 변환행렬을 θ에 대해서 정리할 수 있다.
R(θ)=(cosθsinθ0−sinθcosθ0001)
3차원에서 회전변환
2차원에서 회전 변환의 중심 원점이었다. 3차원에서의 회전 변환에서 회전 중심축은 x축, y축, z축 처럼 하나의 직선이다. 위에서 보인 2차원에서의 회전을 3차원 공간에서의 회전변환으로 확장해서 생각해볼 수도 있다. 사실 위에서 보인 회전은 아래와 같이 3차원 공간에서 z축을 중심으로 한 xy 평면에서의 회전과 동일하다. 그리고 z을 중심으로 회전을 진행했을 때 z축의 좌표는 변하지 않는다는 것도 살펴 볼 수 있다.

따라서 z축을 중심으로 회전변환을 2차원 xz평면상 회전변환에 z축 성분을 유지형태로 다음과 같이 이루어 진다는 것을 알 수 있다. 이를 수식으로 표현하면 다음과 같다.
x′=cosθ⋅x−sinθ⋅y+0⋅z y′=sinθ⋅x+cosθ⋅y+0⋅z z′=0⋅x+0⋅y+1⋅z
이를 행렬로 표현하면 다음과 같다.
(x′y′z′1)=(xyz1)(cosθsinθ00−sinθcosθ0000100001)
즉 Rz(θ)는 다음과 같이 표현할 수 있다.
Rz(θ)=(cosθsinθ00−sinθcosθ0000100001)
다음으로는 x축과 y축을 기준으로 회전변환 식을 유도해보겠다. y축을 기준으로 회전 변환을 한다는 것인 결국 z축을 기준으 회전변환을 하는 식에 y은 x값으로 x값은 z값으로 z값은 y값으로 전환하는 것과 동일하다.

이 그림을 식으로 나타내면 다음과 같다.
z′=cosθ⋅z−sinθ⋅x+0⋅y x′=sinθ⋅z+cosθ⋅x+0⋅y y′=0⋅z+0⋅x+1⋅y
위 식을 알파뱃 순서로 재배열하면 다음과 같다.
x′=cosθ⋅x+0⋅y+sinθ⋅z y′=0⋅x+1⋅y+0⋅z z′=−sinθ⋅x+0⋅y+cosθ⋅z
이를 행렬로 표현하면 다음과 같다.
(x′y′z′1)=(xyz1)(cosθ0−sinθ00100sinθ0cosθ00001)
즉, y축을 기준으로한 회전변환 Ry(θ)행렬은 다음과 같이 나타낼 수 있다.
(xyz1)Ry(θ)=(xyz1)(cosθ0−sinθ00100sinθ0cosθ00001)
같은 방식으로 x축을 기준으로 회전변환에 대해 계산하면 Rx(θ)를 다음과 같이 구할 수 있을 것이다.
(xyz1)Rx(θ)=(xyz1)(10000cosθsinθ00−sinθcosθ00001)
출처:
에이콘 출판 <Game Programming in C++>