CG理論 #3 変換 [Devlog #008]
Table of Contents
CG屋さんのバイブル:Real Time Rendering Fourth Edition を読んで理解したことについてを要約します(内容の転載を避け、詳しく説明しすぎないように配慮します)
変換
変換(transform)
線形変換はベクトル加算とスカラー乗算を保存するもの $$ \textbf{f}(\textbf{x}) + \textbf{f}(\textbf{y}) = \textbf{f}(\textbf{x}+\textbf{y}) $$ $$ k\textbf{f}(\textbf{x}) = \textbf{f}(k\textbf{x}) $$ これが満たされれば線形であるといえる
スケール変換や回転変換など、3要素ベクトルに対するすべての線形変換は3×3行列で表せる
線形変換は原点を不動点とする変換であり、原点は変換されずにそのままの位置に残る
3要素ベクトル $\textbf{x}$ への写像 $\textbf{f}(\textbf{x}) = \textbf{x} + (7, 3, 2)$ のような平行移動は線形ではない
平行移動は、原点の位置が変わるという特性がある
線形変換と平行移動の結合は、一般に4×4行列で格納されるアフィン変換を使って表す
同次表記は点と方向(ベクトル)を同じ形式で扱うことを可能にする
同次座標系では、 $n$ 次元空間における点を $n+1$ に拡張し、例えば3次元点 $(x,y,z)$ はベクトル $(x,y,z,1)$ と表現する
$$ \textbf{v} = \begin{pmatrix} x & y & z & 1\ \end{pmatrix}^T $$
方向(ベクトル)についても、$n$ 次元空間であれば $n+1$ に拡張し、3次元ベクトル $(v_x,v_y,v_z)$ はベクトル $(v_x,v_y,v_z,0)$ と表現する
$$ \textbf{v} = \begin{pmatrix} v_x & v_y & v_z & 0\ \end{pmatrix}^T $$
ここでの $0$ は、ベクトルが原点に固定されないことを示す
基本的な変換
平行移動
ある位置から別の位置への移動変化は ベクトル $\textbf{t}=(t_x,t_y,t_z)$ を用いて平行移動行列 $\textbf{T}$ で表される $$ \textbf{T}(\textbf{t}) = \textbf{T}(t_x,t_y,t_z) =\begin{pmatrix} 1 & 0 & 0 & t_x \\\ 0 & 1 & 0 & t_y \\\ 0 & 0 & 1 & t_z \\\ 0 & 0 & 0 & 1 \end{pmatrix} $$ 点 $\textbf{p}$ の平行移動の例: $$ \text{新しい点} \textbf{p}^\prime =\textbf{T}(\textbf{t})\textbf{p} =\begin{pmatrix} 1 & 0 & 0 & t_x \\\ 0 & 1 & 0 & t_y \\\ 0 & 0 & 1 & t_z \\\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} p_x \\\ p_y \\\ p_z \\\ 1 \end{pmatrix} =\begin{pmatrix} p_x+t_x \\\ p_y+t_y \\\ p_z+t_z \\\ 1 \end{pmatrix} $$
平行移動行列の逆行列は $\textbf{T}^{-1}(\textbf{t})=\textbf{T}(-\textbf{t})$ となり、ベクトル $\textbf{t}$ の符号反転になる
行列をメモリに格納する際の配置は表記法によって異なり、ここでは変換の順序が左から右になる列優先形式で表されている(OpenGLはこれ)(平行移動ベクトルが最右列)
一方、DirectXなどは右から左の順序で変換する行優先形式が使われる(平行移動ベクトルが最下行) $$ \text{新しい点} \textbf{p}^\prime =\textbf{p}\textbf{T}(\textbf{t}) =\begin{pmatrix} p_x & p_y & p_z & 1 \end{pmatrix} \begin{pmatrix} 1 & 0 & 0 & 0 \\\ 0 & 1 & 0 & 0 \\\ 0 & 0 & 1 & 0 \\\ t_x & t_y & t_z & 1 \end{pmatrix} $$ $$ =\begin{pmatrix} p_x+t_x & p_y+t_y & p_z+t_z & 1 \end{pmatrix} $$
以降、列優先(OpenGLと同じ形式)を考慮する
回転
回転変換は、ベクトル(位置や方向)を与えられた原点を通る軸の周りに与えられた角度で回転する
平行移動行列と同様に剛体変換である(点の間の距離と座標系の向きを保存する)
姿勢行列は、空間中の姿勢(カメラビューやオブジェクトの上と前の方向)を定義する回転行列である
2次元空間において、ベクトル $\textbf{v}=(v_x,v_y)$ があるとすると、 $$ \textbf{v}=(v_x,v_y)=(rcos(\theta),rsin(\theta)) $$ とパラメータ化できる
このベクトルを反時計回りに $\phi$ ラジアン回転することを考えると、 $$ \textbf{u} =\begin{pmatrix} rcos(\theta+\phi) \\\ rsin(\theta+\phi) \end{pmatrix} =\begin{pmatrix} r(cos\theta cos\phi-sin\theta sin\phi) \\\ r(sin\theta cos\phi+cos\theta sin\phi) \end{pmatrix} $$ $$ =\begin{pmatrix} cos\phi & -sin\phi \\\ sin\phi & cos\phi \end{pmatrix} \begin{pmatrix} rcos\theta \\\ rsin\theta \end{pmatrix} =\textbf{R}(\phi)\textbf{v} $$ と、うまいこと行列の計算に変換できる
これを3次元空間に拡張すると、 $x$ 軸、 $y$ 軸、 $z$ 軸の周りに $\phi$ ラジアン回転する回転行列を $\textbf{R}_x(\phi)$ 、 $\textbf{R}_y(\phi)$ 、 $\textbf{R}_z(\phi)$ と表すことができる
$$ \textbf{R}_x(\phi) =\begin{pmatrix} 1 & 0 & 0 & 0 \\\ 0 & cos\phi & -sin\phi & 0 \\\ 0 & sin\phi & cos\phi & 0 \\\ 0 & 0 & 0 & 1 \end{pmatrix} $$ $$ \textbf{R}_y(\phi) =\begin{pmatrix} cos\phi & 0 & sin\phi & 0 \\\ 0 & 1 & 0 & 0 \\\ -sin\phi & 0 & cos\phi & 0 \\\ 0 & 0 & 0 & 1 \end{pmatrix} $$ $$ \textbf{R}_z(\phi) =\begin{pmatrix} cos\phi & -sin\phi & 0 & 0 \\\ sin\phi & cos\phi & 0 & 0 \\\ 0 & 0 & 1 & 0 \\\ 0 & 0 & 0 & 1 \end{pmatrix} $$
最下行と最右列を削った3×3行列 $\textbf{R}$ のトレースは回転の角度 $\phi$ に関連している(剛体の回転運動の解析に使える) $$ \textbf{R} =\begin{pmatrix} r_{11} & r_{12} & r_{13} \\\ r_{21} & r_{22} & r_{23} \\\ r_{31} & r_{32} & r_{33} \end{pmatrix}, \quad tr(\textbf{R})=r_{11} + r_{22} + r_{33} = 1+2cos\phi $$
回転行列は直交し、行列式は1となる(回転変換をいくつ連結しても成り立つ)
回転行列の逆行列は、 $\textbf{R}_i^{-1}(\phi)=\textbf{R}_i(-\phi)$ となり、同じ軸での反対方向の回転となる
【点の周りの回転の例】
点 $\textbf{p}$ を回転の中心として、オブジェクトを $z$ 軸周りで $\phi$ ラジアン回転させる $$ \textbf{X}=\textbf{T}(\textbf{p})\textbf{R}_z(\phi)\textbf{T}(-\textbf{p}) $$
- $\textbf{p}$ が原点と一致するように平行移動 $\textbf{T}(-\textbf{p})$
- 回転 $\textbf{R}_z(\phi)$
- 元の位置に平行移動で戻す $\textbf{T}(\textbf{p})$
拡大縮小(スケール)
(編集中)