パフォーマンスの問題に様々な原因があるように、コードの最適化方法も様々です。通常、 CPU の最適化を行うに当たっては、事前にアプリケーションの綿密なプロファイリングを行うことが強く推奨されます。ただし、どんな場合にも適用できる CPU 最適化もいくつかあります。
Unity は、アニメーター、マテリアル、シェーダーのプロパティを内部的に表す際、文字列による名は使用しません。速度を高めるために、全てのプロパティ名はプロパティ ID 内でハッシュ化され、プロパティを示すにはこの ID が使用されます。
したがって、Set や Get メソッドをアニメーター、マテリアル、シェーダーなどに使用する場合は、string 型ではなく int 型のメソッドを使用してください。string 型メソッドは単純に、文字列をハッシュにした ID を int 型メソッドに転送します。
文字列のハッシュから作成されたプロパティ ID は、1回の実行中の間において有効です。この使用方法として最も簡単なのは、静的な読み込み専用の int 変数を各プロパティ名について宣言し、その int 変数を文字列の代わりに使用することです。これは、起動時に、追加の初期化コードなしに自動的に初期化されます。
アニメーターのプロパティ名に適した API は Animator.StringToHash、マテリアルとシェーダーのプロパティ名に適した API は Shader.PropertyToID です。
Unity 5.3 以降は、Physics クエリ API の割り当てなしのバージョンが提供されています。例えば RaycastAll コールは RaycastNonAlloc に置き換え、 SphereCastAll コールは SphereCastNonAlloc に置き換えることができます。 2D アプリケーションの場合は、全ての Physics2D クエリ API の割り当てなしのバージョンもあります。
Mono と IL2CPP ランタイムは、UnityEngine.Object から派生したクラスのインスタンスを特定の方法で処理します。インスタンス上でメソッドを呼び出すと、実際にはエンジンコードを呼び出します。エンジンコードは、スクリプト参照をネイティブ参照に変換するためのルックアップと検証を実行する必要があります。小さいながらも、この型の変数を null と比較するコストは、純粋に C# クラスと比較するよりもはるかに高負荷です。このため、タイトなループやフレームごとに実行されるコードでは、これらの null 比較を避けてください。
タイトなループ内にあるベクターやクォータニオンの計算に関しては、「整数演算のほうが浮動小数点演算よりも速く、浮動小数点演算のほうがベクターやマトリックス演算やクォータニオン計算よりも速い」ということを覚えておきましょう。
このため、可換演算あるいは結合演算の可能な範囲では常に、 個々の計算処理のコストを最小限に抑えるようにしてください。
Vector3 x;
int a, b;
// 非効率的(ベクターの乗算が 2 回発生する)
Vector3 slow = a * x * b;
// 効率的(整数の乗算が 1 回、 ベクターの乗算が 1 回)
Vector3 fast = a * b * x;
HTML の文字列方式 (#RRGGBBAA
) と Unity ネイティブの Color
や Color32
方式との間で色指定の方式の変換を行わなければならないアプリケーションでは、 Unity Community のスクリプトが一般的に使用されています。このスクリプトは速度が遅く、また文字列操作のために相当な量のメモリ割り当てを発生させるものでした。
Unity 5 以降は、この変換を効率的に実行できる ColorUtility API がビルトインで提供されています。可能な限り、こちらの API を使用してください。
基本的には、完成版のコードでは Object.Find
と Object.FindObjectOfType
を一切使用しないことが推奨されます。これらの API を使用すると、 Unity はメモリ内の全てのゲームオブジェクトとコンポーネントの反復処理を行わなければならず、プロジェクトの規模が少し拡大すると効率性が大幅に低下します。
シングルトンオブジェクトのアクセサーの場合はこの限りではありません。グローバル マネージャーオブジェクトは instance プロパティをアクセス可能にすることがよくあり、シングルトンの既存のインスタンスを検知するためにゲッター関数内に FindObjectOfType
コールを持っている場合もよくあります。
class SomeSingleton {
private SomeSingleton _instance;
public SomeSingleton Instance {
get {
if(_instance == null) {
_instance =
FindObjectOfType<SomeSingleton>();
}
if(_instnace == null) {
_instance = CreateSomeSingleton();
}
return _instance;
}
}
}
このパターンは基本的には問題ありませんが、シングルトンのオブジェクトが存在しない場合にアクセサが Scenesで確実に呼び出されるようにするため、入念にコードを調査する必要があります。欠落したシングルトンのインスタンスを getter が自動的に作成しない場合、往々にして、そのシングルトンを探すコードが FindObjectOfType
を繰り返し(1 フレームに複数回の場合も多い)呼び出す結果となり、パフォーマンスに余計な負荷が掛かります。
内部的には、 Unity の Camera.main
プロパティは、 Object.FindObject
の特殊なバリアントである Object.FindObjectWithTag
を呼び出します。このプロパティへのアクセスは Object.FindObjectOfType
への呼び出しよりも効率的という訳ではありません。どうしてもメインカメラがコードでアドレス指定されなければならない場合は、次の二つのうちのどちらかを行うことが強く推奨されます。
Start
または OnEnable
コールバック内で Camera.main
にアクセスし、結果の参照をキャッシュする。
アクティブなカメラを提供するか追加できる Camera Manager
クラスを作成する。
UnityEngine.Debug
ロギング API は非開発版ビルドが基になったものではなく、呼び出されるとログファイルに書き込みを行います。非開発版ビルドにデバッグ情報を意図的に書き込むことはほとんどありませんので、以下のように、開発版限定のロギングコールをカスタムメソッドでラップすることをお勧めします。
public static class Logger {
[Conditional("ENABLE_LOGS")]
public static void Debug(string logMsg) {
UnityEngine.Debug.Log(logMsg);
}
}
これらのメソッドを [Conditional] 属性で decorate することで、 Conditional 属性の使用する define が、コンパイルされたソース内に decorate されたメソッドが含まれるかどうか決定します。
Conditional 属性に渡された define のどれも定義されていない場合は、 decorate されたメソッド に加えて、 その decorate されたメソッドへの全ての呼び出しがコンパイルされます。この効果は、メソッドとメソッドへの全ての呼び出しが #if … #endif
のプリプロセッサ ブロックでラップされた場合と全く同じになります。
Conditional
属性に関する詳細は、 MSDN ウェブサイト msdn.microsoft.com を参照してください。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.