ビューポートとクリッピング (Direct3D 9)
概念的には、ビューポートは 3D シーンが投影される 2 次元 (2D) の四角形です。 Direct3D では、この四角形は Direct3D サーフェス内の座標として存在し、システムによってレンダー ターゲットとして使われます。 射影変換は、頂点をビューポートで使われる座標系に変換します。 ビューポートは、シーンがレンダリングされるレンダー ターゲット サーフェス上の深度値の範囲 (通常は 0.0 ~ 1.0) を指定するためにも使われます。
視錐台
視錐台とは、ビューポートのカメラに対して相対的に配置された、シーン内の 3D ボリュームです。 カメラ空間から画面にモデルがどのように投影されるかは、このボリュームの形に影響されます。 最も一般的な種類の投影である透視投影では、カメラの近くにあるオブジェクトを、離れた位置のオブジェクトよりも大きく表示します。 透視ビューの場合、視錐台は先端にカメラのある四角錐と考えることができます。これを図で表すと次のようになります。 この四角錐は、前方および後方のクリッピング面と交差します。 四角錐を前方と後方のクリッピング面で切り取ったボリュームが、視錐台です。 オブジェクトは、このボリュームの内部にある場合にのみ表示されます。
暗い部屋に立って正方形の窓から外を眺めたところを想像すると、視錐台のイメージがよくわかります。 この例では、前方のクリッピング面は窓であり、後方のクリッピング面は視界を最終的に遮るものになります。たとえば、道路の向こうにある高層ビルや、遠くに見える山並みの場合もあれば、何もない場合もあります。 四角錐の窓から視界を遮るものまでの間を切り取った内部はすべて見渡すことができ、それ以外の部分は何も見えません。
視錐台は、fov (視野) と、z 座標で指定される前方クリッピング面と後方クリッピング面の間の距離によって定義されます。これを次の図に示します。
この図において変数 D は、カメラから、ジオメトリ パイプラインの直前の部分 (ビュー変換) で定義された空間の原点までの距離を表します。 この空間の周りに視錐台の限界を設定します。 この D 変数を使用してプロジェクション マトリックスを構築する方法については、「プロジェクション変換 (Direct3D 9)」を参照してください。
ビューポート矩形
C++ でビューポートの四角形を定義するには、 D3DVIEWPORT9 構造体を 使用します。 D3DVIEWPORT9 構造体は、IDirect3DDevice9 インターフェイスによって公開される次のビューポート操作メソッドで使用されます。
D3DVIEWPORT9 構造体には、シーンをレンダリングするレンダー ターゲット サーフェスの領域を定義する 4 つのメンバー (X、Y、Width、Height) が含まれています。 これらの値は、次の図に示すように、出力先の四角形、つまりビューポート矩形に対応します。
X、Y、Width、Height の各メンバーに指定する値は、レンダー ターゲット サーフェスの左上隅を基準とした相対的なスクリーン座標です。 構造体には他に、シーンがレンダリングされる深度範囲を示す 2 つのメンバー (MinZ と MaxZ) も定義されています。
Direct3D では、ビューポートのクリッピング ボリュームの範囲として、X は -1.0 ~ 1.0、Y は 1.0 ~ -1.0 を想定しています。これらは、過去のアプリケーションで最もよく使われた設定です。 クリッピングの前に射影変換を使うことで、ビューポートの縦横比を調整できます。
Note
MinZ と MaxZ は、シーンがレンダリングされる深度範囲を示し、クリッピングには使用されません。 ほとんどのアプリケーションでは、これらのメンバーを 0.0 と 1.0 に設定して、システムが深度バッファー内の深度値の範囲全体にレンダリングできるようにします。 場合によっては、他の深度範囲を使って特殊効果を実現することもできます。 たとえば、ゲームのヘッドアップ ディスプレイをレンダリングする場合、両方の値を 0.0 に設定すると、シーン内のオブジェクトを強制的に前面にレンダリングできます。または、両方を 1.0 に設定すると、常に背面に置く必要のあるオブジェクトをレンダリングできます。
ビューポートの D3DVIEWPORT9 構造体の X、Y、Width、Height メンバーで使用される寸法は、レンダー ターゲット サーフェス上のビューポートの位置と寸法を定義します。 これらの値は、サーフェスの左上隅を基準とした相対的なスクリーン座標を示します。
Direct3D は、ビューポートの位置とサイズを使って頂点をスケーリングし、レンダリングするシーンをターゲット サーフェス上の適切な位置に配置します。 Direct3D の内部では、これらの値が次の行列に挿入され、各頂点に適用されます。
この行列は、ビューポートのサイズと指定の深度範囲に従って頂点をスケーリングし、レンダー ターゲット サーフェスの適切な位置に平行移動します。 また、この行列は、左上隅のスクリーン原点から y を下方へ増やした位置を反映するように y 軸を反転します。 この行列が適用された後も、頂点は同次です。つまり、各頂点は引き続き [x,y,z,w] 頂点として存在するため、ラスタライザーに送信する前に非同次の座標に変換する必要があります。
Note
ビューポートのスケーリング マトリックスには 、D3DVIEWPORT9 構造体の MinZ メンバーと MaxZ メンバーが組み込まれており、深度範囲 [MinZ, MaxZ] に合わせて頂点をスケーリングします。 これは、これらのメンバーがクリッピングに使用されていた DirectX の以前のリリースとは異なるセマンティクスを表します。
Note
通常、アプリケーションでは 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 はステンシル バッファーのビット深度です。
場合によっては、レンダー ターゲットと深度バッファー サーフェスの小さな部分にのみレンダリングを行う場合があります。 clear メソッドを使用すると、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::P rocessVertices からの場合を除き、プリミティブの変換された頂点を頂点バッファーからクリップしません。 独自の変換を実行していて、クリッピングを行うために Direct3D が必要な場合は、頂点バッファーを使用しないでください。 この場合、アプリケーションはデータを走査して変換します。 Direct3D はデータを 2 回目にスキャンしてクリップした後、ドライバーによってデータがレンダリングされます。これは非効率的です。 したがって、アプリケーションがデータを変換する場合は、 もデータをクリップする必要があります。
クリップする必要がある事前に変換され、点灯した頂点 (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 をもう一度呼び出します。
Note
D3DVIEWPORT9 構造体メンバー MinZ と MaxZ は、シーンがレンダリングされる深度範囲を示し、クリッピングには使用されません。 ほとんどのアプリケーションでは、これらのメンバーを 0.0 と 1.0 に設定して、システムが深度バッファー内の深度値の範囲全体にレンダリングできるようにします。 場合によっては、他の深度範囲を使って特殊効果を実現することもできます。 たとえば、ゲームのヘッドアップ ディスプレイをレンダリングする場合、両方の値を 0.0 に設定すると、シーン内のオブジェクトを強制的に前面にレンダリングできます。または、両方を 1.0 に設定すると、常に背面に置く必要のあるオブジェクトをレンダリングできます。
関連トピック