Niagaraで発生させたStaticMeshからParticleを発生させる

こちらは、Unreal Engine (UE) Advent Calendar 2025 シリーズ3 21日目の記事になります。

はじめに

レベル上に置いてあるものであれば、Static Mesh Locationモジュールを使って、Static MeshからParticleを出すことは、簡単にできます。

ただ、例えばスラッシュやヘリックスなど、Niagara内で制御しているStaticMeshに沿って、火花やParticleを出したい事があると思います。その場合、なんとなくそれっぽい位置に出て見えるように、手動で合わせることもできますが、それだと、スラッシュの向きや大きさを変える度に、また手動での調整が必要になります。
また、ヘリックスなどの複雑なメッシュの場合は、手動で合わせるのは難しいです。

これを、メッシュの位置やサイズが変わったとしても、Particleがメッシュの位置から自動で発生するようにするのが、今回紹介する方法です。

また、上の動画でもそうなっているように、メッシュの向きに沿ってParticleに速度を与える方法と、発生元のUVを使って、スラッシュやヘリックスが出る部分からのみParticleを発生させる方法も、合わせて紹介します。

ちょっと宣伝

解説に入る前に、少し宣伝させてください。

NiagaraとMaterialを高度に使いこなして、様々なエフェクト表現を紹介する講座をColosoから出しています!
ただ作例を作るに留まらず、その背景にある理論や仕組みから解説していて、応用可能な知識として定着させることを目指して、講座の内容を作らせてもらいました。

ご興味ある人は、ぜひ覗いてみてください!
仕組みから学ぶNiagara×Materialの高度VFX表現

環境

UE5.5.4

全体の流れ

  1. Static Mesh Locationで、該当のStaticMeshからParticleが出るようにする
  2. Particle Attribute Readerで、該当のメッシュParticleの位置、大きさ、回転の情報を取得する
  3. 取得した情報を使って、Paritcleの出る位置を調整する
  4. 発生元のメッシュの形状に沿って、Particleを飛ばす
  5. 発生元のメッシュのUV情報を使って、Particleが出る位置をフィルターする

この流れに沿って解説していきたいと思います。こちらを、シンプルな例で作っていきましょう。

実践

0. 下準備

まずは、メッシュを一つ発生させるEmitterを作成しましょう。メッシュは、このスラッシュでよく使うものを使っていきます。

単純に、Mesh Rendererに、このメッシュを設定し、Spawn Burst Instantaneousで1つのParticleを出します。
Emitterの名前は、Meshにしておきます。

次に、メッシュから発生されるParticleのEmitterを作成しましょう。
Add Minimal Emitterで追加し、Spawn Rateを100、Sprite Sizeを3にします。Emitter名は、Particleにしておきます。

これで下準備は完了です!

1. Static Mesh LocationでParticleを発生させる

先ほど作成したParticleのEmitterに、Statci Mesh Locationを追加し、Default Meshに、MeshのEmitterで発生させているスラッシュのメッシュを設定します。

また、今回発生元のメッシュは、Default Meshから変わることはないので、Source Modeを、Default Mesh Onlyにしておきます。Defaultのままにしておくと、このNiagara Systemを何かのStaticMeshにアタッチしてしまうと、発生元のメッシュがその親のメッシュに変わってしまうので、それを防ぐための対応です。

また、わかりやすくするために、Paritcleのマテリアルを、TranslucentのUnlitで、単純にParticleColorを反映するだけにし、色を赤色になるようにしておきます。

これで、このようにスラッシュのメッシュ上の位置からランダムで、Particleが出るようになります。

ただ、MeshのEmitterで、メッシュParticleの大きさや位置、回転を変更してしまうと、Static Mesh Locationで発生位置を制御しているParticleは、デフォルト状態のスラッシュのメッシュから発生させているので、位置がずれてしまいます。

メッシュParticleの回転を変更した例

これを、メッシュParticleの大きさや位置、回転を変更しても、Particleが出る位置が、自動的にそれに合うような処理を入れていきたいと思います。

2. Particle Attribute Readerで該当メッシュの位置、大きさ、回転の情報を取得する

他のEmitterが制御しているParticleの情報を取得するには、Particle Attribute Readerというものを使います。

これについては、以前の投稿で解説しているので、馴染みが無い人は、こちらの解説記事にまず目を通してみてください。

まずは、Particle Attribute ReaderをEmitterのアトリビュートとして、作成します。

それを、Emitter Spawnに入れ、Emitter Bindingに、取得したいParticleを出しているEmitterの名前、今回はMeshを入れて、取得対象を設定します。

次に、Particle Spawnのステージに、Scratch Pad Moduleを作ります。名前は、ApplyMeshTransformとしておきます。このScratch Pad Moduleの中で、該当のメッシュの位置・大きさ・回転の情報を取得し、次で解説するParticleの位置への反映を行っていきます。

Map GetにParticle Attribute Readerを追加して、情報を取得する処理を入れていきます。

今回取得したいのは、位置・大きさ・回転で、それぞれ以下のようなアトリビュート名とデータの型になっているので、

  • 位置:Position(Position)
  • 大きさ:Scale(Vector3)
  • 回転:MeshOrientation(Quaternion)

それぞれのデータの型に合わせた、Get <データ型> by Index というノードを追加し、Attributeに、該当のアトリビュート名を入れていきます。

今回情報を取得する対象のメッシュParticleは、Spawn Burst Instantaneousで1つだけ出しているので、Particle Indexには0を入れれば、そのメッシュParticleを指定したことになります。

このParticle Indexは、Particleの処理順を表すExecution Indexの指定になっていて、Spawn Burst InstantaneousでParticleを出した場合は、発生した順に0から連番が振られます。

今回MeshのEmitterでは、Spawn Burst Instantaneousで1つだけParticleを出しているので、結果的にそのParticleのExecution Indexは0になります。なので、Get <データ型> by Indexのノードでは、Particle Indexを0に指定してあげればよかったという事です。

これで、対象のメッシュの位置・大きさ・回転が取得できたので、これらの値を使って、メッシュ上から発生されるParticleの位置を調整していきましょう。

3. 取得した情報を使って、Paritcleの出る位置を調整する

この位置・大きさ・回転の情報というのは、まとめてTransform情報とよく呼びます。レベル上に置いてあるオブジェクトを選択した時に、Detailsパネルに表示される位置・大きさ・回転の値も、Transformと表示されますね。

今回も、メッシュのTransform情報を扱っているので、それをParticleの位置に反映させることになります。それをするには、Apply Local Transformというノードを使用します。

このノードの、InputVectorに調整前の位置の値を入れ、反映させたい値として、Translateに位置、Scaleに大きさ、Rotateに回転の値をいれます。そうすることで、InputVectorの位置を、該当のメッシュのTransformの値を反映させた位置に動かすことができます。

InputVectorには、元々のParticleの位置を入れればよいので、Map GetにPositionを追加し、それをInputVectorに繋ぎます。自動的にPosition型からVector型に変換するノードが作成されますが、これは大規模マップを想定して、Position型というものが用意されているだけなので、今回はあまり気にしないで問題ないです。

後は、Map SetにもPositionを追加し、Apply Local Transformの出力を繋ぎます。これで、Particleの位置に実際に反映されます。

Apply Mesh Transformの処理は完了です。ただ、Particle Attribute Readerのインプットに、Emitterアトリビュートととして作成したParticle Attribute Readerを設定するのを忘れないようにしてください。

さて、これで上手くいくと思いきや、2つほど注意する点があります。

注意点① Local Spaceにする

今回メッシュの、位置・大きさ・回転の情報をParticleの位置に反映させる処理をしていますが、特に大きさや回転は、ピボット位置が重要になります。

今回の手法を使うにあたって、ピボット位置は、Niagara Systemの位置にする必要があるため、MeshもParticleもローカルスペースにする必要があります。

EmitterのPropertiesのLocal Spaceにチェックを入れて、どちらのEmitterもローカルスペースになるようにしてください。

注意点② Scaleの値をちゃんと設定する

メッシュParticleのMesh Scale Modeが、Unsetになっていても、メッシュParticle自体は、デフォルトの1のサイズで表示されますが、Particle Attribute ReaderでScaleの値を正しく取得することができません。

なので、Scaleの値を設定することを忘れないようにしてください。

ここまで設定できれば、以下のように、メッシュParticleの位置・大きさ・回転を変えても、Particleの発生位置がちゃんとメッシュ上の位置になってくれるようになります。

これで、Niagaraで発生させたStaticMeshからParticleを発生させる、ベースの処理は完了になります。

4. メッシュの形状に沿ってParticleを飛ばす

ここから、より実践的に使える追加のテクニックを紹介していきます。

まずは、メッシュの形状に沿って、Particleを飛ばす方法です。特にスラッシュのようなエフェクトでは、軌跡が流れる逆方向にParticleを飛ばしたり、斬撃が向かう方向に飛ばしたり、といったことをしたいことがあると思います。それをするのに、うってつけの方法になります。

メッシュの形状に沿う方向というのは、UV方向を使うのが良いです。

上記のスラッシュの例でも、Particleを以下の画像の赤方向と青方向に飛ばしていますが、赤は、スラッシュのメッシュのV方向で、青は、U方向になっています。

作成しながら、説明した方がわかりやすいので、実際に処理を入れていきましょう。

わかりやすさのために、まずメッシュにUVチェッカーを表示しておきます。赤の矢印がVの方向で、青の矢印がUの方向になっています。

メッシュのUV方向なんて、どうやって取得するのかと思うかもしれませんが、実は、Static Mesh Locationで、既にその値は取得済みです。

Static Mesh Locationを使うと、自動的にSampledTangentとSampledBitangentというVectorのアトリビュートが作られており、このSampledTangentが該当のメッシュのU方向、SampledBitangentがV方向を示す値になっています。

EmitterがLocal Spaceであれば、これらの値は、ローカル座標系での該当メッシュのUV方向の値になるので、これを使って、Velocityの値を設定すれば、メッシュのUV方向に、Particleを飛ばすことができます。

ただ、忘れてはいけないのが、これもPositionと同じように、メッシュParticleの位置や大きさ、回転を反映させなければならないので、ApplyMeshTransformの中で、同じように処理を加えます。

Map Getに、TangentとBitangentというVectorのインプットを追加し、それを、Positionと全く同じように、Apply Local Transformノードで、発生元のメッシュのTransformを反映させます。

それらの出力を、MeshTangent、MeshBitangentというアトリビュートを作って、それに繋ぎます。

ちなみに、Map SetでParticleのアトリビュートを作るには、まず出力を繋げばLocalと頭に付いたアトリビュートになるので、それを右クリックし、Change NamespaceからParticleを選択することで、Particleのアトリビュートに変換することができます。

そして、TangentとBitangentのインプットに、Static Mesh Locationで取得済みの、SampledTangentとSampledBiTangentを設定します。

これで、元のメッシュTransformを反映させた、メッシュのUV方向が取得できたので、それをVelocityとして使っていきます。

まずは、MeshTangent、つまりU方向にParticleを飛ばしてみましょう。単純に、Add Velocityモジュールを追加し、VelocityにMeshTangentを入れ、Velocity Speed Scaleに任意の値を入れます。

そうすると、このように各Particleが発生した地点のメッシュのU方向にParticleが飛ぶようになります。

VelocityにMeshBitangentを入れれば、このようにメッシュのV方向にParticleを飛ばすことができます。

なので、このようにAdd Velocityを2つ追加し、それぞれMeshTangentとMeshBitangentをVelocityに設定し、Velocity Speed Scaleをそれぞれ調整することで、Meshの形状に沿った方向に、自由にParticleを飛ばすことができます。

これで、メッシュの形状に沿ってParticleを飛ばすことができました。

5. メッシュのUVで、Particleが出る位置をフィルターする

続いて、実践的に使えるもう1つのテクニックとして、メッシュのUVで、発生させるParticleの位置をフィルターする方法を紹介します。

これが、必要な理由は、例えばスラッシュでは、多くの場合Textureを流すなどして、実際にスラッシュの軌跡が見えているのは、メッシュ上の一部分です。それなのに、メッシュ全体からParticleが出ていると、軌跡が見えていない所からもParticleが出ていて不自然に見えます。

それを解消するため、軌跡の見える部分に合わせて、発生させるParitcleの位置も制御できるようにします。

ただ、実際にParitcleが出る位置自体を制御するのはメッシュ自体に仕込みが必要など、大変なので、やり方としては、Particle自体はMesh上の全ての位置から出るが、発生した位置のメッシュのUVが、指定の範囲内でなければ、すぐにKillすることで、メッシュ上の任意の位置のみから出ているように見せる、という方法になります。

これは、ParticleでのDissolveなどでも使う、よくやるやり方になります。

では、実際にどうやるかですが、これもScratch Pad Moduleを追加して、その中で処理していきましょう。名前を、FilterByUVとしておきます。

今回はスラッシュは、メッシュのV方向に流れるようになっているので、Vを使ってフィルターする処理を作っていきます。ただ、Uを使うのも全く同じやり方で出きます。

処理の中身は、これだけで、まずMap Getで、Vector2のMeshUV、floatのV Threshold Min, V Threshold Maxのインプットを追加します。そして、メッシュのUVのVの値が、V Threshold Minより大きく、V Threshold Maxより小さい時のみ、AliveというアトリビュートがTrueになるように処理を組みます。

Aliveというアトリビュートは、Paritcleの生死を管理している値で、これがFalseになると、そのフレームでそのParticleは死ぬことになります。

なので、このような処理を組むことで、メッシュのUVのVの値が、V Threshold MinからV Threshold Maxまでの指定した範囲内にあるPartilceのみ生き残るようになるということです。

あとは、インプットに適切な値を設定していけばOKですが、まず、MeshUVには、Static Mesh Locationで、発生した位置のメッシュのUVも自動的にSampledUVというアトリビュートに格納されているので、その値を入れます。

最後に、V Threshold Min/Maxに、スラッシュの軌跡に合うように適切な値を入れます。今回のスラッシュの軌跡の動きが、Vの1から0方向に動いているので、V Threshold Min/Maxの値も、1から0に遷移するようにします。

Minの値が、先に1から0に減り始め、Maxの値は、少し遅れて減り始めることで、Particleが発生する位置の範囲を生み出します。

また、注意点として、CurveIndexは、スラッシュのNormalizedAgeを入れる必要があります。デフォルトだとParticleのアトリビュートであるNormalizedAgeが入っていますが、これは、メッシュから発生させているParticle自身の寿命に合わせたものなので適切ではないです。

V Threshold Min/Maxの値の遷移は、スラッシュの軌跡の動きの速さに合わせる必要があるので、スラッシュの寿命に合ったNormalizedAgeを入れる必要がありますが、今回は、Systemの寿命とスラッシュの寿命を同じく1秒で合わせてあるので、Systemのアトリビュートである、NormalizedLoopAgeを入れることで、タイミングを合わせています。

スラッシュの寿命とSystemの寿命が合っていない場合などは、V Threshold Min/Maxのカーブのタイミングを調整したり、CurveIndexに入れる値を工夫したりする必要があるので、留意してください。

最後に、Particleの大部分を消すことになるので、全体のParticleの量は増やしておくために、Spawn Rateを200にしておきます。

このような設定をすることで、以下のように、軌跡に合わせてParticleを出すことができるようになります。

これで、実践的に使える手法の紹介ができたかと思います。

おわりに

Niagaraで発生させたStaticMeshからParticleを発生させるというのは、実践的に使うための2つのテクニックも合わせれば、結構色々な所で使える手法かと思います。

少しScratch Pad Moduleなど、普段あまり使わないものを使用することになりますが、実際に手を動かしてやってみると、そこまで難しいことではないと思ってもらえたら嬉しいです。

Scratch Pad Moduleなど、少し高度なNiagaraの使い方を駆使して、面白い表現を紹介しているのが、こちらの講座になるので、ぜひご興味あれば、覗いてみていただければと思います。

仕組みから学ぶNiagara×Materialの高度VFX表現

また、この記事では、あまり仕組み部分まで突っ込んだ説明はしていませんが、この講座の中では、Tangentなど、もっと深堀りした解説をしているので、より深く理屈を理解したい人にも、合った内容になっているかと思います!

結論、このようなことが色々できる、Niagaraってすごいなあ、といういつもの感想を抱いて、メリークリスマスで締めくくりたいと思います。

では、よきCGライフを!