1. 2차원 공간의 회전
2차원 공간에서 회전은 원점을 기준으로 어떤 점을 θθ만큼 회전하는 것을 의미한다. 어떤 점 P(x,y)P(x,y)가 원점을 기준으로 a 만큼 회전된 상태라면 삼각함수를 이용하여 다음과 같이 나타낼 수 있다.(r은 원점과 P 사이의 거리로, 원의 반지름 역할을 한다.)
x=r∗cos(a),y=r∗sin(a)
이 상태에서 θ 만큼 추가로 회전한 점을 P′(x′,y′) 이라고 하면, 다음과 같이 표현할 수 있다.
x′=rcos(θ+a),y′=rsin(θ+a)
이제 이 식을 이용해서 P(x,y)를 P′(x′,y′) 으로 만들어 줄 수 있는 행렬을 구할 차례이다. 행렬 유도를 위해서는 삼각함수의 덧셈 정리가 필요하다. sin, cos의 덧셈 정리는 다음과 같다.
sin(x+y)=sin(x)cos(y)+cos(x)sin(y)
sin(x−y)=sin(x)cos(y)−cos(x)sin(y)
cos(x+y)=cos(x)cos(y)−sin(x)sin(y)
cos(x−y)=cos(x)cos(y)+sin(x)sin(y)
이제 x′을 정리해보자.
x′=r∗cos(θ+a)
=r∗(cos(θ)sin(a)−sin(θ)sin(a))
=r∗cos(θ)sin(a)−r∗sin(θ)sin(a)
=x∗cos(θ)−y∗sin(θ)
같은 방식으로 y′을 정리해준다.
y′=r∗sin(θ+a)
=r∗(sin(θ)cos(a)+cos(θ)sin(a))
=r∗sin(θ)cos(a)+r∗cos(θ)sin(a)
=x∗sin(θ)+y∗sin(a)
이제 이 두 식을 정리하면 다음과 같이 점 P를 θ 만큼 회전 시키는 행렬을 만들 수 있다.
(x′y′)=(xy)(cos(θ)−sin(θ)sin(θ)cos(θ))
2. 3차원 공간의 회전
3차원 공간에서 회전을 하기 위해 필요한 것은 회전축과 회전 각도이다. 이는 곧 회전축을 나타내는 벡터와 회전 각도를 알고 있으면 3차원 공간에서 회전이 가능하다는 것과 같다.(쿼터니언은 다루지 않음)

위의 그림에서 회전축은 유닛 벡터인 n이고, 회전하려고 하는 점은 벡터로 표현된 V 이다. V가 회전축 n에 대하여 θ 만큼 회전한 벡터인 Rn(V) 를 구하는 방법은 그림에서 나타난 projn(V) 벡터와 Rn(V⊥) 벡터를 더하면 된다. 이제 이 두 벡터를 구하는 방법을 알아볼 것이다.
먼저 회전 시키고 싶은 벡터인 V를 n에 투영하여 projn(V)를 얻을 수 있다. n과 V의 내적값에 n을 곱해주면 projn(V)를 얻을 수 있다.
projn(V)=n∗(V⋅n)
그리고 V−projn(V)를 하면 V⊥ 를 구할 수 있다. V⊥는 회전을 위한 평면을 정의하기 위해 사용되는 벡터로, 평면을 정의하기 위해서는 다른 벡터 하나를 더 구해야 한다. 이때 사용할 수 있는 벡터가 바로 n과 V를 외적한 n×V 다. n×V는 n 과 V 모두에게 수직이므로, 앞에서 구한 V⊥와도 수직 상태를 유지한다.
이제 V⊥와 n×V를 이용해 2차원 평면을 정의할 수 있다.(우측의 그림) 만약 이 두 벡터의 크기가 같다면, 그림과 같이 2차원 원 위에서 점을 이동하는 것과 동일한 방식을 적용할 수 있을 것이다. 다행히 V⊥와 n×V의 크기는 같다. 그 이유는 다음과 같다.
- n은 단위 벡터로 크기가 1이다.
- 외적은 두 벡터를 이용해 만들 수 있는 평행사변형의 넓이와 같다. 따라서 |n×V|=|n|∗|V|∗sin(α)이며,
|n|=1이기 때문에 |n×V|=|V|∗sin(α)와 같다. - 삼각함수를 이용해 V⊥의 크기를 구하면 |V⊥|=sin(α)|V| 임을 알 수 있다.
- 따라서 |n×V|=|V|∗sin(α)=|V⊥| 다.
2차원 평면에서 θ 만큼 회전한 벡터를 Rn(V⊥)라 할 때, 이 벡터의 크기는 앞에서 구한 V⊥와 같은 것을 알 수 있다. 따라서 Rn(V⊥)에서 각각 V⊥와 n×V로 수선의 발을 내리면 사각형이 만들어지는데, 이 사각형의 너비와 높이를 나타내는 벡터를 구해 더해주면 Rn(V⊥)를 구할 수 있게 된다.(r을 원의 반지름이라고 취급하자. 실제로는 V⊥의 크기다.)
w=cos(θ)|V⊥|
V⊥|V⊥|∗w=V⊥|V⊥|∗cos(θ)|V⊥|=V⊥∗cos(θ)
h=sin(θ)|n×V|
n×V|n×V|∗h=n×V|n×V|∗sin(θ)|n×V|=n×V∗sin(θ)
Rn(V⊥)=V⊥∗cos(θ)+n×V∗sin(θ)
이제 우리가 원하는 모든 벡터를 구했다. 앞에서 구한 projn(V)와 Rn(V⊥)를 더해주면 n을 회전축으로 사용하여 θ 만큼 회전한 Rn(V) 를 구할 수 있게 된다.
Rn(V)=projn(V)+Rn(V⊥)
회전 행렬을 유도하기 위해 위의 식을 전개하면 다음과 같이 정리할 수 있다.
Rn(V)=projn(V)+Rn(V⊥)
=(n⋅v)n+V⊥∗cos(θ)+(n×V)∗sin(θ)
=(n⋅v)n+(v−(n⋅v)n)∗cos(θ)+(n×V)∗sin(θ)
=cos(θ)v+(1−cos(θ))(n⋅v)n+(n×V)∗sin(θ)
이 식에 x, y, z 각 축을 나타내는 표준 기저 벡터를 넣어 계산하면 최종적으로 다음과 같은 형식의 회전 행렬을 만들 수 있다.
n=(x,y,z),c=cos(θ),s=sin(θ)
Rn=[c+(1−c)x2(1−c)xy+sz(1−c)xz−sy(1−c)xy−szc+(1−c)y2(1−c)yz+sx(1−c)xz+sy(1−c)yz−sxc+(1−c)z2]
위 행렬은 x, y, z 축에 대한 회전을 한 번에 처리하는 행렬이기 때문에 각 축에 대해서만 회전을 하고 싶다면 x축 (1,0,0), y축 (0,1,0), z축 (0,0,1)의 표준 기저 벡터를 입력하면 된다. 이렇게 해서 나온 결과 행렬은 2차원 회전의 식과 매우 유사한 모습을 가지고 있다.
'그래픽스 > DirectX11' 카테고리의 다른 글
쉐이더 리소스 뷰(ID3D11ShaderResourceView) 사용하기 (0) | 2024.06.11 |
---|---|
조명 (0) | 2024.05.08 |
노멀 벡터 변환 (0) | 2024.05.08 |
쉐이더 만들기(버텍스, 픽셀) (0) | 2024.04.22 |
버텍스 버퍼, 인덱스 버퍼, 컨스턴트 버퍼 (0) | 2024.04.22 |