トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

アフィン変換_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.