第4章 ParticleSystemで長い時間Simulateをすると巨大なスパイクが発生する

加藤 有也KATO YUYA

株式会社Colorful Palette

4.1 はじめに

UnityのParticleSystemにはパーティクルのシミュレーション時間を任意の時間で制御することのできるParticleSystem.Simulateが用意されています。しかし、ParticleSystem.Simulateに大きな秒数を指定するとシミュレーションを開始した際に大きなスパイクが発生してしまうケースがあります。本記事では、その具体的な事例と注意点について紹介します。

4.2 ParticleSystem.Simulateとは?

ParticleSystem.Simulateについての公式ドキュメント*1 ParticleSystem.Simulateを使用すると第1引数で指定した時間までパーティクルの演出をシミュレーションし、指定した時間からパーティクルを再度再生することが可能です。

リスト4.1: 0秒時点から再生し直す

1
ParticleSystem.Simulate(0f, false, true);

リスト4.1のように0秒を指定すると途中まで再生していたパーティクルを最初から再生し直す仕組みを作れます。

リスト4.2: 5秒時点から再生し直す

1
ParticleSystem.Simulate(5f, false, true);

リスト4.2のように5秒を指定すると再生中のパーティクルを5秒時点から再生し直す仕組みを作れます。

4.3 問題がある使用方法

問題のあるパーティクル

図4.1: 問題のあるパーティクル

Unityのデフォルトで作成できるパーティクルに追加でNoiseモジュールをオンにします。他に調整しているパラメータはパーティクルを見やすくするためにEmissionモジュールで一直線になるように発生を調整しています。


リスト4.3: 20秒時点から再生し直す

1
ParticleSystem.Simulate(20f, false, false);

そしてこのようなNoiseモジュールを使用したパーティクルをリスト4.3のように第1引数の秒数指定に大きすぎる秒数を入れてシミュレーションしてしまうと処理中に大きなスパイクが発生します。

リスト4.4: シミュレーションの負荷計測

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void OnClickA()
{
    // 再生中のパーティクルがあれば破棄
    if (_activeParticle != null)
    {
        Destroy(_activeParticle);
        _activeParticle = null;
    }

    // 新規生成して再生
    _activeParticle = Instantiate(particlePrefab, Vector3.zero, Quaternion.identity);
    var ps = _activeParticle.GetComponent<ParticleSystem>();
    if (ps != null)
    {
        ps.Play();
    }
}

void OnClickB()
{
    if (_activeParticle == null) return;

    var ps = _activeParticle.GetComponent<ParticleSystem>();
    if (ps != null)
    {
        Profiler.BeginSample("再シミュレーション");
        // 再シミュレーション
        ps.Simulate(20f, false, false);
        Profiler.EndSample();

        ps.Play();
    }
}

どれほどの負荷がかかるのか、Profilerで確認します。ButtonAで作成したパーティクルを生成、ButtonBでパーティクルをシミュレートするコードです。UnityのProfilerで確認した時にParticleSystem.Simulateに問題があるのか調べやすくするためにProfiler.BeginSample、Profiler.EndSampleで囲い、調査しやすくします。

スパイクが発生している様子

図4.2: スパイクが発生している様子

処理時間

図4.3: 処理時間

このようにParticleSystem.Simulate時、ParticleSystemのNoiseモジュールでNoiseJobが約2000回コールされ、これにより約50msのスパイクが発生しています。このコール数はParticleSystemのMax Particlesを下げることで少しは減らすことが可能です。

4.4 おわりに

ParticleSystem.Simulateを使用して任意の秒数からパーティクルを発生させる仕組みを作る必要がある場合、

  • 長い時間を指定して途中からパーティクルを発生させる場面があるのか?
  • Noiseモジュールを使用しているのか?

を確認し、特にNoiseモジュールを有効にしているパーティクルを使用する場合はParticleSystem.Simulateの利用を控えた方が良いです。