Epic Gamesが配布している、Unreal Engineの様々な機能のサンプルをまとめたプロジェクト「機能別サンプル(Content Examples)」の中に、UE4.26では、Niagara AdvancedというMapがあります。
そこでは、Niagaraの新機能やそれを使った応用例など、とても参考になるサンプルが多く配置されていて、実装内容を見てみるとたくさんの学びがあります。
それらのサンプルについて、いくつかの記事に分けて解説を行っていきます。

ちなみに、機能別サンプルはEpic Games Launcherのラーニングタブからダウンロードできます。また、UEのバージョン毎に内容が違うので注意してください。
TLDR;)
- 4.26からNiagaraでGBufferに書き込まれている情報を取得することができるようになったよ
- 実際の位置とSceneDepthをもとに計算した位置を比較することで、意図しないParticleを調整できるよ
はじめに
この記事では、4.26から追加された新機能である、Sample GBuffer Attributesについて解説していきます。
この機能を使えば、GBufferに書き込まれている情報(BaseColor, Depth, Roughness, Metalicなど)を取得することができるので、ワールド上の物体からパーティクルを発生させる時に、質感を合わたりするといったことなどができます。
今回は、Niagara Advancedにある「1.4 Sample GBuffer Attributes」というサンプルの解説を中心に、この機能の説明をしていきたいと思います。
GBufferとは
サンプルの解説に入る前に、GBufferについて簡単に説明をしておきます。
GBufferとは、後のライティングやポストプロセスで使われるための中間バッファで、レンダリングパイプラインのBase Passの所で作成されます。
法線情報や、Metalic、Roughness、深度情報など様々な情報が書き込まれています。


Editor画面上部の、デフォルトではLitと表示されているボタンをクリックして、Buffer Visualization > Overview を選択すると、現在のGBufferを一覧で見ることができます。
書き込まれるのは、カメラに映っている範囲なので、この機能でNiagaraから取得できる値は、その時にカメラに映っているものに限られます。
1.4 Sample GBuffer Attributes の解説

このサンプルでは、グレイマンに、領域ごとに異なる色や、右半身と左半身で質感が異なるようなマテリアルがアサインされています。

Niagaraでは、このグレイマンの表面からParticleを出現させますが、その際に、GBufferを読み取り、色や質感を、出現する表面の色と質感に合わせるといったことをしています。
具体的に中身を見てみましょう。

注目する所は、Sample GBuffer Attributesのところだけですが、これはScratch Padモジュールをリネームしたものです。
他は、Skeltal Mesh LocationでMeshの表面からParticleを出し、重力で落下して、床と衝突するようにしているだけです。
ただ、Meshの表面からParticleを出すときにNormal方向に少しOffsetをつけています。後に出てくるDepthの比較のデモを分かりやすくするためについているものなので、なくても大丈夫です。

では、Sample GBuffer Attributes の中身を見ていきます。

まず、GBufferの値を取得しているところです。
GBuffer Accessのインプットに来るのは、GBufferというデータ型です。(がっつりExperimentalってWarning出てますね)

ParticleのワールドポジションからスクリーンのUVに変換し、Decode ○○ でGBufferの好きな値を取得できます。

今の所、取得できる値は、以上のようなものみたいです。

そして、取得した値を、ColorとDynamic Parameterに入れています。ここでは、BaseColor, Roughness, Metalicをマテリアルに渡して、色・質感を作ってます。
マテリアルでは、受け取った値をそのまま表示しているだけですね。

最後に、このサンプルでは、GBufferから取得したSceneDepthをもとに計算したワールド空間のポジションと、実際のポジションを比較する処理がHLSLで書かれています。そして、ズレすぎていた場合に、位置をSceneDepthの方に合わせる調整や、パーティクルを殺す処理が入っています。

ここで、In_SamplePosは実際のParticleのポジションで、GbufferDepthは、GBufferから取得したSceneDepthです。
カメラの位置と向きから、SceneDepthをもとにしたワールド空間のポジションが計算され、最終的にWorldPosOnDepthに入ります。そして、実際のポジションとの差分が、ProjectedDepthとして出力されています。

そして、入力値のSampled Depth ThresholdよりProjectedDepthの値が大きい場合は、実際のポジションとSceneDepthによるポジションのズレが閾値より大きいということで、入力値の下の二つのフラグのオンオフで、パーティクルの位置を調整したり、殺したりするようにしています。

ズレが大きくても殺さず、ポジションの調整もしない設定にした場合は、このようにグレイマンではなく後ろの壁をサンプリングしているパーティクルが残っているのがわかります。

SceneDepthの方に合わせる設定にしている場合は、後ろの壁をサンプリングしているパーティクルは、位置が調整されて、後ろの壁に張り付いています。
このように、GBufferのサンプリングは、あくまでスクリーンUVに基づいているので、欲しい所以外の部分をサンプリングしてしまう可能性があります。その際の調整方法として参考になりますね。(ちなみに、Meshを外れたところにここまでパーティクルがでてくるのは、Skeltal Mesh Locationで少しオフセットをつけてパーティクルを出現させているからです)
それと、Kill Particles If Too Far From Sampled Depthのフラグの方には間違いがあるので、以下のように直すとちゃんと動作するはずです。

おわりに
以上で、Sample GBuffer Attibutesの解説になります。まだExperimentalな機能なので、使うには注意が必要ですが、色々と面白い表現ができる気がしますね。
このサンプルでは、デフォルトで、グレイマン以外の所をサンプリングしたパーティクルは殺すようにしていますが、逆に、例えば、ボックス上に適当にパーティクルを配置した後、SceneDepthをもとに、背景のMesh達に張り付くようにすることもできる気がします。
GBufferの他の値を利用した表現や、エンジン改造してGBufferに好きな値を入れて利用してみるといったこともできると面白いかもしれません。
それらも今後やっていきればと思っています。
2021/04/10 追記
このSample Gbuffer Attributesを使って一つ作例を作ってみました。
GBuffer からNormal情報を読むことで、それを使ってParticleをMeshに這わせる処理をしています。
One Comment