1. 2차원 공간의 회전
2차원 공간에서 회전은 원점을 기준으로 어떤 점을 $\theta$만큼 회전하는 것을 의미한다. 어떤 점 $P(x, y)$가 원점을 기준으로 $a$ 만큼 회전된 상태라면 삼각함수를 이용하여 다음과 같이 나타낼 수 있다.($r$은 원점과 $P$ 사이의 거리로, 원의 반지름 역할을 한다.)
$$ x = r * cos(a), y = r * sin(a) $$
이 상태에서 $\theta$ 만큼 추가로 회전한 점을 $P'(x', y')$ 이라고 하면, 다음과 같이 표현할 수 있다.
$$ x' = rcos(\theta + a), y' = rsin(\theta + 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(\theta+a)$$
$$ = r*(cos(\theta)sin(a) - sin(\theta)sin(a)) $$
$$ = r*cos(\theta)sin(a) - r*sin(\theta)sin(a) $$
$$ = x*cos(\theta) - y*sin(\theta) $$
같은 방식으로 $y'$을 정리해준다.
$$ y' = r*sin(\theta + a) $$
$$ = r*(sin(\theta)cos(a) + cos(\theta)sin(a)) $$
$$ = r*sin(\theta)cos(a) + r*cos(\theta)sin(a) $$
$$ = x*sin(\theta) + y*sin(a) $$
이제 이 두 식을 정리하면 다음과 같이 점 $P$를 $\theta$ 만큼 회전 시키는 행렬을 만들 수 있다.
$$ \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} x & y \end{pmatrix} \begin{pmatrix} cos(\theta) & -sin(\theta) \\ sin(\theta) & cos(\theta) \end{pmatrix} $$
2. 3차원 공간의 회전
3차원 공간에서 회전을 하기 위해 필요한 것은 회전축과 회전 각도이다. 이는 곧 회전축을 나타내는 벡터와 회전 각도를 알고 있으면 3차원 공간에서 회전이 가능하다는 것과 같다.(쿼터니언은 다루지 않음)
위의 그림에서 회전축은 유닛 벡터인 $n$이고, 회전하려고 하는 점은 벡터로 표현된 $V$ 이다. $V$가 회전축 $n$에 대하여 $\theta$ 만큼 회전한 벡터인 $R_{n}(V)$ 를 구하는 방법은 그림에서 나타난 $proj_{n}(V)$ 벡터와 $R_{n}(V_{\perp})$ 벡터를 더하면 된다. 이제 이 두 벡터를 구하는 방법을 알아볼 것이다.
먼저 회전 시키고 싶은 벡터인 $V$를 $n$에 투영하여 $proj_n(V)$를 얻을 수 있다. $n$과 $V$의 내적값에 $n$을 곱해주면 $proj_n(V)$를 얻을 수 있다.
$$ proj_{n}(V) = n * (V \cdot n) $$
그리고 $V - proj_{n}(V)$를 하면 $V_{\perp}$ 를 구할 수 있다. $V_{\perp}$는 회전을 위한 평면을 정의하기 위해 사용되는 벡터로, 평면을 정의하기 위해서는 다른 벡터 하나를 더 구해야 한다. 이때 사용할 수 있는 벡터가 바로 $n$과 $V$를 외적한 $n \times V$ 다. $n \times V$는 $n$ 과 $V$ 모두에게 수직이므로, 앞에서 구한 $V_{\perp}$와도 수직 상태를 유지한다.
이제 $V_{\perp}$와 $n \times V$를 이용해 2차원 평면을 정의할 수 있다.(우측의 그림) 만약 이 두 벡터의 크기가 같다면, 그림과 같이 2차원 원 위에서 점을 이동하는 것과 동일한 방식을 적용할 수 있을 것이다. 다행히 $V_{\perp}$와 $n \times V$의 크기는 같다. 그 이유는 다음과 같다.
- $n$은 단위 벡터로 크기가 1이다.
- 외적은 두 벡터를 이용해 만들 수 있는 평행사변형의 넓이와 같다. 따라서 $|n \times V| = |n|*|V|*sin(\alpha)$이며,
$|n| = 1$이기 때문에 $|n \times V| = |V|*sin(\alpha)$와 같다. - 삼각함수를 이용해 $V_{\perp}$의 크기를 구하면 $|V_{\perp}| = sin(\alpha)|V|$ 임을 알 수 있다.
- 따라서 $|n \times V| = |V|*sin(\alpha) = |V_{\perp}|$ 다.
2차원 평면에서 $\theta$ 만큼 회전한 벡터를 $R_{n}(V_{\perp})$라 할 때, 이 벡터의 크기는 앞에서 구한 $V_{\perp}$와 같은 것을 알 수 있다. 따라서 $R_{n}(V_{\perp})$에서 각각 $V_{\perp}$와 $n \times V$로 수선의 발을 내리면 사각형이 만들어지는데, 이 사각형의 너비와 높이를 나타내는 벡터를 구해 더해주면 $R_{n}(V_{\perp})$를 구할 수 있게 된다.($r$을 원의 반지름이라고 취급하자. 실제로는 $V_{\perp}$의 크기다.)
$$ w = cos(\theta)|V_{\perp}| $$
$$ \frac{V_{\perp}}{|V_{\perp}|} * w = \frac{V_{\perp}}{|V_{\perp}|} * cos(\theta)|V_{\perp}| = V_{\perp}*cos(\theta) $$
$$ h = sin(\theta)|n \times V| $$
$$ \frac{n \times V}{|n \times V|} * h = \frac{n \times V}{|n \times V|} * sin(\theta)|n \times V| = n \times V * sin(\theta) $$
$$ R_{n}(V_{\perp}) = V_{\perp}*cos(\theta) + n \times V * sin(\theta) $$
이제 우리가 원하는 모든 벡터를 구했다. 앞에서 구한 $proj_{n}(V)$와 $R_{n}(V_{\perp})$를 더해주면 $n$을 회전축으로 사용하여 $\theta$ 만큼 회전한 $R_n(V)$ 를 구할 수 있게 된다.
$$ R_{n}(V) = proj_{n}(V) + R_{n}(V_{\perp}) $$
회전 행렬을 유도하기 위해 위의 식을 전개하면 다음과 같이 정리할 수 있다.
$$ R_{n}(V) = proj_{n}(V) + R_{n}(V_{\perp}) $$
$$ = (n \cdot v)n + V_{\perp}*cos(\theta) + (n \times V)*sin(\theta) $$
$$ = (n \cdot v)n + (v - (n \cdot v)n)*cos(\theta) + (n \times V)*sin(\theta) $$
$$ = cos(\theta)v + (1-cos(\theta))(n \cdot v)n + (n \times V)*sin(\theta) $$
이 식에 x, y, z 각 축을 나타내는 표준 기저 벡터를 넣어 계산하면 최종적으로 다음과 같은 형식의 회전 행렬을 만들 수 있다.
$$ n = (x, y, z), c = cos(\theta), s = sin(\theta) $$
$$ R_{n} = \begin{bmatrix} c + (1-c)x^{2} & (1-c)xy + sz & (1-c)xz - sy \\ (1-c)xy -sz & c + (1-c)y^{2} & (1-c)yz + sx \\ (1-c)xz + sy & (1-c)yz -sx & c + (1-c)z^{2} \end{bmatrix} $$
위 행렬은 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 |