参考資料を元にした、UE5のNiagaraによる落ち葉の発生・積み上げ・吹き飛ばし表現の実装サンプルです。
- 特徴
- NeighborGrid3Dによる高速衝突判定を利用したParticleの積み上げ
- Niagara Data ChannelによるGPU Emitter間の通信を利用したParticleの挙動遷移
- Field SystemによるParticleの挙動制御
L_Leaf_CinematicsレベルをPlayするとこちらが流れます。
Play直後にViewportを左クリックし続けるとこちらが流れます。
- Windows
- UE5.6.0以降
- 要Clone(Git LFSを使用しているため、Download Zipでは動作しません)
- チュートリアルではありません
- 学びたい場合は参考資料を読まれたし
- 最適な実装ではありません
- 読みにくい、効率が悪い、負荷が高いやり方をしている箇所がある
- 環境によっては適切に動作しません
- It works on my machine...
- と言いたいところだが、自分の環境でも安定しない部分がある。助けて
- It works on my machine...
使用されている素材の一部は、Epic Games, Inc. の商標ならびに著作物です。Epicは無断転用を禁じます。本素材はEpicの公式素材ではなく、Epicにより承認されていません。
Content/LeafVFX/VFX/Leaf/NS_Leaf が演出本体です。
Content
├─Characters
│ └─Mannequins // UE5.6テンプレのManny。無改造
│
└─LeafVFX
│ LS_Leaf_Cinematic.uasset // 使用例1。Playすると出る
│ LS_Leaf_Flying.uasset // 使用例2。PlayしてViewportで左クリック押しっぱで出る(Level BPで判定)
│ L_Leaf_Cinematics.umap // 使用例の構成レベル
│ L_Leaf_Test.umap // NS_Leaf動作確認用レベル
│ MoviePipelinePrimaryConfig.uasset // 映像出力時の設定
│
├─Sensei // a.k.a. Blueman
│ │ A_Sensei_Dead.uasset // LS_Sensei_DeadにLinkしたAnimation Sequence
│ │ LS_Sensei_Dead.uasset // 横たわるSenseiの姿勢作成用
│ │ MR_Sensei.uasset // Senseiの制御リグ。ボディのポーズぎめに使用
│ │ SK_Sensei.uasset // エンジン組込のTutorialTPPからSurpport Uniformly Distributed Sampling有効化したもの
│ │
│ └─Materials
│ MI_SenseiMasked.uasset // Sensei_1st用
│ MI_SenseiMasked_NextTarget.uasset // Sensei_2nd用。パラメータ制御を分けるためだけに存在するがDMIで済んだ気も
│ M_SenseiMasked.uasset // 葉っぱ出した時にMaskで消す用のMaterial。Sequencerでパラメータ制御
│
└─VFX
├─Leaf // 葉っぱVFX
│ │ customPBD_IntraParticleCollision.uasset // 組み込みのPBDモジュールをSleep時に何もしない様に改造
│ │ FS_MasterField_Custom.uasset // 演出用にDirectional Magnitude変数をExpose to CinematicsしたField Actor
│ │ NDC_LeafSeed.uasset // 種 -> 積み上げ -> 吹き飛ばしEmitter間の通信用チャネル
│ │ NM_QueryPhysicsField.uasset // Field Systemから外力を拾うNiagara Module
│ │ NS_Leaf.uasset // 葉っぱVFX本体
│ │
│ ├─Meshes
│ │ MI_Leaf.uasset // 葉っぱメッシュの形状調整用
│ │ M_Leaf.uasset // 葉っぱ用Material。本来はMegascans Textureを貼るだけだった
│ │ SM_LeafDish.uasset // 葉っぱメッシュ。球の底面をぶった切ってUV貼り直しただけ
│ │
│ └─NeighborGridSample // Ghislainさんの講座を写経したNeighborGrid3Dデバッグ用
│ M_Debug_Cell.uasset
│ M_Debug_CellText.uasset
│ NM_RandomParticleColor.uasset
│ NM_UpdateDebugCells.uasset
│
└─Sign // 忍術「左手計絶登圧風」VFX
M_FillRenderTargetExampleAdditive.uasset
NS_Sign.uasset
Niagara Data Channels(以下NDC)で、以下のようにEmitter間で状態遷移の様な事を行っています。
状態ごとにEmitterを分けることで、複雑な挙動を管理しやすくしています。
- 植え付け
- 活性化
- 後始末
Initialize Neighbor Grid- Particle間衝突判定で使用するNeighborGrid3D関連パラメータの生成
- 本来はStackingLeaf Emitter内で定義すればよいが、デバッグ用のNE_DebugGridでも参照したいパラメータなのでSystemで定義している
葉っぱの種
- 活性化範囲に入ったら積み上げ葉っぱに遷移する
- 賑やかしのため、20%の確率で吹き飛び葉っぱも同時に発生させる
Initialize Mesh Reproduction Sprite- Mesh表面の座標と向きを採取
Push to Inner- 表面向きの逆側(体内)に押し込む
Select Color from Alpha Weight- LinearColor配列を入力し、alpha値を抽選の重みとして扱って色を決定する
- 「基本的に葉っぱにするキャラのメインカラーにするが、緑と茶の葉っぱも少し混ぜる」という使い方を想定
Init Orientation- Mesh表面に葉っぱの先端を向ける
RequiredActivateDepth- どれくらい活性化範囲に食い込むと活性化するかの値
- 結局
0.0が一番見栄えが良かったので死にパラメータになっている
活性化範囲に入ったらNDCに位置・向き・色などの情報を書き込んで死ぬ
Check Activation- User Parameter指定の活性化範囲に入ったかどうか判定
- ややこしいが「活性化した」と判定されたら
Datainstance.Aliveがfalseになる(消える)
Write NDC Leaf- NDCに書き込み
- Write To Data Chanenl... で自動生成されたもの
Execute Write引数に!Datainstance.Aliveを入力し、死んだ瞬間だけ書きこみをする
Sprite Renderer- デバッグ的な確認のために残している
積み上げ葉っぱ
- 発生源となるMeshを覆い隠す役割
- 種から発生する
- 地面とParticle間でコリジョン判定
- 地面に接すると固まる(動かなくなる)
- 固まったParticleに接しても固まる
- 連鎖的に固まることで、積み上がる挙動を再現している
- 風(外力)に触れたら吹き飛び葉っぱに遷移する
- NDCで遷移先を発生させてから自分を消す
SetParticleAttributeReader- Simulation Stageで隣接Particleの情報を得るのに使用
Init Data Channel- NDCでParticleを発生させる準備
- Spawn from Data Channel...で自動生成されたもの
Spawn from NDC Leaf- Spawn from Data Channel...で自動生成されたもの
Init Particle from NDC- Spawn from Data Channel...で自動生成されたもの
SetCollisionRadius- Particle間コリジョンの半径。PDB PvPステージで使う
OnGround- 床に接しているかどうか。摩擦と積み上がる挙動のために使う
IsSleep- 停止状態(座標更新せず、コリジョンでも動かない)かどうか。積み上がる挙動のために使う
ToushSleepSec- 床または停止状態のParticleに接している時間。連鎖的に停止状態にするのに使う
ToushSleep- 床または停止状態のParticleに接したかどうか。連鎖的に停止状態にするのに使う
ExternakForce- Verletの方法で座標更新する際に考慮する外力。発生した瞬間に飛び出させる用途で使う
TouchPhysicsFieldFrame- Field Systemで設定された力場に接しているフレーム数。BlowingLeafへの切り替えと削除待機判定で使う
Decide Target Orientation- NDCから渡された「体表に葉っぱ先端を向けた向き」から「葉っぱが寝た時の向き」を決定する
Alive From Seed Only- Seed Emitterから発生したParticleのみを生存させる
- StackingLeaf Emitterも同じNDCに書き込むので、自分で自分を発生させないための処理
Update Orientation to Target- 葉っぱを徐々に寝かせる
Drag on Collision- 床や他Particleに接していた場合の減速処理
Update Verlet- Verletの方法を用いたParticle座標更新
Check Physics Field- Field Systemで設定された力場に接しているかどうか判定
Check Sleep- 一定以下の速度、または停止状態Particleに触れ続けたら停止状態に移行する
Write NDC Leaf- 最初に力場に接した瞬間だけ書き込み
Populate Neibor Grid- NeighborGrid3DへのParticles配分
Custom PBD intra PArticle Collision- エンジン組込の
PBD intra PArticle Collisionを改造 - 停止状態(IsSleep)のものは動かさないように(積み上げ挙動のため)
- 発生直後のものは動かさないように(他Particleに接触して飛び出しが減速するのを回避)
- エンジン組込の
- Iteration回数で積み上がりの挙動が変化するので個別のsimulation Stageにする必要がある
Ground Collision- 床下に埋まったものを押し上げる
- 見た目が埋まるのを回避するためにPBD PvPより後に処理する個別のSimulation Stageを設けている
Mesh Renderer- 部分球Meshに葉っぱMaterialを貼ったものを描画
吹き飛び葉っぱ
- 葉っぱであると動きで追認させる役割
- 空気抵抗モジュールでひらひら舞う
- 地面としかコリジョンしない
Check Blow Up Chance- Seedからの発生した時の確率判定
Aerodynamic Drag- 空気抵抗による速度や回転の計算
Collision- 地面との判定のみ
Align Particles with Collision Plane- 地面に落ちた葉っぱを表または裏向きで停止させる
NM Query Physics Field- Field Systemからの外力や速度を適用
- 出力時は
System Life CycleTrackをMuteしないと正常に動作しない時がある- Muteしなくても動作するときもある。謎
- Movie Render Queueでavi出力
- Ezgifでgif化
- 𝕏のgifサイズ制限が15MBらしいのでそれに収まるようにサイズや最適化強度を調整
心残りを供養いたす。
- StackingからBlowingの遷移に関する問題
- StackingはNDC書込後5frame待機してから消しているが、Blowimg発生までに隙間ができたり逆に重複したりする
- NDC書込と読取の問題なのか、Spawnから描画までの遅延の問題なのか特定しきれていない
- 現在の手法だとBlowingに切り替わるまでのPhysics Fieldの値は無視されてしまう
- つまり、1フレームしか発生しないPhysics Fieldの力が反映されない
- これはNDCパラメータに外力や速度を足せば解決しそう
- StackingはNDC書込後5frame待機してから消しているが、Blowimg発生までに隙間ができたり逆に重複したりする
- 葉っぱの色や抽選率のパレットは人力入力だが、GBufferから情報を拾うModuleで自動生成できそう
- Niagara_Advanced_ParticleのSample GBuffer Attributesサンプルを参考にする
- いつのどの辺を拾うんだという問題を解決できず不採用にした
- 種の植え方が雑
- 指などは貫通してしまう
- 均一に散布したあとDistance Fieldで選別する処理も試したが不採用にした
- 後述のInside Unrealで採用している方法
- 倒れた姿勢をStatic Mesh化して、Distance Fieldを生成するが…
- 結局、指先のような細かい部分にFieldがうまく形成されず、全く種を植えられない結果に
- 単に解像度の問題ではあると思うが、複雑化しそうだったので見送り
- 結局、指先のような細かい部分にFieldがうまく形成されず、全く種を植えられない結果に
- 葉っぱのMesh化
- 今回は小皿MeshをMaskして誤魔化してるのでめっちゃoverdrawしている
- 負荷的にはきっちり葉っぱ形状のジオメトリを作った方が良いはず
- PBDの衝突判定形状の詳細化
- 葉っぱなのに球で判定しているので近くで見るとスカスカになっている
- Oriented Particlesなどを参考に詳細化できるかも
- 葉っぱScaleのRandomize
- 忘れてた。後でやろうと思ってParticleにRadiusを持たせていたのに…
- 葉っぱ生成とSkeletal MeshのMask処理の同期が人力
- MeshもComponent Rendererで出すとかで全部Niagara制御化にすれば同期しやすいかも
- StackingLeadの固定処理関連変数名、SleepじゃなくてFreezeが良かったね
- Sleepだとまた起きそうな感じする
- NS_LeafのSequencer制御が安定しない
- previewできたりできなかったり、PIEで実行できたりできなかったり、MRQで実行できたりできなかったりする
- System Life Cycle Trackの使い方が良くないかもしれない
- previewできたりできなかったり、PIEで実行できたりできなかったり、MRQで実行できたりできなかったりする
- previewやPIEで、pauseからコマ送りするとNDCからParticle Spawnされない
- 機能別サンプルでも同じ動作をするので現状そういう仕様っぽい
- デバッグしづらいので一応レポートは送った
- 機能別サンプルでも同じ動作をするので現状そういう仕様っぽい
- まずデモ部分を見ましょう。それの作り方が解説されています
- UE4時代だが、使っている技術そのものは同じ
- Simulation Stageの性質など、重要な言及が多いのでUE5以降でも見る価値があります
- 公式日本語字幕あり
- 公 式 日 本 語 字 幕 あ り
- 公 式 日 本 語 字 幕 あ り
- 公 式 日 本 語 字 幕 あ り
- 公認インストラクターのReza Sarkamari先生によるNiagaraの落ち葉表現講座
- めちゃ丁寧。写経してればいつの間にかいい感じのが完成する
- 吹き飛ぶ落ち葉の挙動はパラメータ含めほぼこれのまんま
- Spriteに適用するテクスチャの粗さが気になる人は切り抜くべし
- Ghislain Girardot先生によるNeighborGrid3D完全攻略ガイド
- めちゃ丁寧。写経してればいつの間にかいい感じのが完成する
- ついでにPBDの基本も身につく…かも
- Physics Fieldの概要説明
- Advect Grid 2D Collection
- NS_Signでほぼそのまんま使用
- 輝度や移流速度をUser Parameterで制御できるように改造した
- Skeletal Mesh Reproduction
- Mesh表面の座標と法線方向取得に利用
- サンプルだとUV座標を利用してMaterialまで再現しているが、このProjectでは不採用
- Particle側がMeshのMaterial知識を持つ必要があるのを嫌った為
- Position Based Dynamics
- Niagaraで動かすPBDのデモ
PBD Intra Particle Collisionの使い方だけわかればOK
- Stuctural Support
- Emitter別に状態管理するアイデアを拝借
- Write into a NDC from Niagara
- GPU Emitter間で通信するための手法として参考にした
- Event HandlerはCPU Emitterでしか使えず、しかしSimulation StageはGPU Emitterでしか使えないので、NDCによる通信を採用
- わりと体当たりで覚えていくしかなかった所に網羅的な資料が登場
- 知識をアップデートしよう
- 元ネタ
- 倫理観をアップデートしよう
どなたかのお役に立てれば幸いです。
以上









