アフィン変換_3DCG
アフィン変換
元のオブジェクトが持つ頂点情報などは中心位置を(0, 0, 0)としたときの座標系であらわされます。これを「ローカル座標」と言います。
ここから始まり、すべてのオブジェクト(物体)はシーンという3D仮想空間内に配置されます。この「シーン」を表現する座標系を「ワールド座標」と言います。ローカル座標からワールド座標に移行する際に、オブジェクトの拡大縮小・回転・平行移動などが行われます。ワールド座標にはオブジェクトだけでなく、光源・視点も配置されます。
さらに、今度はこれを「視点(カメラ)位置から見たときの」座標に変換します。視点は情報として、「視点位置」と「視線方向」があります(その他、視野角度などの情報もありますが、これが使用されるのは「パースペクティブ変換」です)。これを元に変換すると、始点位置が(0, 0, 0)で視線方向がZ軸で奥に向かってZがプラスになる座標系に変換されます。これを「ビュー(視点)座標」と言います。
ここまででは、まだ「3D」の情報です。実際は、2Dのコンピュータのスクリーンに投影するわけですので「3D→2D」の投影処理を行う必要があります。この2Dに変換後の座標系を「スクリーン座標」と言います(なお、この「スクリーン座標」という単語は場合によって呼び名が違うようで「パースペクティブ(透視)座標」といったりもします)。また、ワールド座標やビュー座標からパースペクティブ座標に変換する行為を「パースペクティブ(透視)変換」と言います。結果、スクリーンの中心が(0, 0)となります。また、2次元変換したためにZ値は不要と思われるかもしれませんが、ピクセルの前後関係を把握するために保持することが多いです(この透視座標でのZ値が「Zバッファ法」などで扱われるZ値になります)。
このままでは縦横の縮尺が実際の「スクリーン」とは異なり、また中心が(0, 0)のままのため、実際の描画領域のサイズに合わせます。このときに描画領域の左上が(0, 0)になるように変換されます。この最終的な座標を「ディスプレイ座標」または「デバイス座標」といったりします。これは、描画領域の左上を(0,0)としたときのピクセル位置を表します。
この個々の座標系の変換は、「4x4行列」で表現されます。
流れとしては
- ローカル座標
- ワールド座標
- ビュー座標
- パースペクティブ座標
- ディスプレイ座標
の順に、それぞれ「ローカル座標→ワールド座標」変換行列、「ワールド座標→ビュー座標」変換行列、「ビュー座標→パースペクティブ座標」変換行列、「パースペクティブ座標→ディスプレイ座標」変換(ここだけは行列を使用しない)、の変換が行われます。行列自身は乗算できるため、あらかじめ乗算して座標系の計算負荷を省くこともできます。
このような座標変換のことを総称して「アフィン変換」と言います。それでは、個々の変換を見ていくことにします。
まだ途中です。
ローカル座標→ワールド座標
ローカル座標からワールド座標への変換ですが、主に「拡大縮小」「回転」「平行移動」が行われます。順番に注意してください。回転や拡大縮小は中心(0, 0, 0)を基点として行われます。そして、最後にワールド座標での位置に平行移動します。
回転はX/Y/Z軸中心の変換を書きますが、このような回転ではなく「ある位置からある目標点を見たときの変換」なども回転に値しますので以下は参考程度も考えてください。
拡大縮小
X/Y/Z軸方向に拡大縮小します((Sx, Sy, Sz)で指定)。1.0のときは等倍になります。
[ Sx 0 0 0 ] [X' Y' Z' W'] = [X Y Z 1] [ 0 Sy 0 0 ] [ 0 0 Sz 0 ] [ 0 0 0 1 ]
X' = X * Sx; Y' = Y * Sy; Z' = Z * Sz;
X軸中心に回転
X軸を中心にθx回転させます。
[ 1 0 0 0 ] [X' Y' Z' W'] = [X Y Z 1] [ 0 cosθx sinθx 0 ] [ 0 -sinθx cosθx 0 ] [ 0 0 0 1 ]
X' = X; Y' = Y * cosθx - Z * sinθx; Z' = Y * sinθx + Z * cosθx;
Y軸中心に回転
Y軸を中心にθy回転させます。
[ cosθy 0 -sinθy 0 ] [X' Y' Z' W'] = [X Y Z 1] [ 0 1 0 0 ] [ sinθy 0 cosθy 0 ] [ 0 0 0 1 ]
X' = X * cosθy + Z * sinθy; Y' = Y; Z' = -X * sinθy + Z * cosθy;
Z軸中心に回転
Z軸を中心にθz回転させます。
[ cosθz sinθz 0 0 ] [X' Y' Z' W'] = [X Y Z 1] [ -sinθz cosθz 0 0 ] [ 0 0 1 0 ] [ 0 0 0 1 ]
X' = X * cosθz - Y * sinθz; Y' = X * sinθz + Y * cosθz; Z' = Z;
ワールド座標に平行移動
移動後のワールド座標位置を(Px, Py, Pz)とします。
[ 1 0 0 0] [X' Y' Z' W'] = [X Y Z 1] [ 0 1 0 0] [ 0 0 1 0] [Px Py Pz 1]
X' = X + Px; Y' = Y + Py; Z' = Z + Pz;
これらの行列を乗算し(行列をかける順番に注意してください)、1つの4x4行列でローカルからワールド座標変換ができるようにします。
ワールド座標→ビュー座標
視点から見たときの座標に変換します。まずこれを求めるには、視点位置があり目標点(視点が見ている位置)があることを理解してください。
視点位置をV(Vx, Vy, Vz)、目標点位置をH(Hx, Hy, Hz)とします。このとき視線は、
Dx = Hx - Vx; Dy = Hy - Vy; Dz = Hz - Vz;
で求まります。
cosα = -Dz / sqrt(Dx * Dx + Dz * Dz); sinα = Dx / sqrt(Dx * Dx + Dz * Dz); cosΒ = sqrt(Dx * Dx + Dz * Dz) / sqrt(Dx * Dx + Dy * Dy + Dz * Dz); sinΒ = -Dy / sqrt(Dx * Dx + Dy * Dy + Dz * Dz); [cosα 0 -sinα 0] [1 0 0 0] A = [ 0 1 0 0] [0 cosΒ sinΒ 0] [sinα 0 cosα 0] [0 -sinΒ cosΒ 0] [ 0 0 0 1] [0 0 0 1]
このときの行列Aが視点から目標点を見たときの「回転行列」になります(Y軸中心にα回転させてX軸中心にΒ回転させたのに等しい)。
これだけでは「視点の位置が(0, 0, 0)になるようにする」「Z軸は奥に向かってプラス」ができていないので、それも加えると以下の式になります。
[ 1 0 0 0] T = [ 0 1 0 0] [ 0 0 1 0] [ -Vx -Vy -Vz 1] [ 1 0 0 0] U = [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 1] [X' Y' Z' W'] = [X Y Z 1] * T * A * U
T、A、Uは4x4行列の乗算になるため、順番にかけ合わせて1つの行列にまとめます。
ただし、この「視点位置」「目標点位置」で求まるビュー座標への変換行列で求めることができない例外があります。視点が垂直に上向き・または下向きの場合(Dx = Dz = 0.0の場合)、cosαとsinα計算時の分母が0になるため計算できません。
ビュー座標→パースペクティブ座標
パースペクティブ座標→ディスプレイ座標
です。
Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.