読者です 読者をやめる 読者になる 読者になる

しゅみぷろ

プログラミングとか

ForwardRenderingとDeferredShading

西川善司の3Dゲームファンのための「KILLZONE 2」グラフィックス講座(前編) -GAME Watch

docs.unity3d.com

docs.unity3d.com

ForwardRenderingとDeferredShadingについては上記サイトで詳しく書かれていました。 ここでは勉強を兼ねてForwardRenderingとDeferredShadingについて整理していきたいと思います。また、そもそもUnityのレンダリングがどのように行われているのかということもここでおさらいしていきたいと思います。

書いてて長くなってしまいそうだったので、ForwardRenderingとDeferredShadingそれぞれについての詳細は別記事にして、ここでは概要だけを書いていきます。

レンダリングの順序

複数カメラがある場合や、シェーダーの実行順に違いがある場合、何から優先的にレンダリングされるのかといったことから見ていこうと思います。

Unityの描画順は以下のようになっています。

  1. カメラのDepthが小さいものからレンダリングされる。
  2. 1つのカメラ内でのオブジェクトのレンダリング順は、RenderQueueによって決まる。これはShaderTagsのQueueによって指定される値で、DebugModeのインスペクターからマテリアルを見ることで変更したり確認したりできる。(RenderQueueが負数の場合はShaderTagsで指定されているデフォルトの値が使われる)
  3. RenderQueueが同じ場合、カメラからの距離によって描画順が決定する。RenderQueueがTransparent(3000)未満であれば、カメラから近い順に描画される(不透明オブジェクトの描画を効率的に行う)。Transparent以上であれば、遠い順に描画される。

カメラのレンダリングプロセス

1つ1つのカメラのレンダリングプロセスを見ていきます。

f:id:es_program:20160426003938p:plain

この画像は

Unity - マニュアル: グラフィックスコマンドバッファ

から拝借しました。カメラのレンダリングプロセスを図にしたものです。 少し情報を書き加えると

f:id:es_program:20160426003316p:plain

こんな感じでしょうか。順を追っていくと

  1. カメラはレンダリング時に、レンダリングするオブジェクトに対してForwardRenderingまたはDeferredShadingのどちらかを適用し、ライティングを計算する。
  2. 不透明オブジェクトの描画が終わったら、OpaqueImageEffectパスによって不透明オブジェクトにポストプロセスを適用することができる。
  3. Skyboxを描画する
  4. 透明なオブジェクトの描画をTransparenciesパスで行う
  5. レンダリングの全ての工程が終了した際に、ImageEffectパスでポストプロセスを適用することができる。

となっています。

なお、カメラがForwardRenderingとDeferredShadingどちらを適用するかの設定はPlayerSettingのRenderingPathから可能です。

f:id:es_program:20160426004008p:plain

また、カメラのRenderingPathから設定することも可能です。カメラのRenderingPathがUsePlayerSettingの場合にPlayerSettingで指定したRenderingPathを実行するようになります。

f:id:es_program:20160426004015p:plain

また、シェーダーでライティングを行うパスを指定する場合は、Pass内で

// ForwardRenderingでライティングを行う場合
Tags{"LightMode"="ForwardBase"}

// DeferredShadingでライティングを行う場合
Tags{"LightMode"="Deferred"}

を指定します。

ForwardRendering

詳細に関しては別記事で。

Forward Renderingパスは各オブジェクトを、オブジェクトに作用するライトにもとづいてひとつかそれ以上のパスを用いてレンダリングします。ライトそのものは、設定および強度によって、Forward Rendering により別々に扱われます。

ライティングの計算方法は3種類あり、オブジェクトに作用するライトによってその3種類のアルゴリズムを切り替えます。

ForwardRenderingでは、ピクセルシェーダーを動かして得た結果が深度テストで書き出さずに捨てられてしまうことも多く、これは無駄な演算になります。 また、マルチパスレンダリングでは何度も同じジオメトリで構成されたシーンをレンダリングするようなケースも出てきます(ジオメトリ処理の無意味な重複)。つまり、ForwardRenderingでは、画面に表示するフレーム内の総ピクセル数よりも多く演算してその結果を捨てたり、反復的に同じ計算を無駄に行なってしまうようなことが起こります。

DeferredShading

詳細に関しては別記事で。

遅延レンダリングと呼ばれ、その名の通り描画を遅延させるようなレンダリング手法です。

DeferredShadingではまず最初のパスで、G-Bufferと呼ばれるオブジェクトの描画に必要になりそうな情報を持ったテクスチャバッファを作成します。 次のパスでは、このG-Bufferで書き出されたテクスチャバッファに、ライトの情報からライティングを計算して書き加えていきます。 この2つのパスの実行後、G-Bufferを用いてポストプロセス的に画面を描画することが可能です。

DeferredShadingを使用する場合、オブジェクトに影響を与えることができるライトの数に制限はありません。すべてのライトはピクセルごとに評価されます。さらに、すべてのライトはクッキーとシャドウを持つことができます。

DeferredShadingは、ライティングの処理のオーバーヘッドはライトが照らすピクセルの数に比例するという利点があります。これはどれくらいのオブジェクトを照らすかに関係なく、シーンの中で光のボリュームのサイズによって決定されます。したがって、パフォーマンスは明りを小さくしておくことによって向上します。

不利な面は、DeferredShading は、アンチエイリアシングのための実際のサポートがなく、半透明のオブジェクトを処理することはできないことです(これらはForwardRenderingを使用してレンダリングされます)。Mesh RendererのReceive Shadowsフラグはサポートがありません。カリングマスクは限られた方法でサポートされているだけです。カリングマスクを4つまで使用できます。つまり、カリングレイヤーマスクは、少なくともすべてのレイヤー数から4を引いた数を含まなければなりません。よって、32レイヤーなら28を設定しなければなりません。そうしないと、グラフィカルなアーティファクトを得ることになります。

MRT(Multiple Render Targets)を用いるため、Shader Model 3.0 (もしくはそれ以降)によるグラフィックカードと2面ステンシルバッファが必要です。2006年以降に作られたほとんどの PC グラフィックカードは、GeForce 8xx 以降、Radeon X2400 以降、 そして Intel G45+ 以降のものなども含めDeferredLightingをサポートしています(MRTをサポートするいくつかの GPU は、まだ非常に限られたビット数のみサポートしています)。