Niagara Advancedを覗いてみる

# はじめに
Niagara AdvancedとはUE4.26からContent Examples(機能別サンプル)に追加されたNiagaraのサンプル集が入っているLevelです。
Simulation StageやAttribute Readerなどを使ったサンプルを見ることができます。
かなり複雑なものなので比較的簡単なものだけ見ていきます。
## 1.1 FillRenderTarget
最初に置いてあるやつです。
一見するとビルボードにテクスチャが張られているだけのようですが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/b8b61cd1-164c-683b-92d8-f3951112286f.png)
内部ではSimulation Stageでテクスチャをレンダ―ターゲットにコピーしてマテリアルに渡しているようです。
そもそもSimulation Stageとは何なのか分かっていなかったのですが、コメントで説明が書かれていました。
>Think of a simulation stage as an additional "stack" like Particle Update. The difference is it can iterate, meaning run multiple times on a single frame across all the elements in it.Think of it like a "For Loop" in the stack.

意訳するとParticle Updateのような追加のスタックで、反復処理ができてパーティクルやData Interfaceに対するFor Loopのようなものらしいです。なるほどわからん
また、Data Interfaceなら何でも使えるというわけではないようです。

このEmitterのIteration SourceにはRender Target 2Dが設定されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/71476418-f65a-a7e7-90da-48c84802a6d6.png)
内部ではIndexからUVを計算して色をコピーしています。
ここでのExecution IndexはIteration Sourceに対するものなのでRender Target 2Dの各テクセルになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/1d6f5bf7-912f-0f5a-4da0-ddcfd978b31f.png)
Render Targetをセットした後はTexture ObjectとしてMaterialに渡しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/9bec8e5e-3990-552c-dc8d-b53a7014fc5f.png)
Material側
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/48c7305f-00f0-d689-8101-5ff25a3762bc.png)
## 1.4 SpawnOnGBuffer
UE4.26から追加されたData InterfaceのGBufferを使ったサンプルです。
色が異なり、半分金属のグレイマンから同じ質感の粒々が垂れています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/e8b1cc8d-11f3-028a-a847-78a963e90348.png)
GBfferはView Modeから見ることができるやつです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/f9b5975e-aa93-e5cb-6cce-cf2eecf86152.png)
このサンプルではスポーン時にScreen UVを計算してベースカラー、メタリック、ラフネスをDynamicMaterialParameter経由でコピーしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/771e29cc-a6d1-767d-2e3f-de91d2f2c32d.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/7df5a6b1-fe5d-ec6d-2b0b-9c901c87d123.png)
また、深度が一定の閾値以上であればKillするという処理があり、その判定に使用する値を算出する処理がHlslで書かれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/a4401456-6749-fad3-41ac-513fa4ff5406.png)
Custom Hlslを使用したサンプルが少ないのでありがたいですね。
## 2.1 AttributeReaderRing
Attribute Readerを使用したサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/220a94d6-09e5-7d26-6dc1-3d6ff7c37300.png)
円状に移動するParticleが通過したところの色が変化するというものです。
始めにAttribute Readerを作成して読み取るEmitter名を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/92ee1032-0cd6-7ca2-c07b-33e9a6324e4c.png)
そうするとModuleやScratch Pad内でGet○○で他EmitterのAttributeを読み取れるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/8d0d1496-bbd2-c21b-1606-7b75f7212202.png)
ParticleのAttributeであればInitial.○○やModule名.○○といったものも読み取ることができます。

このサンプルではありませんが、コメントに赤字でAttribute Rederを使用する際にEmitter Spawnに一度だけセットすることが推奨されているようなことが書かれていました。
>Only one attribute reader can exist at a time. It can be used in multiple locations however. It is good practice to define it at Emitter Spawn for general use.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/7bf55acc-daec-5594-dffb-7de247e27f91.png)
以前まではModuleやScratch Pad内で新規に作成していたので参考にさせて頂きます。


## 2.2 AttributeReaderFollow
赤い粒の周りに緑の粒が追従するサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/ea6c6a80-9af8-e05b-a406-9a8726782cb8.png)
Get Num Particlesという関数を使用して他Emitterのスポーン数が参照してランダムIDを取得し、IDからPositionを読み取っています。
(このノード知りませんでした。毎回手動で入力していたので助かります。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/199b3178-4887-a544-c7a9-213482f3c900.png)
IndexとIDの違いですが、IDはIndexとは異なりフレーム間で安定していることが保証されているそうです。
また、IDの読み取りをする際はRequires Persistent IDsにチェックを入れていないとエラーが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/534ec714-c815-273d-8404-6dcca3b12fe4.png)
## 2.3 AttributeReaderStreamers
他EmitterのParticleからスポーンするModuleのサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/eddfb120-203f-621f-317d-8303a3ce2f24.png)
UE4.26から追加された新機能ですね。
Spawn Particles From Other EmitterとSample Particles From Other Emitterをセットで使用するようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/f99e806d-1ea4-1813-6725-74e5b954f7c4.png)
Spawn Particles From Other Emitterで読み取り先のEmitter名の指定やSpawn Rateの設定などが行えます。
Sample Particles From Other EmitterではInitialize Particleで設定できるような値を参照するかどうかなどの設定ができます。
デフォルトではPositionのみになっているようです。

このModuleはGPUとCPUの両方で動作すると書いてありましたが、GPUからCPUのような組み合わせでは動作しなかったので注意。

| 読み取り先   |      読み取り側      |  スポーンするか |
|----------|:-------------:|------:|
| CPU |  CPU| する |
| GPU |    GPU   |   する |
| CPU | GPU |    しない|
| GPU | CPU|    しない |
## 3.x
Neighbor Grid 3Dというのを理解していないのでよくわかりませんでした。申し訳ありません。
ただ、Neighbor Grid 3Dを使うと近傍のParticleの情報を読み取ったり出来るみたいです。（使えるようになりたい。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/7e308e80-ef6e-b402-c3f4-4c4fc5738c7c.png)
画像は3.7 Plexus
## 4.1 Component Renderer
UE4.26の新機能Component Rendererのサンプルです。
グレイマンがにょきにょき生えてきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/1e3ad358-ddd5-8d41-7572-a8ca52c2a16f.png)
Scene Conponentを継承していれば何でも使えるようです。
また、このサンプルではSkeletal Meshのアニメーションの速度をNiagara側から設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/f3539bb9-44bb-e979-c3dd-a5dae9553aa2.png)
Particle SpawnでAnimationPlayRateというAttributeを設定してComponent Rendererから関数を呼び出しているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/ea7e643f-b1a1-0c1f-9a61-bd8d44b49cae.png)
Component側では受け取る変数名とSet ○○ (○○は変数名)という関数を用意しておけばよいようです。

試しに関数呼び出し用のCompoentを作成してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/552e7138-7bde-f245-e98c-a08d4716d85f.png)
Testという名前の変数とSet Testという関数を作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/f8717814-4d75-c890-a7fe-02f3642950b3.png)
Niagaraに今作ったComponentを追加してみると変数名の項目が確かに追加されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/ad7f8a63-4b3e-d534-a39a-f7e31ad7fb9a.png)
Particle.Positionをセットしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/ee628408-0ef2-879c-6fc9-54b29b0b84e3.png)
スポーンしたComponentごとに関数が呼び出されていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/ee9fed59-8e15-b124-b1c7-8587c18db9af.png)


# おまけ
このサンプルを見ていていくつか個人的な発見をしたので紹介します。


- Dynamic InputsにもScratch Padが使える。
- Niagara版InterpToのInterpolateOverTime_Float
- SpriteBasedLineというModuleを使うことでGPUSimでもRibbonのような表現ができる。
- RenderのBindingsからAttributeをセットできる。
- Dynamic InputでReturn Normalized Exec Indexが使える。

__続いて通常のLevelにも新たにサンプルが追加されているようなので見てみます。__
## 4.1 Play Audio Per Particle
UE4.26の新機能でNiagaraからオーディオを再生するサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/500f50cb-1727-63da-acb8-786cad72dd69.png)
プレイしなくても音が鳴るんですね
Audio関連で追加されているModuleは3つあります。

- PlayAudio
- PlayPersistentAudio
- UpdatePersistentAudio

__PlayAudio__
BooleanのAttributeがあり、Trueになったタイミングで一度だけ再生されるようです。
(Sound Waveの設定でLoopingにチェックが入っていると音が止まらないので注意)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/92dc3080-56a6-2eb1-e8fb-8fa081ca31db.png)
再び再生させるにはEmitterのCycleが更新されるか、Particle.HasPlayedAuioをFalseにする必要があります。
こののサンプルではDATA INSTANCE.Aliveの反転が設定されているのでParticleがKillされたタイミングで再生されています。

もう一つのEmitterの方ではCollisionValidが設定されていて衝突したタイミングで音が再生されるようになっています。
CollisionValidはCollisionのModuleを追加すると自動で作成されるAttributeです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/6261360d-f8a9-e974-5a3e-8280d543f252.png)
__PlayPersistentAudioとUpdatePersistentAudio__
こちらは動的にピッチやボリュームを変化させたいときに使うものです。
このサンプルではFindKineticAndPotentialEnergyというModuleで計算された中央のトーラスの力学的エネルギーがピッチとボリュームに連動しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/a9e88c9f-3006-fa68-dea4-24f1f5bb3129.png)
## 4.2 RendererWithNoParticles
EmitterのAttributeをもとにSpriteを表示するというサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/14ee2e74-b37b-761f-f42b-b5e1e060af73.png)
中を見てみると0 Particlesとなっているのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/7a022d69-235c-df6a-52bf-f53563d32fcc.png)
Sprite RendererではSoure ModeがEmitterに設定されており、Bindingsの項目ではEmitterの各Attributeがバインドされていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/62fd6e90-5991-930f-a659-d5c41b259f86.png)
こちらを使うメリットですが、コメントには単一のSpriteの場合はパフォーマンスが向上し、Simulation Stageで流体のシミュレーションなどをレンダ―ターゲットに書き込むといった場合なども便利と書かれていました。

単一のSpriteはともかく流体のシミュレーションをする機会はなさそうですが機能として知っていて損はないと思います。
## 4.3 Mesh Orientation vs. Rotational Force
メッシュの回転に3種類あるというサンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/88ab472d-5dde-10bf-20a7-0f4f381ede20.png)

- Direct Orientation
- Rotational Velocity
- Rotational Force

上の3つがあります。

__Direct Orientation__
Direct Orientationは直接回転を指定するので直線的な動きでDragも考慮されません。

__Rotational Velocity__
Rotational Velocityは初速を与えるのでそのままでは直線的な動きですがDragやMassが考慮されます。
サンプルではParticle SpawnでRotation Forceが設定されています。
ここをAdd Rotational Velocity Moduleにすると初速にMassが考慮されないようになるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558809/7e471337-8ff5-2360-d5de-5031fe40c559.png)
__Rotational Force__
Rotational Forceは力を与えているので加速します。こちらもDragやMassが考慮されます。
(高校で習う力学の位置、速度、加速度の関係が回転に変わったというイメージだと思います。)

# おわりに

Niagara完全に理解した状態の自分には難しかったです。HlslやSimulation Stageが使えるようになるよう精進して参ります。
また、よいサンプルがたくさん公開されたのでこれを機にSimulation Stageの情報が増えてくれることを願います。

UE4.26のリリースノート
https://docs.unrealengine.com/ja/WhatsNew/Builds/ReleaseNotes/4_26/index.html

Niagaraのドキュメント
https://docs.unrealengine.com/en-US/RenderingAndGraphics/Niagara/index.html