Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】「deltaTime をキャッシュ」の勘違い【C#】

Unity のパフォーマンス最適化の1つとして目にする「deltaTime をキャッシュする」ですが,過去記事にて誤用していました。

本稿は,その訂正記事といたします。

(Unity 2019.4.17f1)


はじめに

deltaTimeは,変化するフレームレートに対して「一定した時間」を保持するためのプロパティです。

docs.unity3d.com

これが正常に作動しているかどうかを判別するため,今回はStopwatchクラスを使用します。

docs.microsoft.com

フレームレートに影響されないStopwatchの値から,deltaTimeを減算してみましょう。


deltaTimeの毎フレーム取得

using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour
{
    // 処理速度表示UIテキスト
    Text text;
    // ストップウォッチ
    static readonly System.Diagnostics.Stopwatch Stopwatch = new System.Diagnostics.Stopwatch();
    // 合計時間
    float totalTime;

    void Start()
    {
        // UIテキストを代入
        text = GameObject.Find("Text").GetComponent<Text>();

        // 計測開始
        Stopwatch.Start();
    }

    void Update()
    {
        // 合計時間の更新
        totalTime += Time.deltaTime;
        // Stopwatch と Time.deltaTime の差
        text.text = Stopwatch.ElapsedTicks * 0.0000001f - (totalTime + Time.deltaTime) + string.Empty;
    }
}

Stopwatch と deltaTime の差が 1.2 付近で均衡している画像
Stopwatch を増加しながら deltaTime を減算する

StopwatchdeltaTimeの開始時間がずれているため '0' ではなく '1.2' 前後を行き来していますが,増減のバランスは保てているように見えます。


deltaTime の冒頭代入

次に,私が誤解していた「deltaTimeのキャッシュ」を例示します。

using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour
{
    // 処理速度表示UIテキスト
    Text text;
    // ストップウォッチ
    static readonly System.Diagnostics.Stopwatch Stopwatch = new System.Diagnostics.Stopwatch();
    // Time.deltaTime のキャッシュ用
    float deltaTime;
    // 合計時間
    float totalTime;

    void Start()
    {
        // UIテキストを代入
        text = GameObject.Find("Text").GetComponent<Text>();
        // Time.deltaTime をキャッシュ
        deltaTime = Time.deltaTime;

        // 計測開始
        Stopwatch.Start();
    }

    void Update()
    {
        // 合計時間の更新
        totalTime += deltaTime;
        // Stopwatch と Time.deltaTime の誤差
        text.text = Stopwatch.ElapsedTicks * 0.0000001f - (totalTime + deltaTime) + string.Empty;
    }
}

Stopwatch と deltaTime の差が 広がっている画像
キャッシュした deltaTime を減算する

StopwatchdeltaTimeのバランスが壊れ,差が広がっていますね。

考えてみれば当たり前で,deltaTimeが持つ「フレームごとにレートに合わせる」という機能を冒頭代入によって奪っているわけです。


「deltaTime をキャッシュ」の真意とは

それでは「deltaTime をキャッシュ」とは,どういう意味なのか。

推測になりますが,以下のような場合に有効であると考えます。

using UnityEngine;
using UnityEngine.UI;

public class NewBehaviourScript : MonoBehaviour
{
    // 処理速度表示UIテキスト
    Text text;
    // 処理速度表示UIテキスト
    Text text2;
    // ストップウォッチ
    static readonly System.Diagnostics.Stopwatch Stopwatch = new System.Diagnostics.Stopwatch();
    // Time.deltaTime のキャッシュ用
    float deltaTime;
    // 合計時間
    float totalTime;

    void Start()
    {
        // UIテキストを代入
        text = GameObject.Find("Text").GetComponent<Text>();
        // UIテキストを代入
        text2 = GameObject.Find("Text2").GetComponent<Text>();

        // 計測開始
        Stopwatch.Start();
    }

    void Update()
    {
        // Time.deltaTime をキャッシュ
        deltaTime = Time.deltaTime;
        // 合計時間の更新
        totalTime += deltaTime;
        // Stopwatch と Time.deltaTime の誤差を更新
        ChangeText();
        // Stopwatch と Time.deltaTime の誤差を更新
        ChangeText2();
    }

    void ChangeText()
    {
        // Stopwatch と Time.deltaTime の誤差
        text.text = Stopwatch.ElapsedTicks * 0.0000001f - (totalTime + deltaTime) + string.Empty;
    }

    void ChangeText2()
    {
        // Stopwatch と Time.deltaTime の誤差
        text2.text = Stopwatch.ElapsedTicks * 0.0000001f - (totalTime + deltaTime) + string.Empty;
    }
}

ChangeText()ChangeText2()の2か所で,deltaTimeを使用しています。

この両方でTime.deltaTimeを計算するより,Update()関数の冒頭でキャッシュする方が処理速度は上がります。

このように,「1フレーム内でTime.deltaTimeを2回以上利用する場合は,Update()の冒頭でキャッシュする」と考えて良いでしょう。


おわりに

「deltaTime をキャッシュする」というテクニックについて,私なりの見解です。

別解釈や御指摘などありましたら,御連絡いただけると幸いです。

以上,deltaTimeのキャッシュに関する訂正と検証記事でした。