Unityの Visual Effect Graph (以下、VFX Graph) は、GPUを活用して大量のパーティクルを高速に描画できる強力なツールです。VFX Graphでは、動きを制御するためにテクスチャ(ノイズマップ等)をサンプリングすることがよくあります。しかし、「C#スクリプトから動的にテクスチャを渡した途端、パーティクルが画面から消えてしまう」または「ノイズの乗り方が崩れ、意図しない挙動になる」というバグが発生することがあります。

本記事では、このC#からVFX Graphに動的テクスチャを渡す際に発生するサンプリング不良の原因を究明し、安全にパラメータを転送してパーティクル制御を安定させるための解決手順を解説します。

初心者向け:この問題を現実で例えると?

VFX Graphと動的テクスチャの関係を、学校の授業で使う「プロジェクターとスライドフィルム」に例えてみましょう。

VFX Graphは、渡された画像(スライドフィルム)を読み取って、その模様の通りに光の粒子(パーティクル)を投影するプロジェクターです。あらかじめ用意された画像を使う場合は、最初からフィルムが固定されているため、何の問題もなく綺麗な映像が壁に映し出されます。

しかし、授業の途中で先生(C#スクリプト)が手作りの新しいフィルム(動的テクスチャ)を差し込もうとしたとします。この時、もしフィルムの解像度設定がプロジェクターの枠とズレていたり、フィルム自体が特殊なフォーマットで作られていて光を透過しなかったりすると、壁には真っ暗な影しか映らなくなってしまいます。これが「パーティクルが消えてしまう」現象の正体です。さらに、差し込むスロット名(変数名)を書き間違えて別の場所に突っ込んでも機械は読み込めません。正しく動かすには、受け入れスロット(Blackboard)の設定と、手渡すフィルム(C#の割り当て)の規格を一致させる必要があります。

不具合の症状と具体的な現象

このテクスチャ受け渡しバグが発生した際、以下のような症状が見られます。

  • スクリプトからテクスチャを割り当てた瞬間、それまで出ていたパーティクルがすべて非表示(消滅)になる。
  • コンソールにエラーは表示されないが、VFXの境界ボックス(Bounds)だけが描画されたままになる。
  • 渡したテクスチャの明暗が反転して解釈されたり、極端に拡大・縮小されてサンプリングされ、パーティクルが不自然な動きを示す。

想定される原因:なぜ解釈がおかしくなるのか?

VFX Graphへの動的テクスチャバインドが失敗する原因は、主に以下の3点です。

  1. Blackboardの変数型ミスマッチ: VFX Graph側の公開変数の型が、C#側で期待している Texture2D ではなく、互換性のない型になっている。または変数の参照名(Reference Name)と、C#で指定した文字列が完全一致していない。
  2. C#での文字列直接指定によるスペルミス: スクリプト内で vfx.SetTexture("MyNoiseTex", texture) のように、文字列でプロパティを直接指定し続けると、打ち間違いによる紐付け失敗が起きやすくなります。
  3. テクスチャのインスタンス状態: 動的生成した RenderTexture 等が「まだ完全に構築されていない空(Null)の状態」でバインドされてしまい、VFX Graph側でゼロサンプリング(黒扱い)として処理されてしまう。

具体的な解決方法とアプローチ

この問題を確実に防ぎ、動的なテクスチャ転送を成功させるための実装ステップは以下の通りです。

1. VFX Graph側の変数の型と「Reference」名の統一

VFX Graphのエディタを開き、Blackboard パネルで以下の2点を確認します。

  • 変数の型が Texture2D になっていること。
  • Reference フィールドの名前(例:m_NoiseTex)が、C#から呼び出す名前と一致していること。(※表示名ではなく Reference 名がバインドに使われます)。

2. PropertyToID を使用した高速かつ安全なバインド

C#側で毎フレームのように文字列指定でテクスチャをセットすると、タイポによるバグを引き起こすだけでなく、Unity内部での検索負荷が発生します。これを防ぐため、事前に Shader.PropertyToID を使って整数型のIDに変換し、それを介してバインドを行います。

using UnityEngine;
using UnityEngine.VFX;

public class VFXTextureBinder : MonoBehaviour
{
    [SerializeField] private VisualEffect targetVFX;
    [SerializeField] private Texture2D dynamicNoiseTexture;

    // VFX Graphの Blackboard で設定した Reference 名を指定
    private static readonly int NoiseTexPropertyId = Shader.PropertyToID("m_NoiseTex");

    void Start()
    {
        if (targetVFX == null) targetVFX = GetComponent();
        ApplyDynamicTexture();
    }

    public void ApplyDynamicTexture()
    {
        if (targetVFX != null && dynamicNoiseTexture != null)
        {
            // 安全かつ高速な ID 経由でのテクスチャ設定
            targetVFX.SetTexture(NoiseTexPropertyId, dynamicNoiseTexture);
            Debug.Log("Successfully bound dynamic texture to VFX Graph.");
        }
    }
}

実務で役立つ確認チェックリスト

VFX Graphへテクスチャを渡す際に確認すべき実務チェックリストです。

確認項目 対策・確認手順
Reference名の確認 Blackboardの変数の Reference 名が、C#の指定名と完全一致しているか。
Exposed設定 Blackboard上のテクスチャ変数の Exposed チェックボックスがONになっているか。

まとめ

VFX Graphに対するC#からの動的テクスチャバインドは、強力な動的ビジュアルを生み出す基礎技術です。表示が消えたり崩れたりする場合は、変数の Reference 設定の確認、Shader.PropertyToID による確実なバインドパスの構築、およびテクスチャ自体のインスタンス状態を確認することで、バグを未然に排除できます。