【Unity】WebGLのフレームレート設定の落とし穴と解決方法

【Unity】WebGLのフレームレート設定の落とし穴と解決方法

WebGLでの実行フレームレート設定は、iOS / AndroidやPCと同じ方法だと動きません。
unityroomで公開するときに重要となるので、対応方法と、フレームレート設定コンポーネントを紹介します。

※環境: Unity 2022.3.21f1

WebGLビルドでFPS指定が動かない

WebGLで動かないコード

TargetFPSコンポーネント
貼り付けるとInspactorからFPS指定できるコンポーネント

using UnityEngine;
using UniRx;

public class TargetFPS : MonoBehaviour
{
    public int FrameRate = 60;

    private void Awake()
    {
        // フレームレートを設定する
        Application.targetFrameRate = FrameRate;

        // フレームレートが変更されたら、反映する
        this.ObserveEveryValueChanged(x => x.FrameRate)
            .Subscribe(_ => Application.targetFrameRate = FrameRate);
    }
}
  • iOS / Android / PCなどでは、こちらで問題なく動作
  • WebGLだと効果がなく、60fps指定が無効になってしまう

フレームレート指定が動かない原因

以下の書き込みで、原因と対応についても情報がありました。
targetFrameRate not working in 2021.3.1 LTS WebGL – Unity Engine – Unity Discussions

WebGLで以下のどちらかを満たす場合、強制的にモニターのリフレッシュレートが参照されてしまうようです。

  • QualitySettings.vSyncCount != 0
  • 60 % Application.targetFrameRate == 0

つまり、任意のFPSを指定するには

  • vSyncCountが OFF
  • 60 ÷ targetFrameRate が割り切れない
    • 60fps, 30fps, 15fpsは割り切れるのでNG
    • 59fps, 29fps, 14fpsならOK

WebGL対応フレームレート指定コード

using UnityEngine;
using UniRx;

public class TargetFPS : MonoBehaviour
{
    public int FrameRate = 60;

    private void Awake()
    {
        UpdateFPS();
        this.ObserveEveryValueChanged(x => x.FrameRate)
            .Subscribe(_ => UpdateFPS());
    }

    private void UpdateFPS()
    {
#if UNITY_WEBGL
        // https://discussions.unity.com/t/targetframerate-not-working-in-2021-3-1-lts-webgl/881482
        // WebGLだとvSyncCountを0にし、60fpsではなく59fpsにしないと正常に動作しない
        QualitySettings.vSyncCount = 0;
        int frameRate = FrameRate;
        if (60 % FrameRate == 0)
        {
            --frameRate; // 割り切れる場合は、-1しておく
        }
        Application.targetFrameRate = frameRate;
#else
        Application.targetFrameRate = FrameRate;
#endif
    }
}

これで、どのプラットフォームでもフレームレートを正しく指定できるようになりました。

まとめ

WebGL特有の挙動によってフレームレートが正しく反映できないとわかりました。
エディターでは、フレームレート指定が動いてしまうので普段からFPS表示をしていないと見落としてしまいます。

FPSのお手軽確認

FPS表示を手軽にやりたい人は、FEELCorgi Engine, TopDown Engineに付属するMMFPSCounterをおいておくと簡単です。
MMFPSCounter
画面右端に小さくFPSを表示できます。


Corgi Engine, TopDown Engineには、FEELや関連ツールが含まれていて、お得ですよ。

フレームレート指定コンポーネントTargetFPS.cs

WebGLで出力したいゲームの多くは、カジュアルなゲームなので60fps以上の高フレームレートは不要です。
今回紹介したコンポーネントをシーンに置いておけば、60fpsや30fpsに簡単に設定できて便利です。

例えば起動時のローディングシーンでは30fpsにしておき、ゲームが始まったら60fpsにしたりできます。

また、アプリ実行中もInspectorから動的にFPSを変えられるのでデバッグでも重宝しています。
例えば、フレームレート低下時のバグやプレイ感を確認するのもInspectorから5fpsや10fpsに指定するだけです。

いままで次のようなバグの解決や、修正確認に役立ってきました。

  • 低フレームレートで、移動が遅くなる不具合
  • 同一フレームに複数ボタンを押したときの不具合
  • タブ切り替えボタンを押下後、タブ切り替え中アニメ中に決定ボタンを押したときの不具合

ということで、ゲームでよく使うコンポーネントの改修と紹介の話でした。