CG理論 #1 レンダリングパイプライン [Devlog #002]

Table of Contents

CG屋さんのバイブル:Real Time Rendering Fourth Edition を読んで理解したことについてを要約します(内容の転載を避け、詳しく説明しすぎないように配慮します)

レンダリングパイプライン


レンダリングパイプラインの主な機能は、視点(仮想カメラ)、光源、3次元オブジェクトから2次元イメージをレンダーすること

(2次元イメージ中の)オブジェクトの位置と形を決定するもの

  • 幾何学形状(ジオメトリ)
  • 環境特性
  • カメラ配置

(2次元イメージ中の)オブジェクトの見た目を決定するもの

  • マテリアル特性
  • 光源
  • 表面テクスチャ
  • シェーディングの式

アーキテクチャ

レンダリングパイプラインはいくつかのステージからなり1、スピードアップを主な目的として並列に実行される

主なステージ(各々でさらにいくつかのサブステージで構成される)

  • アプリケーション(衝突検出、アニメーション、物理シミュレーションなど)
  • ジオメトリ処理(座標変換、投影などの幾何学的処理)
  • ラスタライズ(3つの頂点から三角形の内側のピクセルを求める)
  • ピクセル処理(ピクセル単位での処理(色や深度など))

フレーム間に実行する計算の複雑さによってフレーム/秒が変化し、これによりレンダリングの性能を表すことが一般的

アプリケーション

開発者はこのアプリケーションステージで何が起こるのかを制御する

アプリによって一番の違いが見られるのはレンダリングパイプラインの中でもこのアプリケーションステージであると思われる

アプリケーションの作業は基本的にCPU上で実行するが、コンピュートシェーダーを使ってGPU上で実行することもある

レンダーすべきジオメトリ(点、直線、三角形)をジオメトリ処理ステージに渡すのが主なタスク

ユーザからの入力情報を扱ったり、描画する必要がないポリゴンを求めるカリングアルゴリズムを実行したりと様々な処理を行う

[DX12] Input-Assembler(頂点情報やインデックス情報の入力)

Input-Assembler(入力アセンブラー)は頂点情報だけではなく、“どの3頂点を組み合わせて三角形を作るのか"という情報などが入力されるステージ

ポリゴンの表示のためには、数値(バイトの塊)を解釈するための頂点レイアウトインデックス情報、そしてもちろん頂点情報(バイトの塊)が入力情報として必要になる

ジオメトリ処理

ジオメトリ処理ステージでは、幾何学形状(ジオメトリ)を三角形単位と頂点単位で操作する

ジオメトリ処理ステージのサブステージ(機能ステージ)

  • 頂点シェーディング
  • 投影
  • クリッピング
  • スクリーンマッピング

頂点シェーディング

頂点シェーディングでは、頂点位置を計算し、頂点出力データにもたせる法線やテクスチャ座標などを評価する

頂点シェーダーのもともとの仕組み2

  1. 各頂点の位置と法線に光源を適用して色を計算
  2. 頂点の色を三角形上で補間

頂点シェーダーは各頂点に関連付けたデータの設定を行う

頂点の計算

  1. モデル空間にモデルが存在(モデルのいずれかの頂点や近傍などに原点をとる)
  2. モデル変換により、モデルごとにモデル空間内での位置と向きが決まる
  3. オブジェクトはモデル座標(=ローカル座標:モデル空間の座標)をもち、モデル変換が適用されると、ワールド空間内でのワールド座標が決まる

カメラ空間での頂点の計算

  1. ビュー変換により、カメラを原点としたカメラ空間での座標が決まる
    (視線がZ軸(負or正)方向、上がY軸、右がX軸 ※API依存)

モデル変換とビュー変換のいずれも4×4行列として実装できる

シェーディング

シェーディングでは、各オブジェクトのマテリアルとそれを照らす光源による効果を決定する見た目のモデル化を行う

各点におけるシェーディングの式の計算は、ジオメトリ処理の間に行うものもあれば、ピクセル単位の処理で行うものもある

続くステージに出力する色、ベクトル、テクスチャ座標、その他のシェーディングデータは、頂点ごとに格納されたマテリアルデータ(点の位置、色、シェーディング式の評価に必要な数値情報など)を用いて算出される

投影からクリッピングへ

正準ビューボリュームは、端点が(-1,-1,-1)(1,1,1)にある単位立方体で、0 <= z <= 1等のボリュームを使って定義される

頂点シェーダーが行う投影

  • 正投影(平行投影) -> 直方体のから単位立方体に変換
  • 透視投影 -> ピラミッド形状の錐台から単位立方体に変換
  • その他:斜投影や不等角投影など

変換はいずれも4×4行列として実装できる

変換により、モデルのクリップ座標が決まり、Z軸座標の情報はZバッファーに格納されることで3次元から2次元に投影される

[DX12] Vertex Shader(頂点シェーダー:頂点座標変換)

頂点シェーダーは、以下の役割を担う

  • 平行移動や回転の変換
  • カメラ用の変換
  • スクリーンへ投影する変換

また、ボーンによる頂点変換も頂点シェーダーの役割である

頂点処理の追加オプション

  • テッセレーション
  • ジオメトリシェーディング
  • ストリーム出力

テッセレーション

テッセレーションとは、三角形や四角形(線分を含む)をより細かい三角形に分割することで、実行時により精密な表現を可能にする処理である

またテッセレーションは、頂点のセットで作られるパッチのセットで表現される曲面サーフェイスから三角形のセットに変換することもする

サブディビジョンサーフェスやハイトマップといった、実際に細かく頂点を調整する緻密な表現などにも応用される

  • ハルシェーダー
  • テッセレーター
  • ドメインシェーダー

シーン上でのカメラからの距離に応じて、適切な数の三角形を生成することで、処理時間とメモリの無駄を省く

テッセレーションについての参考ページ:テッセレーションの概要

[DX12] Hull Shader(ハルシェーダー:パッチをどう分割するか設定)

頂点シェーダーからくる入力パッチ情報から、出力パッチ情報とパッチ定数を生成する

ハルシェーダーには、実際にテッセレーターに分割するための設定(分割数や分割の仕方)を記述する

頂点シェーダーからくる頂点データをパッチ(3つ一組 or 4つ一組)として扱い、分割の目安になる座標データ入力コントロールポイントとして扱う

パッチごとに実行される関数パッチ内のコントロールポイントごとに実行される関数が必要になる

[DX12] Tesselator(テッセレータ:パッチを分割)

ハルシェーダーで設定されたパッチデータをもとに、テッセレーターが実際に分割を行う

基本的にプログラマが行えることはない

[DX12] Domain Shader(ドメインシェーダー:生成頂点を設定)

テッセレーションにより分割された結果、最終的にできた頂点を扱う

ドメインシェーダーは、出力されたパッチ定数コントロールポイントドメインロケーション(分割後の頂点座標を決めるためのパラメータ)を受け取る

ジオメトリシェーディング

ジオメトリシェーダーは、様々な種類のプリミティブから新たな頂点を生成する

最もよく使われるのがパーティクルの生成で、花火の爆発を例とすると、それぞれの火球を1つの頂点で表し、視点を向いて何ピクセルかに広がる正方形に変えるといった処理ができる

[DX12] Geometry Shader(ジオメトリシェーダー:頂点を増やしたりする)

プリミティブ単位で(三角面なら頂点3つを一組にして)加工処理が行われる

座標の移動だけでなく、面数を増やすことも可能で、壁などに影を投影するための"シャドウボリューム"や"フィン法ファー表現"などに活用される

作られる頂点数の最大値の指定なども行われる

ストリーム出力

処理した頂点をパイプラインの下流に送る代わりに配列に出力し(GPU上のメモリに書き込み)、頂点データの処理を行うことができる

花火を例としたパーティクルシミュレーション等で使われる

クリッピング

続くステージにはビューボリューム内にあるプリミティブだけを渡すため、部分的にビューボリューム内にあるプリミティブに対してクリッピングを行う必要がある

単位立方体外のプリミティブは破棄され、完全に内側のプリミティブは保持され、単位立方体と交わるプリミティブは単位立方体でクリップし、新たな頂点を作成して古いものを破棄する

投影によって得られる同次座標を使い、クリップ空間(同次座標系)でクリップを行い、透視除算することで3次元正規化デバイス座標に配置する

スクリーンマッピング

3次元座標データのクリップ済みのプリミティブを、スクリーン座標とz-座標を合わせたウィンドウ座標に変換する

スクリーンマッピングによる平行移動とスケーリング操作が行われ ($x_1 < x_2$ かつ $y_1 < y_2$) 、z-座標も($z_1 < z_2$)としてマップされる
(OpenGL:[-1,+1]、DirectX:[0,1]、デフォルトでは $z1 = 0、z2 = 1$ )

ラスタライズ

ラスタライズ(走査変換)ステージでは、レンダリング画面空間のプリミティブ(三角形の中にある全てのピクセル)を求め、画面空間の2次元頂点から画面上のピクセルへの変換を行う

ラスタライズ

  • 三角形セットアップ(プリミティブアセンブリー)
  • 三角形トラバース

ラスタライズは三角形だけでなく、点と直線も扱う

三角形がピクセルに重なっているかどうか(内部性)を決定する仕組みは、GPUのパイプラインの設定に依存し、

  • ポイントサンプリング(各ピクセルの中心の1点が三角形の内側にあるか)
  • スーパーサンプリング アンチエイリアシング(出力解像度の数倍の解像度でサンプリングする)
  • マルチサンプリング アンチエイリアシング(↑を発展させ、三角形の内側部分の計算を省略する)

といったアルゴリズムを使う

三角形セットアップ

三角形セットアップは、三角形のデータ(差分、辺の式など)を計算し、ジオメトリーステージからのシェーディングデータ三角形トラバースの補間に使われる

三角形トラバース

三角形トラバースは3、三角形の内側にあるサンプルやピクセルを求める

ピクセルの三角形と重なる部分にフラグメントを生成する

各フラグメントのプロパティは、フラグメントの深度シェーディングデータを含み、三角形の頂点間で補間される

三角形上の遠近補間も行う4

[DX12] Rasterizer(ラスタライザー:頂点をピクセル化)

テッセレーターと同様に、プログラマが手を出せないブラックボックスステージ(もちろん、オプションの指定は可能)

  • 頂点の並びから裏か表かを判断し、描画すべきかどうかを決定する
  • そのピクセルが塗りつぶし対象となるかどうかを判断する
  • 頂点情報を補間してピクセルシェーダーに渡す

ピクセル処理

ピクセル処理ステージでは、ピクセル単位、サンプル単位の計算と操作を行う

ピクセル処理

  • ピクセルシェーディング
  • マージ

ピクセルシェーディング

ピクセル単位(フラグメントごと)のシェーディングの計算処理は、シェーディングデータを入力として、1つ以上の色情報を出力する

開発者はピクセルシェーダー(フラグメントシェーダー)にプログラムを供給し、プログラマブルなGPUコアで実行させる

オブジェクトに1つ以上のイメージを貼り付けるテクスチャリングはここで行われる

[DX12] Pixel Shader(ピクセルシェーダー:ここでテクスチャ等を参照する)

ラスタライザーが塗りつぶすべきだと判断したピクセルに対し、補完された頂点データを引数として、ピクセルを最終的に塗りつぶす色(画素値情報)を返すのがピクセルシェーダーである

頂点シェーダーで頂点に色を付けておけば、勝手に補完されてグラデーションになる

ランバートの余弦則によるシェーディングの計算を頂点シェーダーで行えば、ピクセルシェーダーはただ入力された色を返すだけだが、たいていの場合、明るさの計算がピクセルシェーダーで行われる

頂点情報のuv情報から補間されたuv座標をもとに、テクスチャから色を抽出してポリゴンに色を付ける

  • マテリアルの色やテクスチャの色を調べる
  • シェーディングを行い濃淡を計算する
  • 調べた色情報と濃淡を合成した色情報を出力する

また、最近ではマルチパスレンダリングなどで、ポストエフェクトやシャドウマップなど複雑な処理を行うのにも使用される

マージ

マージ(ROP:ラスター操作、レンダー出力ユニット)

ピクセル単位の色情報(RGB)をカラーバッファに長方形配列で格納する

ピクセルシェーディングから送られるフラグメントの色を、既にカラーバッファに格納されている色とブレンドする

z-バッファ(深度バッファ)アルゴリズムを用いて可視性の決定も行い、ピクセル単位で最も近いプリミティブのz-値をカラーバッファと同じサイズと形で格納する

同じピクセルにおいて、z-値を比較することで描画する色を更新する

z-バッファ(深度バッファ)はピクセルごとに1つのz-値しか格納しないので、部分的に透明なプリミティブに使うことができず、透明度を表現できない

アルファチャンネルはカラーバッファに関連付けられ、ピクセルごとの不透明度の値を格納する

完全に透明なフラグメントはピクセルシェーダープログラムで選択破棄操作が行われ、z-バッファーに影響を与えないようにする(旧APIでは破棄操作にアルファチャンネルのアルファテスト機能が使われていた)

ステンシルバッファは、オフスクリーンバッファ(画面表示が行われないフレームバッファ)であり、ステンシルバッファにレンダーした内容を使うことでカラーバッファとz-バッファを制御する

このようなマージ・ブレンド操作を行うことで、透明度や色の累積などの効果が生まれる

画面にはカラーバッファの内容が表示されるが、ラスタライズされて画面に送られている途中のプリミティブが見えるのを避けるため、ダブルバッファリングが行われる

バックバッファでレンダリング処理を行い、垂直帰線期間でフロントバッファと交換する

[DX12] Output-Merger(出力マージャー:レンダーターゲットや深度への出力)
  • どれが手前に来て、どれが奥に来るのか
  • 半透明ならば、先に描画されているオブジェクトとどのようにブレンドするのか

などを考えて、既に描画済みの色との合成を行う(一方のピクセルシェーダーはあくまで色を決めるだけのもの)

  • 深度テスト(Z値テスト)を行うか否か
  • どのようにブレンドするか(αブレンディングや加算など)

といった設定を、各種定数を用いて行う





まとめ - パイプラインでのモデルの行方

点、直線、三角形は、モデルやオブジェクトを構成するレンダリングプリミティブである

モデルはシーンの画面上のウィンドウに遠近法でレンダーされる

アプリケーションステージ

アプリケーションステージでは、ユーザからの入力(マウスの動きなど)に対応する回転行列をモデルに適用させる

例えば、モデルのパーツをユーザが選択して移動させたり、カメラを事前に定義した線路に沿って動かせたり

位置と向きなどのカメラパラメータを時間に応じて更新し、レンダーするフレームごとにカメラ位置、光源、モデルのプリミティブをジオメトリ処理ステージに渡す

ジオメトリ処理ステージ

アプリケーションステージで以下を算出済みであるとする

  • オブジェクトの自身の位置と向きの両方を記述する行列(オブジェクトごとに)
  • 投影行列
  • ビュー変換行列

ジオメトリ処理ステージでは、頂点と法線を上記の行列で変換し、オブジェクトをビュー空間に入れる

単位立方体でクリップし、ウィンドウにマップする

ラスタライズステージ

プリミティブ内のすべてのピクセルを求める

ピクセル処理ステージ

プリミティブごとにピクセルの色を算出する

テクスチャが関連付けられている三角形は、それを適用してレンダーする

可視性はzバッファアルゴリズムと破棄オプションやステンシルテストを使う