ビューポートとクリッピング (Direct3D 9)

概念上、ビューポートとは 3 次元 (3D) シーンが射影される 2 次元 (2D) の矩形です。Direct3D の場合、この矩形は、レンダー ターゲットとして使用される Direct3D サーフェス内の座標として存在します。射影トランスフォームは、ビューポートに使用される座標系に頂点を変換します。ビューポートは、シーンをレンダリングするレンダー ターゲット サーフェスの深度値の範囲 (通常は 0.0 ~ 1.0) の指定にも使用されます。

視錘台

視錐台とは、ビューポートのカメラに対して相対的に配置されたシーン内の 3 次元の入れ物です。この入れ物の形状は、カメラ空間からスクリーンにモデルを射影する方法に影響を与えます。最も一般的な種類の射影は、パースペクティブ (遠近投影) 射影です。この射影では、カメラの近くにあるオブジェクトが、カメラの遠くにあるオブジェクトよりも大きく表示されます。パースペクティブ ビューの場合、視錐台とは先端にカメラがある角錐と考えるとわかりやすくなります。この角錐は、前方および後方のクリップ面と交差します。前方と後方のクリップ面の間にある角錐型の入れ物が視錐台です。オブジェクトは、この入れ物の中にあるときにのみ見えます。

Viewing frustrum

視錐台は、暗い部屋の中で正方形の窓から外を見ている状況を想像するとよくわかります。この状況で、近いほうのクリップ面は窓であり、後方クリップ面は視界を最終的に遮るもの、たとえば、街の高層ビル、遠方の山脈、または遮るものが何もない状態です。先端が切れた角錐の内部 (窓から最終的に視界を遮るものまでの間) にあるものはすべて見ることができ、それ以外のものは何も見えません。

視錐台は、z 座標で指定される前方と後方のクリップ面の間の距離および fov (視野) で定義されます。

Frustum

この図では、変数 D は、カメラから、ジオメトリ パイプラインの最後の部分で定義された空間の原点 (ビュー トランスフォーム) までの距離です。この空間の周りに視錐台の限界を設定します。この変数 D を使用して射影行列を作成する方法については、「射影トランスフォーム (Direct3D 9)」を参照してください。

ビューポート矩形

C++ のビューポート矩形は、D3DVIEWPORT9 構造体を使用して定義します。D3DVIEWPORT9 構造体は、IDirect3DDevice9 interface インターフェイスが公開する次のビューポート操作メソッドを使用します。

D3DVIEWPORT9 構造体には、X、Y、Width、Height の 4 つのメンバーがあります。これらは、シーンがレンダリングされるレンダー ターゲット サーフェスの領域を定義します。これらの値は、次の図に示すように、転送先の矩形、つまりビューポート矩形に対応します。

Viewport rectangle

X、Y、Width、Height メンバーに指定する値は、レンダー ターゲット サーフェスの左上角を基準とする相対的なスクリーン座標です。この構造体は、シーンをレンダリングする深度範囲を示す 2 つの追加メンバー (MinZ および MaxZ) を定義します。

Direct3D では、ビューポートのクリッピング ボリュームの範囲は、X 方向については -1.0 ~ 1.0、Y 方向については 1.0 ~ -1.0 と想定しています。この値は、過去のアプリケーションで最もよく使われた設定値です。クリッピングの前に射影トランスフォームを使用して、ビューポートのアスペクト比を調整できます。

    MinZ および MaxZ は、シーンをレンダリングする深度範囲を示し、クリッピングには使用されません。ほとんどのアプリケーションでは、これらのメンバーを 0.0 と 1.0 に設定して、システムが深度バッファー内のすべての範囲の深度値にレンダリングできるようにします。場合によっては、別の深度範囲を使用して特殊効果を得ることもできます。たとえば、ゲームのヘッドアップ ディスプレイをレンダリングする場合、両方の値を 0.0 に設定してフォアグラウンドのシーン内のオブジェクトを強制的にレンダリングしたり、両方の値を 1.0 に設定して常にバックグラウンドに存在する必要があるオブジェクトをレンダリングしたりすることができます。

ビューポートの D3DVIEWPORT9 構造体の X、Y、Width、Height メンバーで使用される寸法は、レンダー ターゲット サーフェスのビューポートの位置とサイズを定義します。これらの値は、サーフェスの左上角を基準とする相対的なスクリーン座標の値です。

Direct3D では、ビューポートの位置とサイズを使用して、頂点をスケーリングし、レンダリングするシーンをターゲット サーフェス上の適切な位置に配置します。内部的には、Direct3D は、各頂点に適用する行列にこれらの値を挿入しています。

Matrix

この行列は、ビューポートのサイズおよび指定の深度範囲に従って頂点をスケーリングし、その頂点をレンダー ターゲット サーフェスの適切な位置に平行移動します。また、この行列は、y 座標を反転して、y が下方に増加する左上角のスクリーン原点を反映します。この行列を適用した後も、頂点は同次です。つまり、頂点は依然として [x,y,z,w] 頂点として存在するので、ラスタライザーに送る前に頂点を非同次の座標に変換する必要があります。

    ビューポート スケーリング行列は、D3DVIEWPORT9 構造体の MinZ および MaxZ メンバーを組み込んで頂点をスケーリングし、深度範囲 [MinZ, MaxZ] に合わせます。これは以前のリリースの DirectX のセマンティクスとは異なります。以前のリリースでは、これらのメンバーがクリッピングに使用されていました。

    アプリケーションでは通常、MinZ と MaxZ をそれぞれ 0.0 と 1.0 に設定し、すべての深度範囲がレンダリングされるようにします。しかし、その他の値を使用して、一定の効果を得ることもできます。たとえば、両方の値を 0.0 に設定して、すべてのオブジェクトを強制的に前景に置いたり、両方を 1.0 に設定して、すべてのオブジェクトを背景にレンダリングしたりすることができます。

ビューポートのクリア

ビューポートをクリアすると、レンダー ターゲット サーフェス上のビューポート矩形の内容がリセットされます。深度バッファー サーフェスおよびステンシル バッファー サーフェスの矩形もクリアされます。

ビューポートをクリアするには、IDirect3DDevice9::Clear を使用します。このメソッドは、クリアされるサーフェスの領域を定義する 1 つ以上の矩形を受け入れます。Count パラメーターを 1 に設定し、pRects パラメーターをビューポート領域全体を含む 1 つの矩形のアドレスに設定すると、ビューポート全体がクリアされます。ビューポート全体をクリアするには他に、pRects パラメーターを NULL に設定し、Count パラメーターを 0 に設定する方法があります。

IDirect3DDevice9::Clear は、深度バッファー内のステンシル ビットのクリアに使用できます。Flags パラメーターを設定するだけで、IDirect3DDevice9::Clear のレンダー ターゲットおよび関係するすべての深度バッファーまたはステンシル バッファーに対する働きを指定できます。D3DCLEAR_TARGET フラグを指定すると、引数 Color で指定した任意の RGBA 色 (マテリアル色ではない) を使用してビューポートをクリアします。D3DCLEAR_ZBUFFER フラグを指定すると、Z で指定した任意の深度まで深度バッファーをクリアします。0.0 は最も近い距離を表し、1.0 は最も遠い距離を表します。D3DCLEAR_STENCIL フラグを指定すると、ステンシル ビットを引数 Stencil で指定した値にリセットします。指定できる値は 0 ~ 2n-1 の整数です。ここで、n はステンシル バッファーのビット深度を示します。

場合によっては、レンダー ターゲット サーフェスと深度バッファー サーフェスの一部にのみレンダリングすることがあります。クリア メソッドを使用すると、1 回の呼び出しでサーフェスの複数の領域をクリアすることもできます。これを行うには、Count パラメーターをクリアする矩形の数に設定し、pRects パラメーターに矩形の配列内の最初の矩形のアドレスを指定します。

クリッピングするビューポートの設定

射影行列の結果によって、次のように射影空間のクリッピング ボリュームが決まります。

-wc<= xc<= wc

-wc<= yc<= wc

0 <= zc<= wc

この場合x、y、 z、および w は、射影トランスフォームを適用した後の頂点座標を表します。クリッピングが有効な場合 (既定の動作)、これらの範囲外に x、y、または z 成分を持つすべての頂点がクリッピングされます。

頂点バッファーを除き、アプリケーションでは、D3DRS_CLIPPING レンダリング ステートを使ってクリッピングを有効または無効にします。頂点バッファーのクリッピング情報は処理中に生成されます。詳細については、「固定機能頂点処理 (Direct3D 9)」および「プログラム可能な頂点処理 (Direct3D 9)」を参照してください。

Direct3D では、IDirect3DDevice9::ProcessVertices によるものを除き、頂点バッファーのプリミティブの変換済みの頂点をクリッピングしません。独自のトランスフォームを実行する際に、Direct3D でクリッピングを行う必要がある場合は、頂点バッファーを使わないでください。この場合、アプリケーションではデータをトラバースして変換します。Direct3D が再度データをトラバースしてクリッピングした後、ドライバーがデータをレンダリングするので、効率的ではありません。したがって、アプリケーションがデータを変換する場合は、データのクリッピングも行う必要があります。

デバイスが、クリッピングを要するトランスフォーム前のライティング済み頂点 (T&L 頂点) を受け取ると、クリッピング操作を実行するために、その頂点の逆数の同次の w (RHW) とビューポートの情報を使用して頂点をクリッピング空間に逆にトランスフォームします。クリッピングはその後に実行されます。T&L 頂点をクリッピングするための逆トランスフォームは、すべてのデバイスで実行できるわけではありません。

D3DPMISCCAPS_CLIPTLVERTS デバイス機能は、デバイスが T&L 頂点をクリッピングできるかどうかを示します。この機能が設定されていない場合は、レンダリングするデバイスに送る T&L 頂点をアプリケーションでクリッピングする必要があります。ソフトウェア頂点処理モード (デバイス自体をソフトウェア頂点処理モードで作成するか、ソフトウェア頂点処理モードに切り替えるかどうかに関係なく) では、デバイスは常に T&L 頂点をクリッピングできます。

レンダリング デバイスのビューポート パラメーターを構成するための要件は、ビューポートのクリッピング ボリュームを設定することのみです。これを実行するには、クリッピング ボリュームのクリッピング値とレンダー ターゲット サーフェスのクリッピング値を初期化し、設定します。ビューポートは、一般的には、レンダー ターゲット サーフェスの全領域にレンダリングするように設定されますが、必ずしもそうする必要はありません。

C++ でこれを実現するには、D3DVIEWPORT9 構造体のメンバーを次のように設定します。

D3DVIEWPORT9 viewData = { 0, 0, width, height, 0.0f, 1.0f };

D3DVIEWPORT9 構造体に値を設定した後、IDirect3DDevice9::SetViewport メソッドを呼び出してデバイスにビューポート パラメーターを適用します。次のコードは、この呼び出しを示しています。

HRESULT hr;

hr = pd3dDevice->SetViewport(&viewData);
if(FAILED(hr))
    return hr;

この呼び出しが成功すると、ビューポート パラメーターが設定され、次回レンダリング メソッドが呼び出されたときに有効になります。ビューポート パラメーターは、D3DVIEWPORT9 構造体の値を更新して、再度 IDirect3DDevice9::SetViewport を呼び出すだけで変更できます。

    D3DVIEWPORT9 構造体の MinZ および MaxZ メンバーは、シーンがレンダリングされる深度範囲を示し、クリッピングには使用されません。ほとんどのアプリケーションでは、これらのメンバーを 0.0 と 1.0 に設定して、システムが深度バッファー内のすべての範囲の深度値にレンダリングできるようにします。場合によっては、別の深度範囲を使用して特殊効果を得ることもできます。たとえば、ゲームのヘッドアップ ディスプレイをレンダリングする場合、両方の値を 0.0 に設定してフォアグラウンドのシーン内のオブジェクトを強制的にレンダリングしたり、両方の値を 1.0 に設定して常にバックグラウンドに存在する必要があるオブジェクトをレンダリングしたりすることができます。