🎆

シンプルな打ち上げ花火をUnity VFX Graphで作る

に公開

この記事で学べる事

  • パーティクルの寿命をトリガーとしたパーティクルの発生させ方
  • GPUイベントの使い方
  • カスタムアトリビュートの基本的な使い方

【注意点】
この記事単体でも完遂できるように作成していますが、前回の記事である「Minimalから作るUnity VFX Graph 基礎編」を見ていただくとスムーズに進められると思います。
https://zenn.dev/althenasoft/articles/80888ccb77e448

作りたいものを決める

毎回恒例の作りたいものを決めて書き出そうのコーナー?です。
行き当たりばったりで作っていると特定の部分に拘り過ぎて時間を無駄にしたりいらないものを作ってしまったりするので作る前に作るものを明確にしておきましょう。

打ち上げ花火の初めから終わりまでのエフェクトを作る

まずよくある打ち上げ花火のイメージを思い浮かべてみましょう。

  1. 下からひゅ~と火の玉があがってくる
  2. 特定の地点に到達したら球を中心として360に火花が爆散する

大きく分けてこんな感じでしょう。
実は前回やった螺旋よりは結構シンプルな作りになるので先にこっちをやればよかったなって思いましたが、今回は2つのエフェクトを作る必要があるので後回しにしました。

VFXGraphは複数の出力が可能なため1つのファイルで別々のエフェクトを作ることができます。
なので火の玉があがるエフェクトと爆発のエフェクトは別々につくることになるわけです。

まずは前回のおさらいとして下から上に上がる表現をまずは作ってみましょう。
単純に直線運動だと面白くないので、今回は重力を感じる上昇を組み込みます。

Step1 ひとまず愚直に打ち上げてみる

実際の打ち上げ花火に近づけるのは後回しにしてまずは下から上に上昇させてみます。
少しでも実際の花火に近づけるように、重力をきかせて徐々に減速していく上昇を作っていきます。

1-1. 必要なコンテキストを設定

毎回全部説明すると冗長になってしまうのでなるべくシンプルにわかりやすく進めます。
デフォルト設定のままにしてるところは省略しています。

  • Spawn System
    • Single Burst
      • Count: 1
  • Initialize Particles
    • capacity: 1
    • set Velocity
      • x = 0
      • y = 15
      • z = 0
    • set Lifetime
      • 2.3
    • set Size
      • 1
    • set Wave Offset
      • Custom Attributesで「waveOffset」自作
      • 作成するとブロックとしてセッターが使えるようになる
      • ※ 今回これは使用しなかったのであってもなくてもいいです。
  • Update Particles
    • Gravity
      • y: -7
    • integration Update
    • Set Base X
      • Custom Attributesで「baseX」自作
      • 作成するとブロックとしてセッターが使えるようになる
      • ※ 今回これは使用しなかったのであってもなくてもいいです。
    • Set Position
      • 後から設定するため一旦デフォルト値
    • Set Base Y
      • Set Base X同様、CustomAttributeで「baseY」自作作成
      • 後で設定
    • Trigger Event (On Die)
      • パーティクルの寿命が尽きたときに発火するイベント
      • Count: 128
        • 次のパーティクルのSpawn数
        • 爆発部分のパーティクル数となる
  • Output Particle
    • Main Texture
      • お好みで

Spawnは説明するところが無いので割愛します。
Initialize Particleも説明するところはそんなにないですが、SetVelocityのY座標はお好みに合わせて調整してみてください。他の数値もお好みで。

一旦自分の環境での見栄えが良い値にしているだけで特にこだわりはないです。

1-2. Update ParticleのY座標を毎フレーム更新

前項でInitializeでYに対してVelocityを与えています。
つまりYの値に力が加えられ変化します。

そしてUpdate側でY座標を更新します(Set PositionのY)
何を元に更新するのかというと、現在のポジションを取得してY座標だけ取り出し、Update側のSetPositionのYに設定する。

これだけで毎フレーム上昇していく仕組みが作れます。
更にUpdateにGravityを設定しているため重力を考慮した動きになっているわけです。

ここで重力を変更して再生してみると違いがよくわかります。

0だとそのまま画面外に進んでいくのに対して-7だといい感じのところで止まってくれます。
もしそれでも画面外に行っているなら重力の値を変えてみてください。

これでシンプルに重力を考慮した上昇に関しては完了です。

Outputに関しては今はいじりません。
テクスチャは好きに変えてもらって大丈夫です。

Step2. 爆発のエフェクトを作る

Unity6でVFXGraph17.2以上であればおそらくすぐ完成します。
というかサンプルをそのまま使えます。

花火っぽくするには調整が必要ですが、今回はサンプルを流用して楽しましょう。
見た目の細かい設定なんかはまた別の機会にやろうと思います。

+マークを押して新たなエフェクトを作るときに出てくるテンプレートの選択で「Simple Burst」を選択します。

すると先ほどまで作業していた場所にSimpleBurstの一連のコンテキストが生成されます。

このままだと上昇していくエフェクトと同時に発動してしまうので調整が必要になります。

2-1. Trigger EventとGPU Eventをつなぐ

今回やりたいこととしては、1つ目の上昇パーティクルが終了してから爆発のパーティクルを出したいわけです。

そのためにはパーティクルが終了をトリガーとして次のパーティクルがスタートするという仕組みを構築してあげる必要があります。

そこで今回使うのが、上昇エフェクト側に設置したUpdateParticleに設定したブロック「Trigger Event (On Die)」を使用します。

Modeとしては「On Die」としており、パーティクルが死んだ(終了した)ときにイベントが発生するしくみとなります。

画像の「evt」という緑の部分がGPUEventコンテキストにつなぐことにより次のパーティクルのスタートの合図にすることが可能になっています。

次にGPU Event側を作ります。

何もない所でSpaceか右クリを押して「GPU Event」コンテキストを出します。

先ほどの「Trigger Event」のevtから「GPU Event」のEvtに接続するとでイベント発生を受け取ることが可能になります。

テンプレートから作成したSimpleBurstのSpawnコンテキストは不要になるため、削除してください。

Spawnコンテキストの代わりとなるのが、先ほど設定した「Trigger Event」と「GPU Event」になっています。

「Trigger Event」側でCountとして128を設定していたと思います。
あれがSpawnコンテキストのパーティクルを発生させる数として扱います。

次に「GPU Event」のアウトプットに「SpawnEvent」となっていると思いますので、そこからSimpleBurstの頭に接続してあげることでSpawnコンテキストの代わりを設定することができました。

これで上昇エフェクトが終了したらSimpleBurst側のエフェクトがスタートされる仕組みができあがります。

この仕組みはエフェクト作りにおいて結構多用するためしっかりと仕組みを覚えておきましょう。

例えばチャージしてからビームを発射するようなエフェクトを一連で作る場合などにも活用できます。

花火も溜めて(ゲージ上昇みたいなイメージ)から溜めたものを爆発するという流れになっているためこの仕組みは様々なエフェクトの基礎的な部分となります。

2-2. 爆発エフェクトの位置を調整する

おそらく現時点で上昇したパーティクルに対して爆発の発生位置が異なっていることに気付けると思います。

爆発の位置を上昇パーティクルの位置と合わせるにはどうしたらよいでしょうか?

一応ここまでの要素だけで完成させることができるので、考えてチャレンジしてみたい方はこの先を見ずに進めてみてもよいでしょう。

ヒントというかほぼ答えになっちゃいますが「上昇パーティクルの位置を保持しておく」

ことで爆発の位置を同期することができます。

ここから先は答えになります。

InitializeParticleコンテキストの「Set Position Shape Sphere」のトグルとなっている「Arc Sphere」を開いていくとTransformのPositionのY座標を1-1で用意したgetプロパティでもある「baseY」をつないであげることで爆発側の発生の初期位置を変更することができます。

「baseY」はカスタムアトリビュートのため普通のプロパティと違いSetも使用できるので、上昇パーティクル側で位置をSetしておけば爆発側でもその値を持ってくることができるわけです。

欲しい値は上昇パーティクル側の消える直前のY座標となります。

なので本来は最終の値だけを保持すればいいのですが、仕様上Update側にSetのブロックを設置してあげる必要があります。

試しにOutput側に置いてみましたが反映されませんでした。

「Set Base Y」ブロックはカスタムアトリビュート「baseY」を作成したことにより設置できるブロックとなっています。

SetPositionのYに設定したGetPositionノードのYから同じように「Set Base Y」のインプットに接続することで値を毎回保存することができます。

正直なところプログラム視点で考えると消える直前の最終の値だけ保持すればよいのですが、VFXGraphだとそのような形を組む場合GetPositionからSetBaseYまでの間に条件を組んであげる必要があります。

例えばLifeTimeが尽きた場合にのみ値を保存するという仕組みを作れそう(やってないのでわからないですが)ではありますが、無駄にノードが増えてしまうとみためもぐちゃぐちゃになるので今回はシンプルに毎フレームY座標を保存する形にしました。

これで爆発側のY座標の初期値を取得できる状態になったので、先ほどSimpleBurst側のInitializeのSetPositionYに接続したbaseYで初期座標が決定されます。

これで上昇したのちに理想の位置で爆発エフェクトが発生します。

打ち上げ花火の一連の流れはこれにて完了となります。

あとは爆発エフェクトの色を変えたり、実際の打ち上げ花火を見てリアルな感じに重力を調整したり、上昇エフェクトに火の尾ひれを付けて上昇させたりと完成度を高めるフェーズに入ることができます。

最終的な接続図は以下の画像のようになっています。

最後に

元々は蛇行運転(火の尾ひれの部分)しながら上昇してリアルな花火を作る講座にしようと思ったのですが実際に作っていると思ったよりノードが増えてしまって初級講座としてはあまりよろしくない構成になりそうだったため必要最低限まで削ぎ落した結果今回の講座になりました。

パーティクルを発生させてから終了後に新たなパーティクルを発生させるといった基本的なモノを自分で作れるようになれば後は値を調整して理想のエフェクトに近づけていくのがエフェクト作りの楽しみでもあり、エフェクト作りとしてのセンスも磨けるのかなと思っています。

何事も基礎的な部分というのは多少の違いはあれど大体同じになるので、そのあたりは一旦省略して本来やりたいことに時間を置くべきだなと私は思っています。

ここからはエフェクト作りにはあまり関係ない内容となっていますが、生成AI時代の学習についてちょっと思うこともありましたので書き残しておきます。

生成AIを使用して、誰が作ってもそこまで変化がないor人に見せる部分ではないものはAIに任せてしまったほうが効率はかなり良くなります。

実際の見た目に関してはAIに伝えたところである程度理想的な形にもっていけるレベルにはなっていますが、エフェクトというものは結局最終は人間が見るものなので微調整する力は必ず必要となります。

ただ、これも時間の問題なのかなと思っているところもありますが……

Discussion