Screen Space Fake Omnidirectional Shadow

deferred shading なら、光源位置→ピクセル位置に向かってレイを飛ばして、途中の位置バッファの Z がレイより手前の箇所があったらライティング処理中断すれば、ポストエフェクトで超高速に影を出せるんじゃね?と思いついてやってみた図。

光源位置→ピクセル位置 間を 10 回サンプリング。120 FPS 出ていました。


遮蔽されてたら即中断ではなく、減衰させるようにすればソフトシャドウっぽくなるんじゃね?と思いついてやってみた図。
omnidirectional_soft_shadow


ぱっと見かなり良い感じに見える絵が出てるんじゃないかと思いますが、問題が 2 つあります。
・位置バッファには一番手前のピクセルしか情報が残っていないため、立体交差を表現できない (そのピクセルは手前から奥まで全部遮蔽されてることになってしまう)
・画面外のオブジェクトの影は出せない (上の動画でも右端とかがたまにおかしくなっている)


後者に関しては、カメラの視錐台に入ってないライトはフェードアウトさせる、とかごまかしようがある気がしますが、前者が致命的です。手前にパーティクルが一粒来ただけでその光源は消失してしまいます。
今作のような、見下ろし視点で光源盛りだくさんゲーならこのままでも実用に耐えそうですが、今後を考えてスマートにポストエフェクト影を実現する方法が欲しいところです。以下、実装までは行ってませんが、思いついたアイデア群。


・裏面描画した位置バッファも作っておき、表面に遮蔽されている && 裏面に遮蔽されていないとき遮蔽と見做す
裏面の位置バッファを作る負担がでかい上、1 オブジェクト分しか交差を表現できない。


・モデルが全部立方体or球という前提の元、全ピクセルに描画元の立方体/球データを持たせて、その形状データと内外判定する
このゲームでしか使えない手法。裏面描画と同等の結果を 1 パスの GBuffer 生成で得られるはず。しかしやっぱり 1 オブジェクト分しか交差を表現できない。


・上記の案の発展。モデル群を Z 座標でソートして奥→手前の順で描画し、DirectX11 で加わった機能である StructuredBuffer で、描画された形状データをピクセル毎にリンクリストで記録。その形状データ群と内外判定する
立体交差も完璧に表現できるはず!ただしこのゲームでしか使えない。


・最初の案の発展。裏面描画、表面描画別々に StructuredBuffer に Z をリンクリストで記録。表面に遮蔽されてる数 != 裏面に遮蔽されてる数 なら遮蔽されていると見做す
2 パス必要なものの、任意の形状の立体交差を表現できる?



StructuredBuffer をまだ使ったことがないのでほんとに実現できるかわからんのですが、Order Independent Transparency みたいな使い方ができるそうなので行けそうな雰囲気はあります。