Skip to content

seiko-dev/LeafVFX

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

これは何?

参考資料を元にした、UE5のNiagaraによる落ち葉の発生・積み上げ・吹き飛ばし表現の実装サンプルです。

  • 特徴
    • NeighborGrid3Dによる高速衝突判定を利用したParticleの積み上げ
    • Niagara Data ChannelによるGPU Emitter間の通信を利用したParticleの挙動遷移
    • Field SystemによるParticleの挙動制御

使用例

LS_Leaf_Cinematic

L_Leaf_CinematicsレベルをPlayするとこちらが流れます。

LS_Leaf_Cinematic

LS_Leaf_Flying

Play直後にViewportを左クリックし続けるとこちらが流れます。

LS_Leaf_Flying

動作要件

  • Windows
  • UE5.6.0以降
  • 要Clone(Git LFSを使用しているため、Download Zipでは動作しません)

注意事項

  • チュートリアルではありません
  • 最適な実装ではありません
    • 読みにくい、効率が悪い、負荷が高いやり方をしている箇所がある
  • 環境によっては適切に動作しません
    • 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                           

NS_Leaf解説

Niagara Data Channels(以下NDC)で、以下のようにEmitter間で状態遷移の様な事を行っています。

NDC

状態ごとにEmitterを分けることで、複雑な挙動を管理しやすくしています。

処理の流れ

  1. 植え付け
    • Skeletal Meshの表面から内部に少し潜った所に種Particleを配置する Step1
  2. 活性化
    • Sequencerで種のParticleの「活性化」判定を動かす
    • 活性化した種Particleは消え、同じ場所から葉っぱParticleが出る
    • 「積み上げ葉っぱ」と「吹き飛び葉っぱ」を各Emitterから発生させる(それぞれ後述) Step2
  3. 後始末
    • SequencerでField System制御Actorを動かす
    • Fieldからの外力が加わった「積み上げ葉っぱ」は消え、同じ場所から「吹き飛び葉っぱ」を生成する
    • 「吹き飛び葉っぱ」は外力に従ってひらめきながら飛んでいく Step3

System

System

  • Initialize Neighbor Grid
    • Particle間衝突判定で使用するNeighborGrid3D関連パラメータの生成
    • 本来はStackingLeaf Emitter内で定義すればよいが、デバッグ用のNE_DebugGridでも参照したいパラメータなのでSystemで定義している

Seed Emitter

葉っぱの種

  • 活性化範囲に入ったら積み上げ葉っぱに遷移する
  • 賑やかしのため、20%の確率で吹き飛び葉っぱも同時に発生させる

Seed

Particle Spawn

  • Initialize Mesh Reproduction Sprite
    • Mesh表面の座標と向きを採取
  • Push to Inner
    • 表面向きの逆側(体内)に押し込む
  • Select Color from Alpha Weight
    • LinearColor配列を入力し、alpha値を抽選の重みとして扱って色を決定する
    • 「基本的に葉っぱにするキャラのメインカラーにするが、緑と茶の葉っぱも少し混ぜる」という使い方を想定
  • Init Orientation
    • Mesh表面に葉っぱの先端を向ける
  • RequiredActivateDepth
    • どれくらい活性化範囲に食い込むと活性化するかの値
    • 結局0.0が一番見栄えが良かったので死にパラメータになっている

Particle Update

活性化範囲に入ったらNDCに位置・向き・色などの情報を書き込んで死ぬ

  • Check Activation
    • User Parameter指定の活性化範囲に入ったかどうか判定
    • ややこしいが「活性化した」と判定されたらDatainstance.Alivefalseになる(消える)
  • Write NDC Leaf
    • NDCに書き込み
    • Write To Data Chanenl... で自動生成されたもの
    • Execute Write引数に!Datainstance.Aliveを入力し、死んだ瞬間だけ書きこみをする

Render

  • Sprite Renderer
    • デバッグ的な確認のために残している

StackingLeaf Emitter

積み上げ葉っぱ

  • 発生源となるMeshを覆い隠す役割
  • 種から発生する
  • 地面とParticle間でコリジョン判定
  • 地面に接すると固まる(動かなくなる)
    • 固まったParticleに接しても固まる
    • 連鎖的に固まることで、積み上がる挙動を再現している
  • 風(外力)に触れたら吹き飛び葉っぱに遷移する
    • NDCで遷移先を発生させてから自分を消す

StackingLeaf

Emitter Spawn

  • Set
    • ParticleAttributeReader
      • Simulation Stageで隣接Particleの情報を得るのに使用
  • Init Data Channel
    • NDCでParticleを発生させる準備
    • Spawn from Data Channel...で自動生成されたもの

Emitter Update

  • Spawn from NDC Leaf
    • Spawn from Data Channel...で自動生成されたもの

Particle Spawn

  • Init Particle from NDC
    • Spawn from Data Channel...で自動生成されたもの
  • Set
    • CollisionRadius
      • 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に書き込むので、自分で自分を発生させないための処理

Particle Update

  • Update Orientation to Target
    • 葉っぱを徐々に寝かせる
  • Drag on Collision
    • 床や他Particleに接していた場合の減速処理
  • Update Verlet
    • Verletの方法を用いたParticle座標更新
  • Check Physics Field
    • Field Systemで設定された力場に接しているかどうか判定
  • Check Sleep
    • 一定以下の速度、または停止状態Particleに触れ続けたら停止状態に移行する
  • Write NDC Leaf
    • 最初に力場に接した瞬間だけ書き込み

Populate Grid

  • Populate Neibor Grid
    • NeighborGrid3DへのParticles配分

PBD PvP

  • Custom PBD intra PArticle Collision
    • エンジン組込のPBD intra PArticle Collisionを改造
    • 停止状態(IsSleep)のものは動かさないように(積み上げ挙動のため)
    • 発生直後のものは動かさないように(他Particleに接触して飛び出しが減速するのを回避)
  • Iteration回数で積み上がりの挙動が変化するので個別のsimulation Stageにする必要がある

PBD Costraints

  • Ground Collision
    • 床下に埋まったものを押し上げる
    • 見た目が埋まるのを回避するためにPBD PvPより後に処理する個別のSimulation Stageを設けている

Render

  • Mesh Renderer
    • 部分球Meshに葉っぱMaterialを貼ったものを描画

BlowingLeaf Emitter

吹き飛び葉っぱ

  • 葉っぱであると動きで追認させる役割
  • 空気抵抗モジュールでひらひら舞う
  • 地面としかコリジョンしない

BlowingLeaf

Particle Spawn

  • Check Blow Up Chance
    • Seedからの発生した時の確率判定

Particle Update

  • 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パラメータに外力や速度を足せば解決しそう
  • 葉っぱの色や抽選率のパレットは人力入力だが、GBufferから情報を拾うModuleで自動生成できそう
    • Niagara_Advanced_ParticleのSample GBuffer Attributesサンプルを参考にする
    • いつのどの辺を拾うんだという問題を解決できず不採用にした
  • 種の植え方が雑
    • 指などは貫通してしまう
    • 均一に散布したあとDistance Fieldで選別する処理も試したが不採用にした
      • 後述のInside Unrealで採用している方法
      • 倒れた姿勢をStatic Mesh化して、Distance 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で、pauseからコマ送りするとNDCからParticle Spawnされない
    • 機能別サンプルでも同じ動作をするので現状そういう仕様っぽい
      • デバッグしづらいので一応レポートは送った

参考資料

  • まずデモ部分を見ましょう。それの作り方が解説されています
  • UE4時代だが、使っている技術そのものは同じ
    • Simulation Stageの性質など、重要な言及が多いのでUE5以降でも見る価値があります
  • 公式日本語字幕あり
    • 公 式 日 本 語 字 幕 あ り
      • 公 式 日 本 語 字 幕 あ り
  • 公認インストラクターのReza Sarkamari先生によるNiagaraの落ち葉表現講座
    • めちゃ丁寧。写経してればいつの間にかいい感じのが完成する
  • 吹き飛ぶ落ち葉の挙動はパラメータ含めほぼこれのまんま
  • Spriteに適用するテクスチャの粗さが気になる人は切り抜くべし
  • Ghislain Girardot先生によるNeighborGrid3D完全攻略ガイド
    • めちゃ丁寧。写経してればいつの間にかいい感じのが完成する
    • ついでにPBDの基本も身につく…かも
  • Physics Fieldの概要説明

Niagara_Advanced_Particle レベル

  • 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別に状態管理するアイデアを拝借

Niagara_Data_Channels レベル

  • Write into a NDC from Niagara
    • GPU Emitter間で通信するための手法として参考にした
    • Event HandlerはCPU Emitterでしか使えず、しかしSimulation StageはGPU Emitterでしか使えないので、NDCによる通信を採用
  • わりと体当たりで覚えていくしかなかった所に網羅的な資料が登場
  • 知識をアップデートしよう
  • 元ネタ
  • 倫理観をアップデートしよう

どなたかのお役に立てれば幸いです。

以上

About

Leaf VFX Sample for UE5 Niagara system

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors