Q. VFX Graphで大きな爆発や雷のエフェクトを作りました。画面中央で再生している間は綺麗に見えますが、カメラを少し左右に振って発生源が画面端に寄ると、まだエフェクトが残っているのに突然すべて消えてしまいます。原因は何ですか?

A. これは、VFXの描画判定を行う「バウンディングボックス(Bounds)」のサイズがパーティクルの広がる範囲に対して小さすぎるために発生する、カメラ視錐台カリングFrustum Culling)のバグです。

不具合の症状と突然消えるカリング現象

UnityのVisual Effect Graph(VFX Graph)で、空間を広く使うダイナミックなエフェクトを作成した際、不自然なバグに直面することがあります。エフェクトの発生源を画面の中央に捉えているときは表示されるのに、カメラの向きを変えて発生源を画面の外に追いやった瞬間、画面内にまだ大量に残って漂っているはずのパーティクルが一瞬にして全て消え去ってしまう現象です。カメラを元に戻すと再び出現します。これは描画負荷を削減するためのUnityのカリング機能が、設定ミスによって発生した状態です。

初心者向けの例え話:劇場の見えない舞台と役者の大ジャンプ

この現象をイメージしやすくするために、エフェクトを「劇場の舞台で演技をする役者たち」、VFXオブジェクトのBoundsを「見えない木の木枠で囲まれた舞台そのもの」に例えてみましょう。

劇場のカメラマン(カメラ視錐台)は、映画を撮影しています。カメラマンは非常に合理的で、「舞台(Boundsの木枠)がカメラの画角の中に少しでも入っているか」だけを毎フレームチェックしています。もし木枠が完全に画角の外側に外れたら、カメラマンは「もう舞台上には誰もいない、撮影をサボって休憩しよう」と判断し、カメラのスイッチを切ってしまいます(これがカリングです)。

問題になるのは、舞台の木枠が「1メートル四方」と狭いにもかかわらず、役者たちが風に乗ったり大ジャンプしたりして、木枠の外側10メートル先まで飛び出して演技をしているケースです。役者がいくら画面内で走り回っていても、カメラマンは「木枠がカメラの画角に入っていない」という理由だけでカメラのスイッチをオフにしてしまいます。その結果、画面内にいる役者たちが一瞬で消えてしまいます。解決策はシンプルです。アクターが走り回るエリア全体を包み込めるように、「見えない舞台(Boundsの木枠)」のサイズを十分に広げてあげることです。

想定される主な原因

エフェクトが突然消去されるバグの主な原因は以下の通りです。

  1. Boundsの初期値がデフォルトのまま極小である: VFX Graphを新規作成した際、バウンディングボックスのサイズは通常「1m × 1m × 1m」のような非常に狭い立方体に設定されています。これを超える範囲にパーティクルを飛散させると、カリングの誤判定が発生します。
  2. 物理パラメータや外部要因による大きな移動: `Gravity`や `Turbulence`、あるいはスクリプトによる速度の加算によって、パーティクルが放出後に想定以上の長距離を移動しているにもかかわらず、Boundsがそれに追従していないためです。
  3. 動的Bounds計算の無効化: GPUパーティクルは超高速で処理するため、毎フレーム現在の一番端にいるパーティクルをCPUで追跡すると多大な負荷がかかります。そのため、VFX Graphではサイズを事前に固定(静的Bounds)するのが基本となっており、手動調整を怠るとこの問題が発生します。

具体的な解決方法と手順

カメラの動きによってエフェクトが消えないようにするための設定手順です。

手順1:バウンディングボックス(Bounds)の視覚化

まずは現状のサイズを確認します。シーンビューの上部ツールバーにある「Visual Effect Helper」メニューからBounds表示を有効化するか、対象のVFXオブジェクトを選択します。シーンビュー上に緑色のワイヤーフレームで立方体(Bounds)が表示されます。パーティクルがこの緑の箱からはみ出して飛んでいることを確認してください。

手順2:VFX GraphでのBoundsサイズ・位置の手動調整

  • VFX Graphエディタを開き、エディタウィンドウの左上にある **`VFX Property Sheet`** を表示します。
  • 設定項目の中にある **`Bounds`** を探します。
  • **`Size`** の値を、エフェクトの最大拡散範囲を完全にカバーできる大きさ(例: `10, 10, 10` など)に変更します。
  • パーティクルが特定の方向へ進む場合は、**`Center`** の値をスライドさせて、緑色の箱の重心をその方向へずらします。

手順3:自動計算機能(Record Bounds)の活用

手動でのサイズ設定が難しい場合は、VFX Graphの機能である **`Record Bounds`** を使用します。ゲームを実行するかエディタで再生した状態でこのボタンを押すと、放出されたパーティクルの移動履歴から最大範囲を自動的に計測し、最適なBoundsのサイズと中心点を自動的に適用してくれます。

エフェクトタイプ別 Bounds 推奨設定表

エフェクトのタイプ 推奨される Bounds サイズ 設定のポイント
足元の土煙や小さな火花 3m × 3m × 3m 程度 ほぼデフォルトに近いサイズでも対応可能。Centerは足元に配置。
大爆発や巨大な魔法陣 15m × 15m × 15m 程度 衝撃波や破片が飛ぶ距離を考慮し、全方位に広く設定する。

以下は、C#スクリプトからVFXのバウンディングボックスの状態を動的に変更・確認するためのデバッグ用コードです。

using UnityEngine;
using UnityEngine.VFX;

[RequireComponent(typeof(VisualEffect))]
public class VFXBoundsOptimizer : MonoBehaviour
{
    private VisualEffect vfx;
    [SerializeField] private Vector3 customSize = new Vector3(20f, 20f, 20f);
    [SerializeField] private Vector3 customCenter = Vector3.zero;

    void Start()
    {
        vfx = GetComponent<VisualEffect>();
        if (vfx != null)
        {
            vfx.localBounds = new Bounds(customCenter, customSize);
        }
    }
}

バウンディングボックスのサイズを適正に調整しておくことは、ゲームのビジュアルを崩さないために必須のタスクです。広げすぎるとカリングの効果が薄れて描画不可が多くなり、狭すぎると表示バグに直結するため、上記の手順とGizmo表示を用いてエフェクトごとにジャストなサイズを見極めましょう。