Unity のパフォーマンス最適化の1つとして目にする「deltaTime をキャッシュする」ですが,過去記事にて誤用していました。
本稿は,その訂正記事といたします。
(Unity 2019.4.17f1)
はじめに
deltaTime
は,変化するフレームレートに対して「一定した時間」を保持するためのプロパティです。
これが正常に作動しているかどうかを判別するため,今回はStopwatch
クラスを使用します。
フレームレートに影響されない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
の開始時間がずれているため '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
が持つ「フレームごとにレートに合わせる」という機能を冒頭代入によって奪っているわけです。
「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
のキャッシュに関する訂正と検証記事でした。