レンダリングパイプライン
概要
レンダリングパイプラインとはモデルデータの入力から出力までの レンダリングのための加工手順のことです。![]()
レンダリング
レンダリングとは入力データである、3Dモデルのポリゴンデータや、 テクスチャデータを使用して画面や画像として出力することです。 3Dモデルファイルはモデルの形を形成するポリゴンデータや 色を表現するマテリアルがあり、そのマテリアルにテクスチャが含まれています。![]()
ポリゴンデータ
ポリゴンデータは3Dモデルのデータの事で、ポリゴンの集合です。 ポリゴンは3つ以上の頂点で形成される多角形のことで、 基本的にモデルデータで使用するポリゴンの頂点数は三または四頂点で 構成されていることが多いです。 このポリゴンの頂点情報(座標や色など)を管理するための バッファが用意されており、そのバッファを頂点バッファと呼びます。上の図のように最終的にモデルデータは頂点バッファに格納され、 レンダリングパイプラインで使用されることになります。
テクスチャデータ
テクスチャデータはbmpやpngなどの画像のことで、様々なフォーマットが使用可能です。 これらのテクスチャをメモリ上に読み込んで使用します。 また、レンダリングターゲットに描き込んでいる画像も テクスチャデータとして使用することができます。
出力
レンダリングパイプラインから出力された画像はメモリ上に保存されます。 このメモリ領域のことは「レンダリングターゲット」「バックバッファ」 「サーフェース」などと呼ばれています。 このレンダリングターゲットの画像を画面に転送することで ディスプレイ上で描画が行われています。![]()
加工の順番
レンダリングパイプラインの加工は以下の順番で行われています。頂点パイプラインとピクセルパイプラインの部分がプログラマブルに使用できる箇所です。 シェーダには開発側がソースを書いて作成するプログラマブルシェーダと 既存でシェーダ機能が用意されている固定機能シェーダがあります。 近年のシェーダはプログラマブルシェーダで記述することを必須としており、 固定機能シェーダでシェーダを記述できるのはDirectX9以前、OpenGL2.0以前など、 古いバージョンのグラフィックライブラリでしか扱えなくなっています。
頂点シェーダ
頂点シェーダはレンダリングパイプラインの最初に行うシェーダ処理です。 主な処理は「座標変換」「テクスチャ座標の計算」「陰影処理」です。 この処理は各ポリゴンの頂点一つ一つに対して行われます。上のイメージ図で注意してほしい点は頂点シェーダの変換後は テッセレーションやジオメトリシェーダ、ラスタライズやピクセルシェーダがあるので 頂点シェーダ終了後にすぐにレンダリングターゲットに反映されません。 あくまでもイメージです。
座標変換
3Dモデルは独自の座標系である「ローカル座標」を持っています。このローカル座標はあくまで各モデルが自分自身を表現するための座標なので、 このまま描画すると全て画面の中央に集まってしまい こちらの意図通りの位置に配置できません。
そこで3D空間の座標を用意してそこにモデル配置します。 そうすることで、3D空間の座標軸を指標としてモデルの座標が決めれるので 自分達が求めている場所に配置することができるようになります。 この指標となる3D空間用の座標を「ワールド座標」と呼びます。 そしてモデルの持つローカル座標をワールド座標のどこかの位置に配置する 変換方法を「ワールド座標変換」と呼びます。 このワールド座標変換が頂点シェーダの役割の一つです。
![]()
テクスチャ座標の計算
モデルにはテクスチャを貼り付けることができます。 貼り付けの方法は各頂点に対して貼り付けるテクスチャの座標が決まっており、 ピクセルシェーダにて座標を元にしてテクスチャの色情報を抽出して モデルに貼り付けているように見せています。 頂点シェーダでは貼り付けるためのテクスチャの座標を求める計算を行います。
陰影処理
頂点は法線というポリゴンの向きを表すベクトルを持っています。 この法線ベクトルと、光の向き表す光源ベクトルを使用して、 頂点に対しての光の当たり具合、反射具合を計算することができます。 これらの計算処理のことをまとめて陰影処理と呼んでいます。上の図では光が左上から右下に対して降り注いでおり、 その光を赤色の立方体が浴びている内容となっています。 光をまともに浴びている左側は赤がはっきりと出ていますが、 右側の面は光の当たりが少ないための暗い赤色になっています。 このような結果になるように処理を行っているのが陰影処理です。
テッセレーションシェーダ
テッセレーションシェーダは頂点シェーダから送られてきたポリゴンを 分割することができるシェーダです。 テッセレーションシェーダを使用することにより、LOD用に複数の3Dモデルを 用意することなく、一体のモデルだけで動的にLODを実現することができます。 テッセレーションは「ハルシェーダ」「テッセレータ」「ドメインシェーダ」の 三つで構成されています。![]()
ハルシェーダ
ハルシェーダはどのように分割を行うかを決めるためのシェーダです。 この後のテッセレータやドメインシェーダで行う分割処理を行うための 分割計画のための設定を行うのがこのハルシェーダの役割になります。
パッチ
テッセレーションを使用する場合、パイプライン入力のトポロジに変化が生じます。 非テッセレーションの場合、ポリゴン(三角形)が入力情報として送られますが、 テッセレーションではパッチと呼ばれるプリミティブが渡されます。 このパッチにはコントロールポイントと呼ばれる分割用の制御点をもっており、 1~32までポイントを設定することが可能で、複数のコントロールポイントを 設定することでこの後のテッセレータでの分割をより詳細に制御することが可能です。
用語 | 説明 |
---|---|
トポロジ | ポリゴンの構成のこと |
テッセレーション係数 | パッチ毎に指定する分割係数のことです。 この係数を増やすことでより細かい分割を行うことができます。 |
テッセレータ
テッセレータはハルシェーダで設定を行ったパッチをもとに頂点分割を行うシェーダです。 固定機能シェーダなのでプログラマーが処理を書くことはDirectX11の段階ではありません。
分割方法
ポリゴンの分割は三角形や四角形などの分割単位や 離散的分割、連続的分割などの分割アルゴリズムの選択などをすることが可能です。
ドメインシェーダ
ドメインシェーダではテッセレータで分割されたポリゴンに対して 様々な変更を行うためのシェーダです。 例えば曲線を描くように変更したり、凹凸ができるようにしたりと 新規ポリゴンを使用して新しい表現を行うために用意されているシェーダです。
ジオメトリシェーダ
ジオメトリシェーダはポリゴンに対して頂点の増減を行うことができるシェーダです。 テッセレーションはパッチ(ポリゴン)に対して分割を行い、 ポリゴンの増加を行いましたが、ジオメトリシェーダはポリゴンの増減が可能です。 ジオメトリシェーダを使用することでポイントをラインにしたり、 ラインをポリゴンにしたり、することが可能です。![]()
カメラ空間への展開
カメラ空間への展開はジオメトリシェーダまで終了したポリゴンを ワールド座標からカメラ座標へ変換します。 この変換中~変換後にカリング処理を実行します。 カリングとはカメラの範囲に入っていないポリゴンや カメラの視点ベクトルに向いていないポリゴンを描画しない手法です。
ラスタライズ
ラスタライズは頂点シェーダとピクセルシェーダの間に存在する処理で、 頂点シェーダで決まった座標とポリゴン単位の色を元にして フレームバッファにピクセル単位で描画情報を設定する処理です。 ラスタライズが行う処理は「線形の補間」と「頂点カラーの補間」です。
線形の補間
フレームバッファに対し、頂点シェーダで変換された 頂点の座標を配置し、頂点同士を線で結びます。![]()
頂点カラーの補間
線で結ばれポリゴンが作成されたら、そのポリゴンの内部を走査し、 頂点カラーの色で補間を行います。 この補間が行われたポリゴン一つ一つがピクセルシェーダの対象となります。![]()
ピクセルシェーダ
ピクセルシェーダはラスタライズで設定された色情報を取得して そこに何らかの対応を行い、その結果の色情報をGPUへ戻します。![]()
ピクセルシェーダの注意点
上でも書いていますが、ピクセルシェーダはラスタライズで処理された ピクセル一つ一つつに対して処理を行います。 そのため頂点シェーダと比較した場合、作業コストは大きいです。 画面全体を表示するようなデータがラスタライズに存在した場合、 その画面領域のピクセルに対してピクセルシェーダの処理を 行わなければいけません。
画面サイズ(横 * 縦) | ピクセルシェーダの実行回数 |
---|---|
800 * 600 | 800 * 600 => 480,000回 |
1920 * 1080 | 1920 * 1080 => 2,073,600回 |
レンダーバックエンド
レンダーバックエンドはピクセルシェーダ決定したピクセル情報の 描き込みを判断する場所になります。 ここで描き込みに対して問題なしと判断されて始めて レンダリングバッファに出力されます。 判断に使用するテストには「アルファテスト」「深度テスト」 「ステンシルテスト」などがあります。
アルファテスト
アルファテストはピクセルのアルファ値の値で出力するかどうかを判断します。 判定は既に描き込まれているピクセルのアルファ値より大きいor小さいで判定します。![]()
深度テスト
深度テストは描画されたピクセルが現在描画されているピクセルよりも 手前 or 奥かどうかを判断し、その結果が出力するかを決めます。
深度バッファ(Zバッファ)
深度バッファとはピクセルに出力された奥行きを保存する領域です。 このバッファの値と新しく出力されるピクセルの奥行きを比較します。 深度バッファは「デプスバッファ」「Zバッファ」とも呼ばれています。![]()
ステンシルテスト
ステンシルテストとはステンシルバッファと呼ばれるバッファの値と ピクセルを描画する際に設定した参照値を比較して描画するかどうかを判定します。![]()
出力
これらのシェーダやテストを全て実行した結果、一つのモデルデータが レンダリングターゲットに出力されます。 そして、この内容を全てのモデルデータに対して行われたレンダリングターゲットを 毎フレーム画面に出力しているのが3Dゲームの描画ということになります。![]()