Microsoft Corporation
はじめに
このホワイト ペーパーは、Direct3D 行列の直接操作によって Direct3D トランスフォーム パイプラインのパラメーターを設定する方法について説明する、Direct3D アプリケーション開発者向けの資料です。
概要
Direct3D では、3D モデル座標をピクセル座標 (画面空間) に変更するために、3 つのトランスフォームが使用されます。それらは、ワールド トランスフォーム、ビュー トランスフォーム、および射影トランスフォームです。
ワールド トランスフォームは、モデル座標をワールド座標にトランスフォームする方法を制御します。ワールド トランスフォームには、平行移動、回転、および拡大縮小が含まれますが、ライトには適用されません。ワールド トランスフォームを使用した作業の詳細については、「ワールド トランスフォーム (Direct3D 9)」を参照してください。
ビュー トランスフォームは、ワールド内のカメラ位置を指定することによって、ワールド座標から "カメラ空間" への変換を制御します。ビュー トランスフォームを使用した作業の例については、「ビュー トランスフォーム (Direct3D 9)」を参照してください。
射影トランスフォームは、カメラ空間から "クリップ空間" へジオメトリを変更し、パースペクティブの変形を適用します。"クリップ空間" という用語は、このトランスフォームでジオメトリをビュー ボリュームにクリッピングする方法を表します。射影トランスフォームを使用した作業の例については、「射影トランスフォーム (Direct3D 9)」を参照してください。
最後に、クリップ空間のジオメトリがピクセル座標 (画面空間) にトランスフォームされます。このトランスフォームは、ビューポートの設定によって制御されます。
頂点のクリッピングとトランスフォームは、同次空間 (単純に配置。第 4 成分を含む座標系の空間) で実行する必要がありますが、ほとんどのアプリケーションにとって最終的な結果は "画面空間" で定義される異次の 3 次元 (3D) 座標である必要があります。つまり、入力頂点とクリッピング ボリュームの両方を同次空間に変換してクリッピングを実行してから、表示のために異次空間に戻す必要があります。
Direct3D の 3 つのトランスフォームである、ワールド、ビュー、および射影トランスフォームは、Direct3D 行列によって定義されます。Direct3D 行列は、D3DMATRIX 構造体によって定義される 4x4 の同次行列です。Direct3D 行列は、COM インターフェイスのような標準のオブジェクトではありませんが、他の Direct3D オブジェクトと同じように作成したり設定したりできます。Direct3D 行列の詳細については、「トランスフォーム (Direct3D 9)」を参照してください。
トランスフォーム パイプライン
モデル座標の頂点が Pm = (Xm, Ym, Zm, 1) で指定される場合は、次の図に示したトランスフォームが、画面座標 Ps = (Xs, Ys, Zs, Ws) の計算に適用されます。
これら 7 つのステージの処理は、次のとおりです。
ワールド行列 Mworld によって、頂点がモデル空間からワールド空間に変換されます。この行列は、次のコードによって設定されます。
- d3dDevice->SetTransform (D3DTRANSFORMSTATE_WORLD, matrix address)
Direct3D の実装は、この行列の最後の列が (0, 0, 0, 1) であると仮定します。ユーザーが行列の最後の列に異なる値を指定した場合はエラーは返されませんが、ライティングとフォグが不適切になります。
ビュー行列 Mview によって、頂点がワールド空間からカメラ空間に変換されます。この行列は、次のコードによって設定されます。
- d3dDevice->SetTransform (D3DTRANSFORMSTATE_VIEW, matrix address)
Direct3D の実装は、この行列の最後の列が (0, 0, 0, 1) であると仮定します。ユーザーが行列の最後の列に異なる値を指定した場合はエラーは返されませんが、ライティングとフォグが不適切になります。
射影行列 Mproj によって、頂点がカメラ空間から射影空間に変換されます。この行列は、次のコードによって設定されます。
- d3dDevice->SetTransform (D3DTRANSFORMSTATE_PROJECTION, matrix address)
適切なフォグとライティングの効果を得るには、射影行列の最後の列を (0, 0, 1, 0) または (0, 0, a, 0) に指定する必要があります。推奨される形式は、(0, 0, 1, 0) です。
射影空間内のすべてのポイント Xp = (Xp, Yp, Zp, Wp) に対するクリッピング ボリュームは、次のように定義されます。
-Wp < Xp <= Wp
-Wp < Yp <= Wp
0 < Zp <= Wp
これらの方程式を満たさないポイントはすべてクリッピングされます。
ビュー ボリュームが次のように定義されているとします。
Sw - カメラ空間における近くのクリップ面の画面ウィンドウ幅
Sh - カメラ空間における近くのクリップ面の画面ウィンドウの高さ
Zn - カメラ空間の Z 軸に沿った近くのクリップ面までの距離
Zf - カメラ空間の Z 軸に沿った遠くのクリップ面までの距離
射影行列は次のように記述できます。
ここで、Mij は、Mproj のメンバーです。
正射影の場合は、次のようになります。
Direct3D では、パースペクティブ射影行列の形式は次のように仮定されています。
射影行列の形式がこれとは異なる場合は、不自然な効果が生じます。たとえば、テーブル フォグが機能しなくなります。
Direct3D を使用すると、ユーザーはクリップ ボリュームを次のように変更できます。
これは、次のように書き換えることができます。
この場合
Cx、Cy - D3DVIEWPORT9 からの dvClipX、dvClipY
Cw、Ch - D3DVIEWPORT9 からの dvClipWidth、dvClipHeight
Zmin、Zmax - D3DVIEWPORT9 からの dvMinZ、dvMaxZ
このトランスフォームは、精度を向上させることができ、クリッピング ボリュームのスケーリングやシフティングと等価です。
対応する Mclip 行列は、次のとおりです。
頂点は次の式によってトランスフォームされます。
- (Xc, Yc, Zc, Wc) = (Xp, Yp, Zp, Wp) * Mclip
クリップ ボリュームをスケーリングしない場合は、ビューポートのパラメーターを次のデフォルト値に設定します。
dvClipWidth = 2
dvClipHeight = 2
dvClipX = -1
dvClipY = 1
dvMinZ = 0
dvMaxZ = 1
ユーザーが DrawPrimitive 呼び出しで D3DDP_DONOTCLIP フラグを指定している場合、このクリッピング ステージは省略可能です。この場合は、Mvs を含めてすべての行列を結合できます。
ビューポートのスケール行列 Mvs によって、座標がビューポート ウィンドウ内に収まるようにスケーリングされ、Y 軸の上下が反転します。
この場合
dwX、dwY - D3DVIEWPORT9 からのピクセル単位のビューポートのオフセット
dwWidth、dwHeight - D3DVIEWPORT9 からのピクセル単位のビューポートの幅と高さ
最後に、画面座標が計算され、ラスタライザーに渡されます。
使用方法のヒント
ワールド行列およびビュー行列の最後の列は、(0, 0, 0, 1) である必要があります。そうでなければ、ライティングが不適切になります。
特に必要がない限り、Mclip 行列は単位行列として作成されるようにビューポートのパラメーターを設定します。
dvClipWidth = 2
dvClipHeight = 2
dvClipX = -1
dvClipY = 1
dvMinZ = 0
dvMaxZ = 1
関連項目
ワールド トランスフォーム (Direct3D 9), ビュー トランスフォーム (Direct3D 9), 射影トランスフォーム (Direct3D 9), D3DMATRIX, トランスフォーム (Direct3D 9)