Minimalから作るUnity VFX Graph 基礎編
この記事で学べる事
- Unity VFX Graphのテンプレート「Minimal」からパーティクルを表示させる手順
- 各コンテキストで何をやれば最低限のエフェクトが出せるかの方法
- 円運動の作り方
- らせん状に落下していく仕組みの作り方
- Lerpノードについて
ソフトウェアのバージョン等
- Unity
- v6.2 (6000.2.2f1)
- Visual Effect Graph (VFXGraph)
- v17.2
- OS
- Windows11
【注意点】
入門の入門を見ている前提で進めていきますので、初めてVFX Graphを弄る方は入門の入門記事から見てもらえるとスムーズにこの記事を理解できると思います。
初回チュートリアルなのに結構長くなってしまいましたので、Stepごとに区切ってあります。焦らず着実にStepを踏んで覚えていきましょう。
作りたいものを決める
まずどういうエフェクトにしたいのかを決めておかないと何をすればいいのかもわからなくなってしまいますので、最終的に作りたいエフェクトを決めましょう。
作りたいエフェクト:らせん状に落ちていく星
2次元で見ると円の中心の周りを回転している状態になります。
3次元で見ると、上から下にらせん状に星が回転しながら降りていく状態になります。
最終的には円錐の形に添って上は半径が短く、下に行くほど半径が大きくなる仕組みにしたいと思います。
要素を分解して作っていく
目標に対してどういう順番で作っていくのかを確認します。
- 上から下にパーティクルが落ちる状態を作る
- 円の中心を軸にして回転する
- 上記を組み合わせてらせん状に落ちていく
- 応用として上記は円柱に沿って落ちていくイメージだが、下に行くほど半径を大きくする円錐をイメージとして改良する
Step1. 上から下にパーティクルが落ちる状態を作る
これはとても簡単で極論言ってしまえばVelocityをマイナス1にするだけで達成できます。
後は起点をどこにするかぐらいの問題です。
それではVFX Graphを作成してテンプレートをMinimalを選択して進めていきます。
作成したら何か名前を付けてSceneにドラッグ&ドロップで設置しておく。
ランプのアイコンが出ていたら大丈夫です。
設置しておけば作りながら動作を確認しやすいのでオススメです。
先ほど作成したVFXGraphファイルをダブルクリック等で開くとVFXGprah編集ウィンドウに切り替わります。
1-1. SpawnにSingleBurstブロックを追加
Minimalから始めるとSpawnコンテキストには何も設置されていない状態です。
SpawnSystemの枠内で右クリしてSingleBurstブロックを追加しましょう。
- Single Burst 設定
- Count = 1
- Delay = 0
の状態にしておきます。
それ以外は特に弄る必要は今のところ無しです。(SpawnModeやDelayMode等)
とりあえず再生して1回だけ表示するという形にしたいのでSingleBurstを使用しています。
1-2. InitializeにSet Positionブロックを追加
InitalizeParticleの枠内にある「Press space to add blocks」のところらへん右クリして「Set Position」を設置してください。
※ Positionの左にある矢印をクリックすると展開されxとyとzをそれぞれ個別に変数(プロパティ)を割り当てることができます。
特に設定することはないですが、落ちるのをわかりやすくするためにY座標を「1」にしておくのがオススメですが一旦デフォルトの「0」で進めます。
1-3. InitializeにSet Lifetimeブロックを追加
これが無いとパーティクルの生存時間が無いため表示されません。
※スクショは「1-4」でまとめて記載。
- Lifetime = 5(0以上であればOK)
1-4. InitializeにSet Sizeブロックを追加
サイズを設定していないと小さすぎて見えないので、調整できるように設置します。
- Size = 1
これも0以上であれば何でもいいですが大きすぎると意味わからなくなりますし1にしておいて後で自分が見やすいサイズにでも変更してください。
最終的にInitializeコンテキストはこのようになりました。
スクショには「Set Color and Alpha ブロック」が存在していますが見た目の色を変えているだけなのでお好みで大丈夫です。
1-5. Update ParticleにSet Velocityブロックを追加
これが無いと移動してくれないので必須。
- y = -1
xとzは一旦0でOK。
これで下に落ちる挙動になります。
1-6. Integration Update (Position)ブロックを追加
これは追加するだけでOKです。
やっていることはdeltatimeを掛けてpositonに反映します。
厳密にいうと違うのかもしれませんが、フレームレートが変わってしまうと理想の動きにならないのでdeltatimeをかけることによってフレーム落ちとかをしてもちゃんと移動してくれるようになります。
1回でもUnityでUpdate関数を使ってキャラを移動させたりする人は大体感覚はつかめるのかなと思っていますが、もし何もかも初めての人はとりあえず設定しておけばいいブロックだと思ってください。
なぜ必要なのかは後から知ればOKです。
解説すると長くなりそうなのと脱線してしまう可能性が非常に高いため、気になる方は公式ドキュメントを読んでAIに尋ねてみるといいかもです。
一応公式のドキュメントは以下。
1-7. Output Particleの設定
最終的な表示内容に関してはこのコンテキストが担当しています。
今回はそこまで弄ることが無いので簡単に。
-
Blend Mode = Additive
- これに関しては状況に応じて変更してください
- 今回作っていくものはAddtiveでいきます。
-
Main Texture
- これがパーティクルとして表示される見た目になります。
- 特に指定するものがなければ「Knob」「Defauit Particle」とかにしておくとよいでしょう。
- 無ければ自作するかプロジェクトにあるなにかしらのテクスチャを使用してください。
- もし星のテクスチャを持ってる人はそれでいいかもしれません。
「Step1. 上から下にパーティクルが落ちる状態を作る」としてはここまでになります。
これでパーティクルを動かす基本がなんとなく理解できたと思います。
書籍やYoutubeとかに上がっているチュートリアルで燃え続ける火を作るだったり何かしらのオーラを作るだったりだと思うのですが、なぞるだけだと結局何をどうしたらこうなるんだっけっていう記憶ができないような人も多いと思うので、今回の様に分解して進めていくことで記憶に定着させていくのが個人的は良いのかなと思っています。
今回はわかりやすくSet Velocityを使いましたが、Step2ではSetVelocityを使うとシンプルに動かせなかったのでSetPositionでやっていくのでご了承ください。
Step2. 円の中心を軸にして回転する
Step1で上から下に落ちていく仕組みが出来ました。
これにStep2を続けて足すとらせん状に落ちていく形になります。
毎フレーム計算して位置を移動させる仕組みにしましょう。
Step1ではSetVelocityのYを-1にして下に落としていましたが、回転処理を作る場合Velocityだと私の技量がまだ足りないせいか理想の動きをしてくれなかったのでSetPositionを使用していきます。
まずは毎フレーム値が変わるノードを設置します。
2-1. Get Ageノードを追加して速度を掛ける
- パーティクルが生成されてからの経過時間を取得できるノード
- この値を角度として使用することで、時間経過と共に円運動を実現する
このノードからMultiplyをつないで速度(2.0)を設定する。
速度に関しては一旦リテラルでやっていますが変数にしておくと便利です。
2-2. 三角関数を使って円運動を実現
三角関数を学校で習ったとき、将来絶対こんなもん使わんだろって思ってた時期が私にもありました。
アニメーションを作るときにはよく使うのですが細かい所までは今は覚えなくても大丈夫です。
面倒くさい計算なんかは全部ノード側でやってくれますので、興味のある人はまた勉強してみてください。
- Sineノードのinputに2-1で作ったMultiplyの出力を入れる
- Sineノードの出力からMultiplyを出して2.0(半径)を掛ける
- Cosineノードのinputに2-1で作ったMultiplyの出力を入れる
- Sineノードの出力からMultiplyを出して2.0(半径)を掛ける
2-3. Vector3ノードにそれぞれの値を入れてSetPositionにつなぐ
- Multiply(Sine)の出力をVector3のXに入力
- Multiply(Cosine)の出力をVector3のZに入力
- Vector3からUpdateParticleのSetPositionに入力
これでパーティクルの円運動が出来るようになったと思います。
もしUpdateParticleにSet Velocityが残っていて動かない場合は一旦SetVelocityを消してください。
2-4. 落下を組み合わせて螺旋状に落ちる動きを実現
Step1でやった下に落ちる状態が現在なくなったので加えて回転しながら落ちていく見た目にします。
現在XとZに値を入れたVector3があると思うので、次にYに値を入れる準備をしていきます。
- GetAgeノードからMultiplyを出して0.5(落下スピード)を掛ける
- Negateノードを使って符号を反転させる(これが無いと上昇する)
- Negateノードを使いたくない場合最初から値をマイナスにしててもよい(変数化して自由に)
- Negateノードの出力からVector3のYに入力。
最終的にはこのような接続になっています。
これで回転しながら下に落ちていく動きが完成しました。
インスペクタから見た目を調整するために速度や半径は変数化しておくとよいでしょう。
おまけ. 動きを円柱沿いから円錐沿いに調整する
現在は1本の見えない円柱の周りをぐるぐる回転して落ちていくイメージ化と思います。
作り方のイメージとしては結構簡単で、円錐はてっぺんほど半径が小さいので時間に応じて半径を広めていけばいいでしょう。
3-1. リテラルをプロパティ化しておく
ここまでリテラルでやってきたと思うので、ここで各種値を変数化します。
今回必要になったプロパティは以下
※ 全てfloat型になります。
- RotateSpeed (回転速度で使用
- 値: 5.0
- FallSpeed (落下速度で使用
- 値: 0.5
- StartRadius (開始時半径
- 値: 0.01
- EndRadius (終了時の半径
- 値: 2
- Lifetime (InitializeのLifeTimeに設定する
- 値: 5
値はあとから好きに調整してもらって大丈夫です。
3-2. Get LifeTimeノードでGet Ageの値を割る
- Divideノードを使用して「Age / Lifetime」を構築します。
- Divideノードは除算+正規化の役割をもったノード(らしい)です。
除算は順番が変わると結果が変わるので必ず「Get Age」をAに接続してください。
- この出力をLerpノードを出して入力「S」に接続しておく。
※ Lerpノードについては後述
3-3. Lerpノードへの接続
- StartRadiusをXに接続
- EndRadiusをYに接続
Lerpの出力は動的な半径となります。
3-4. SineとCosineの半径を動的にする
3-3で構築したLerpの出力が動的半径となるので、SineとCosineの半径として使用します。
これでパーティクルの発生から終了までかけて半径が広がっていく仕組みが出来ました。
後は再生してみると円錐螺旋落下が完成します。
構築お疲れ様でした。
Lerpノードについて
- Lerp = Linear Interpolation(線形補間) の略です。
特定の値(例えば時間)を使って2つの値の間を滑らかに移動するといった使い方で用いることが多いです。
今回の円錐にそって半径を大きくしていきたいといった感じに最適な仕組みですね。
VFXGraphというかアニメーションを作る際によく使われる仕組みなので覚えておきましょう。
今回で言うとXが始点、Yが終点、Sが時間になります。
最後に
作りながらこの記事を書いてたので結構時間がかかりました。
この生成AI時代でそりゃ誰もやらないわけだ……w (海外の方はちらほらいますが)
VFXGraphのノード構築も記事構築もAIが全部やってくれたら楽なんですが、VFX Graphに関してはまだMCPもVFXGraphには対応してなさそうですがそれも時間の問題なのかなとは思っています。
現在VFXGraphはいわゆるノード形式のヴィジュアルプログラミングオンリーですが、いずれはHLSLみたいにコードで完結する作り方もできるようになればAIで生成できるんじゃないでしょうか。
なんならいっそのことVFXGraphやめて全部HLSLで書けばいいんじゃないか……?
そんな不安も抱えつつVFXGraphの日本人ユーザーが増えてくれると願いつつ初心者でもわかりやすい記事を書いていこうと思います。
三角関数や外積などの数学チックなことをすることが多いので難しいといえば難しいのですが、計算自体はノード側で勝手にやってくれます。
今の時代であればLLMにお願いして作りたいエフェクトの動きを手順+解説付きで出してくれるので、数学を収めてこなかった人でも気軽にエフェクト作りにチャレンジできるいい時代なのかなとは思っています。
Discussion