弾が着弾して火花が飛び散るような、複雑な連鎖演出(Sub-emitter)をGPUパーティクルで完璧に動作させる接続フローです。
不具合 of 症状と具体的な現象
Visual Effect Graph(VFX Graph)で、親パーティクルが消滅した瞬間(Dieイベント)に子パーティクルを発生させる「Sub-emitter」を構築した際、以下の問題が頻発します。
- 親は正常に消滅しているが、子パーティクルが1つも生成されない。
- VFX Graph内でエラーは出ておらず接続も正しいように見えるが、実行時に何も描画されない。
- 親の生成数が少ないうちは子が出るが、親が大量になると子が突然出なくなる。
初心者向けの例え話:カプセルトイと極小のトレイ
この現象を理解するために、親パーティクルを「親カプセル」、子パーティクルを「中に入っている大量のミニおもちゃ」に例えてみましょう。
親カプセルが割れた(消滅した)瞬間に、中から大量のミニおもちゃを飛び出させて、床に並べたいと考えています。しかし、ここには2つの重大なルールがあります。
1つ目のルールは、「おもちゃを並べる専用トレイ(子パーティクルのCapacityバッファメモリ)を事前に用意すること」です。もしトレイが極端に小さく、3個しか乗らない場合、カプセルが割れて100個のおもちゃが飛び出そうとしても、トレイに乗り切らない残り97個は置く場所がなくて消滅してしまいます。これが Capacity不足 の状態です。GPUはメモリを事前に固定で確保するため、後からトレイを大きくしてくれません。
2つ目のルールは、「カプセルが割れた!」という手紙(Dieイベント)を伝える経路です。親から手紙を書いて直接おもちゃ(Initialize)に渡そうとしても、間にある受付窓口(Spawnコンテキスト)を通さないと、おもちゃたちはいつ発生すればいいのかわかりません。手紙が窓口で止まっている状態が、Spawnコンテキストの接続ミス です。
想定される主な原因
VFX GraphにおけるSub-emitterがスポーンしない原因は、主に以下の3点です。
- 子システム側のCapacity(容量)が小さい: GPUパーティクルは実行中に動的にメモリを確保できません。最大メモリ(Capacity)を初期化時に固定確保するため、この値がデフォルト(64など)のままだと、親が一度に消滅した瞬間にバッファが枯渇し、スポーン処理がGPUによって無視されます。
- イベント接続のフロー間違い: 親の `Trigger Event On Die` ノードから出力されたイベントを、子システムの `Initialize` に直接接続している場合です。イベントは必ず `Spawn (GPU)` コンテキストを経由して `Initialize` に伝わる必要があります。
- 境界ボックス(Bounds)のカリング: VFX全体の境界判定サイズが不適切な場合、カメラの視界から外れたと判定されて描画がカリングされます。
具体的な解決方法と手順
Sub-emitterを正常に動作させるための設定フローです。
手順1:Capacity の拡張(最重要)
子パーティクル側の Initialize コンテキストを選択し、インスペクターにある **`Capacity`** をデフォルトの低い値から **`2000` 〜 `3000`** 程度に引き上げてください。これは、親が消滅した際に発生する「子パーティクルの最大同時存在数」をカバーするのに十分な大きさである必要があります。
手順2:GPU Spawn コンテキストの経由とノード接続
親の消滅イベントを伝える正しい接続フローを再構築します。
- 親のシステム内に `Trigger Event On Die` ノードを配置します。
- 子システムの開始点として、通常の `Spawn` ではなく **`Spawn (GPU)`** コンテキストを配置します。
- `Trigger Event On Die` の出力(Event)から、`Spawn (GPU)` の `Start` 入力へ接続します。
- `Spawn (GPU)` の出力から、子システムの `Initialize` コンテキストの `Spawn` 入力へ接続します。
手順3:データの継承(Inherit)設定
子システムの内側で `Inherit Source Position` および `Inherit Source Velocity` ノードを配置し、親から引き継いだ座標からパーティクルが放出されるように設定します。これにより、移動中に親が死んだ場合でも、その場から自然に子パーティクルが散らばるようになります。
実務向けチェックリスト&トラブルシューティング
| チェック対象 | 確認項目 | 対策・推奨設定 |
|---|---|---|
| 子システムのCapacity | デフォルト値(64等)のままか? | 同時発生数に応じて2000以上に増やす。 |
| 接続コンテキスト | Spawn (GPU) を経由しているか? | Spawn (GPU) を中間に配置して接続する。 |
| インヘリット設定 | 親の位置を引き継いでいるか? | `Inherit Source Position` を使用する。 |
以下は、C#スクリプトからVFX Graphのカスタムイベントをトリガーし、子エフェクトの動作を確認するためのサンプルコードです。
using UnityEngine;
using UnityEngine.VFX;
[RequireComponent(typeof(VisualEffect))]
public class VFXSubEmitterDebugger : MonoBehaviour
{
private VisualEffect vfxComponent;
[SerializeField] private string customEventName = "OnParentDieTest";
void Start()
{
vfxComponent = GetComponent<VisualEffect>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && vfxComponent != null)
{
VFXEventAttribute eventAttribute = vfxComponent.CreateVFXEventAttribute();
eventAttribute.SetVector3("position", transform.position);
vfxComponent.SendEvent(customEventName, eventAttribute);
Debug.Log($"Sent Event: {customEventName}");
}
}
}
このデバッグスクリプトを使用することで、ゲーム実行中にVFX GraphのSub-emitterが正しくイベントを受け取ってスポーンするかどうかを、親システム全体の動作を待たずに単体でテスト可能です。プロファイラを確認しながらCapacityの閾値を最適化する際にも有効です。