トランスフォーム (Direct3D 9)
Direct3 の機能の一部で、ジオメトリを固定機能ジオメトリ パイプラインに挿入するトランスフォーム エンジンのこと。これは、ワールドでのモデルとビューアー、画面上のディスプレイのプロジェクト頂点、およびビューポートへの頂点のクリップの位置を指定します。また、トランスフォーム エンジンはライティング計算を実行して、各頂点でのディフューズとスペキュラ成分を決定します。
ジオメトリ パイプラインは、入力として頂点を取得します。トランスフォーム エンジンは、ワールド、ビュー、射影トランスフォームを頂点に適用し、結果をクリップしてから、すべてをラスタライザーに渡します。
パイプラインの先頭では、モデルの頂点がローカルの座標系を基準にして宣言されています。これはローカル原点であり、方向でもあります。この座標の方向は、モデル空間と呼ばれることもあります。また、個別の座標はモデル座標と呼ばれます。
最初のステージでは、ジオメトリ パイプラインはモデルの頂点をローカル座標系からシーン内のすべてのオブジェクトが使用する座標系に変換します。頂点の方向を変更するプロセスは、ワールド トランスフォームと呼ばれます。この新しい方向は通常ワールド空間と呼ばれます。ワールド空間の各頂点はワールド座標を使用して宣言されます。
次のステージでは、3D ワールドを記述する頂点の位置が、カメラを基準にして決定されます。つまり、アプリケーションでシーンの視点が選択されることによって、ワールド空間の座標の位置が調整されてカメラの視点の周りを回転するようになり、ワールド空間からカメラ空間へと切り替わります。これがビュー トランスフォームです。
次のステージでは、射影トランスフォームが行われます。パイプラインのこの部分では、オブジェクトはシーンに深みのある効果を与えるようにビューアーからの距離で測定されます。そのため、近くのオブジェクトは遠くのオブジェクトよりも大きく見えます。わかりやすくするため、ここでは射影空間として射影トランスフォーム後に存在する頂点の空間について説明します。グラフィック関連のほかの書籍では、射影空間をポストパースペクティブ同次空間と呼ぶこともあります。すべての射影トランスフォームがシーンでオブジェクトのサイズを測定する訳ではありません。また、射影はアフィンまたは正射影と呼ばれることがあります。
パイプラインの最後の部分では、画面に表示されない頂点が削除されるため、ラスタライザーが、表示されない色やシェーディングの計算に時間を取られることはありません。このプロセスは、クリッピングと呼ばれます。クリッピング後、残りの頂点はビューポート パラメーターによって測定され、画面座標に変換されます。シーンがラスタライズされたときに画面に表示される結果としての頂点は、画面空間に存在します。
トランスフォームは、オブジェクト ジオメトリをある座標空間から別の座標空間へと変換する場合に使用されます。Direct3D は行列を使用して、3D トランスフォームを実行します。このセクションでは、行列が 3D トランスフォームを作成する方法、トランスフォームの一般的な使用方法、行列を結合させて複数のトランスフォームを含む 1 つの行列を生成する方法について説明します。
- ワールド トランスフォーム (Direct3D 9) - モデル空間からワールド空間に変換する
- ビュー トランスフォーム (Direct3D 9) - ワールド空間からビュー空間に変換する
- 射影トランスフォーム (Direct3D 9) - ビュー空間から射影空間に変換する
行列のトランスフォーム
3D グラフィックで動作するアプリケーションでは、ジオメトリ トランスフォームを使用して、次を実行します。
- 別のオブジェクトを基準にしてオブジェクトの位置を示す
- オブジェクトを回転し、サイズを決定する
- 表示する位置、方向、パースペクティブを変更する
4 x 4 行列を使用して、すべてのポイント (x,y,z) を別のポイント (x', y', z') に変換できます。
次の演算を (x, y, z) で実行すると、行列によってポイント (x', y', z') が作成されます。
一般的なトランスフォームには、並行移動、回転、拡大縮小があります。これらのエフェクトを作り出す行列を結合して 1 つの行列にし、1 度に複数のトランスフォームを計算させることができます。たとえば、これらのポイントを並行移動し、回転させる 1 つの行列を作成できます。
行列は、行、列の順番で記述されています。各軸に対して頂点を均等に調節する行列は、均一の拡大縮小として知られていますが、数学的に表すと次のような行列になります。
C++ では、Direct3D は D3DMATRIX 構造体を使用して、2 次元の配列として行列を宣言します。次の例では、D3DMATRIX 構造体を均一の拡大縮小行列として動作するように初期化する方法を示しています。
// In this example, s is a variable of type float. D3DMATRIX scale = { s, 0.0f, 0.0f, 0.0f, 0.0f, s, 0.0f, 0.0f, 0.0f, 0.0f, s, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
Translate
次のトランスフォームは、ポイント (x, y, z) を新しいポイント (x', y', z') に並行移動します。
C++ では平行移動行列は手動で作成できます。次の例は、頂点に並行移動する行列を作成する関数のソース コードを示しています。
D3DXMATRIX Translate(const float dx, const float dy, const float dz) { D3DXMATRIX ret; D3DXMatrixIdentity(&ret); ret(3, 0) = dx; ret(3, 1) = dy; ret(3, 2) = dz; return ret; } // End of Translate
簡単に使用できるように、D3DX ユーティリティ ライブラリで D3DXMatrixTranslation 関数を提供しています。
拡大縮小
次のトランスフォームは、x 方向、y 方向、z 方向に、ポイント (x, y, z) を新しいポイント (x', y', z') に任意の値で拡大縮小します。
[回転](Rotate)
ここでは、トランスフォームは左手座標系を記述しています。そのため他の場所にあるトランスフォーム行列とは異なっています。
次の行列は x 軸の周りのポイント (x, y, z) が回転し、新しいポイント (x', y', z') を作り出します。
次の行列は y 軸の周りのポイントを回転します。
次の行列は z 軸の周りのポイントを回転します。
これらの例の行列では、ギリシャ文字の theta がラジアンの回転角度を表しています。角度は、回転軸を基準とし、原点から時計回りの方向で指定します。
C++ アプリケーションでは、D3DX ユーティリティ ライブラリで提供される D3DXMatrixRotationX、D3DXMatrixRotationY、および D3DXMatrixRotationZ 関数を使用して、回転行列を作成します。以下は、D3DXMatrixRotationX 関数のコードです。
D3DXMATRIX* WINAPI D3DXMatrixRotationX ( D3DXMATRIX *pOut, float angle ) { #if DBG if(!pOut) return NULL; #endif float sin, cos; sincosf(angle, &sin, &cos); // Determine sin and cos of angle pOut->_11 = 1.0f; pOut->_12 = 0.0f; pOut->_13 = 0.0f; pOut->_14 = 0.0f; pOut->_21 = 0.0f; pOut->_22 = cos; pOut->_23 = sin; pOut->_24 = 0.0f; pOut->_31 = 0.0f; pOut->_32 = -sin; pOut->_33 = cos; pOut->_34 = 0.0f; pOut->_41 = 0.0f; pOut->_42 = 0.0f; pOut->_43 = 0.0f; pOut->_44 = 1.0f; return pOut; }
行列の連結
行列を使用すると、2 つまたはそれ以上の行列を乗算して、エフェクトを組み合わせることができるという利点があります。たとえば、モデルを回転させてから、次にそれを別の場所に並行移動させる場合、2 つの行列を適用する必要はありません。その代わり、回転と平行移動の行列を乗算し、両方のエフェクトを含む合成行列を作成します。このプロセスは行列の連結と呼ばれ、次の公式のように記述されます。
この公式では、C は作成された合成行列となります。また M1 ~ Mn は個別の行列となります。ほとんどの場合、2 つまたは 3 つの行列が連結されますが、制限はありません。
D3DXMatrixMultiply 関数を使用して、行列の乗算を実行します。
行列の乗算が実行される順番は、非常に重要です。上記の公式では、行列連結は左から右の順番で実行されます。つまり、合成行列を作成するのに使用した行列のエフェクトは、左から右への順番で発生します。一般的なワールド行列は、次の例のようになります。よくある空飛ぶ円盤を表すワールド行列を作成するとします。空飛ぶ円盤を中心点 (モデル空間の y 軸) で回転させ、それを自分のシーンの別の場所に並行移動させます。このエフェクトを実現するには、まず回転行列を作成し、次にそれを並行移動行列で乗算します。次の公式のようになります。
この公式では、Ry は y 軸で回転する行列を表し、 Tw は、ワールド座標で並行移動する位置を表しています。
行列を乗算する場合は、順番が重要です。なぜなら 2 つのスカラー値を乗算するのとは異なり、行列の乗算は可換的ではないからです。反対の順番で行列を乗算すると、空飛ぶ円盤がワールド空間に並行移動してから、ワールド原点で回転するという順番でエフェクトが発生してしまいます。
作成した行列の種類にかかわらず、期待どおりのエフェクトを実現するには、左から右へのルールが適用されることを忘れないでください。