【UnityShader】Deferred Shading #114
はじめに
Deffered Shadingについて勉強していきます。
Forward Rendering
各オブジェクトを1つ、または複数のパスで描画するものになります。
パスの数は、オブジェクトに作用するライトによって決まります。
ライティング
Forward Rendertingには以下の3つのライティングが存在します。
ライティング名 | 意味 |
---|---|
ピクセルライティング(Per-pixel) | ピクセルごとに計算される高価なもの |
頂点ライティング(Per-vertex) | 頂点ごとに計算される安価なもの |
球面調和ライティング(SH) | 頂点で複数のライトの球面調和による計算コストが実質0だが、あくまで近似なので精度は低い |
これらをUnityが自動で割り振ってくれます。
パス
パスは以下の2種類があります。
パス名 | 意味 |
---|---|
ベースパス | 1つのディレクショナルライトと全ての頂点ライティング、球面調和ライティングでオブジェクトをレンダリングする |
加算パス | 追加されたピクセルライティングでオブジェクトをレンダリングする |
問題点
ディレクショナルライト以外のピクセルライトは、加算パスでレンダリングされます。
これはひとつのライトごとにひとつのパスを使用するものになります。
つまり、1つのオブジェクトに対して複数のライトが当たる場面等で非常に負荷がかかってしまいます。
また、ピクセルライティングから頂点や球面調和ライティングに変更させても、これらは精度が低いものとなるので、不自然な描画結果になってしまう可能性があります。
Differd Rendering
こちらは2パスで描画する手法になります。
パス
パスは以下の2種類があります。
パス名 | 意味 |
---|---|
G-Bufferパス | 各オブジェクトを1回レンダリングするもの 描画に必要なデータをG-Bufferとしてテクスチャに書き込む |
ライティングパス | G-Bufferと深度に基づいてライティングを計算するパス |
G-Buffer
G-Bufferはテクスチャとして各データを保持しているものになります。
1パス目で、描画に必要なデータをG-Bufferに書き込きます。
2パス目以降で、このテクスチャを使用して描画していきます。
これらのテクスチャはグローバルシェーダーのプロパティとして、設定されます。
詳しくは以下となります。
プロパティ名 | 意味 | 備考 |
---|---|---|
_CameraGBufferTexture0 | Diffuse Color(RBG), occlusion(A) | |
_CameraGBufferTexture1 | Specular Color(RBG), roughness(A) | roughness = 1.0 - smoothness |
_CameraGBufferTexture2 | 法線ベクトル(RBG), 未使用(A) | |
_CameraGBufferTexture3 | Emission + lighting + lightmaps + reflection probes | カメラがHDRレンダリングを使用している場合、Emission + lightingのRenderTargetsは生成されない 代わりに、カメラがレンダリングするターゲットがRT3として使用される |
_CameraGBufferTexture4 | Light occlusion(RGBA) | ShadowmaskかDistanceShadowmaskのライトモードを使用している場合に使える |
_CameraDepthTexture | Depth + Stencil |
メリット
ライティングを2パス目でまとめて行うため、ライトを増やしても負荷がかかりにくいことが挙げられます。
また、オブジェクトに影響を与えられるライトの数に制限が無く、ピクセル毎に評価冴えるため正しく描画されます。
デメリット
半透明のオブジェクトを正しく描画できない
これはG-Bufferパスで情報を2次元のテクスチャに書き込んでしまうからになります。
このパス段階ではブレンドができず、G-Bufferには1ピクセルにつき1つのデータしか保存できないため不透明と半透明の情報を同時に保持できません。
これにより、オブジェクト同士の前後関係が無くなってしまい、半透明が正しく描画されなくなってしまいます。
MSAAが使えない
G-Bufferを全てMSAA用に変更する必要があります。
また、各サブピクセルでライティングを行う必要があり結果的にSSAAと負荷がそこまで変わらなくなってしまうからになります。
MSAA
1ピクセルをより小さなサブピクセルと呼ばれるもの二分割します。
この分割数はMSAAの手前に付いている値に応じて変化し、4xなら4分割、8xなら8分割になります。
このサブピクセルの深度を求め、深度の差が大きい箇所をエッジとして色を求める手法になります。
実装
適当にScene上にオブジェクトを配置します。
CameraのRendering PathをDeferred
に設定して終了になります。
結果
フレームデバッグ上に各Textureが出ています。
CameraDepthTexture
ShadowMapTexture
GBufferTexture0
GBufferTexture1
GBufferTexture2