Unity 3 D性能最適化(二)
6629 ワード
IsAlive
U 3 Dのパーティクルシステムスクリプトインタフェースは多くの人が使ったことがあると信じられています.ParticleSyetemクラスの一連のインタフェースにはboolタイプのパラメータであるwithChildrenがあり、このパラメータによってTransform親子関係ツリーで関連付けられたParticleSystemインスタンスセット全体に同じ判断または操作を直接適用することができます.しかし、便利な機能には、必ず性能の罠がある......
IsAliveというインタフェースを例に(粒子システムがすべての粒子が消滅したかどうかを判断するために使用され、一般的にloop以外の例エミッタで使用される)U 3 Dでこのインタフェースがどのように実現されているかを見てみましょう.
伝達されたwithChildrenパラメータがtrueである場合、関数は、下位gameObjectを含むすべての検出可能なパーティクルシステムコンポーネントを取得するためにGetParticleSystems(this)を呼び出し、その後、これらのパーティクルシステムコンポーネントに対してIsAlive判定を順次呼び出すことを試みる.withChildrenがfalseであれば、自分自身を判断するだけだ.当然、オーバーヘッドの大きさはGetParticleSystemsの実現にかかっています.
U 3 Dは、すべての下位gameObjectインスタンス上のパーティクルシステムコンポーネントを取得するために再帰的な方式を用い、再帰終了後に結果リストに戻る際にリスト要素コピー(List.ToArray())を1回行い、パーティクルシステムコンポーネントを取得する際にtransform 2を用いる.gameObject.GetComponent()は、transform 2ではありません.GetComponent()は、前の記事から実験で確認したように、前の方法の方がオーバーヘッドが大きい.ここを見て、私たちの心の中にはもうスペクトルがあるかもしれません.それは--効率は絶対にどこまでも高くなく、性能に影響を与える場所が多すぎます......やはり小さな実験を設計して、このような状況でどのような方法を使うべきかを見てみましょう.
設計実験——1つの2層構造、1つの親gameObjectは1つのParticleSystemコンポーネントをマウントし、2つのサブgameObjectはそれぞれ1つのPariticleSystemコンポーネントをマウントし、2つの異なる方法でこの組み合わせに対してIsAlive各8を判断する×1024×1024回.
シナリオ1では、親gameObject上のPariticleSystemに対してIsAlive(true)を直接呼び出す.
シナリオ2では、ループ前にGetComponentsInChildrenですべてのPariticleSystemをリストに格納し、ループ中にこのリストを遍歴し、リスト内の各ParticleSystemに対してIsAlive(false)を呼び出す.
実験結果−スキーム1は約3900 ms,スキーム2は約65 msであった.
結果の対比は明らかだ.実際、U 3 Dが提供するこのインタフェースの意味は、そんなに頻繁な呼び出しが必要でない場合、IsAlive(true)を使用してすべてのサブパーティクルシステムを手動で取得する過程を省くことができ、コードを簡潔にすることである.U 3 Dは現在、このインタフェースの実現に考慮に値するところがあるが.ParticleSystemが提供するこのファミリーインタフェース(IsAliveはその1つにすぎないほか、Play、Pause、Stopなどもある)は、使用頻度があまり高くない場合、例えば初期化や破棄の際に使い捨て呼び出しを行うだけであれば、withChildrenパラメータがtrueであっても大したことはなく、多くのコードを少なくすることができ、何をしてもよい.しかし、頻繁に呼び出す必要がある場合、例えばフレームごとにパーティクルシステムの集合に対してIsAliveを判断する場合、怠惰ではなく、書くべきものは書かなければならない.また注意すべき点は、IsAliveというファミリーインタフェースの無参形式は、withChildrenをtrueとデフォルトで使用しているので、間違えないようにしてください.
PSでは、G e t D i r c t P e r icleSystemRecursiveの実装方法に注意すると、ノードにPariticleSystemコンポーネントが必要であることが再帰的な条件であることがわかります.再帰の過程で、あるノードにParticleSystemコンポーネントがないことが発見されると、親子関係ツリーのこの枝が頭打ちになっても、さらに下にはパーティシステムが存在しても無視されます.そのため、もしあなたが直面しているParticleSystemの集合にこのような断層がちょうど存在するならば、それはやはり自分でまめに、自分でGetCoronentsInChildrenを使ってすべての粒子システムのコンポーネントを探したほうがいいです.
U 3 Dのパーティクルシステムスクリプトインタフェースは多くの人が使ったことがあると信じられています.ParticleSyetemクラスの一連のインタフェースにはboolタイプのパラメータであるwithChildrenがあり、このパラメータによってTransform親子関係ツリーで関連付けられたParticleSystemインスタンスセット全体に同じ判断または操作を直接適用することができます.しかし、便利な機能には、必ず性能の罠がある......
IsAliveというインタフェースを例に(粒子システムがすべての粒子が消滅したかどうかを判断するために使用され、一般的にloop以外の例エミッタで使用される)U 3 Dでこのインタフェースがどのように実現されているかを見てみましょう.
public bool IsAlive()
{
bool withChildren = true;
return this.IsAlive(withChildren);
}
public bool IsAlive(bool withChildren)
{
if (withChildren)
{
ParticleSystem[] particleSystems = ParticleSystem.GetParticleSystems(this);
ParticleSystem[] array = particleSystems;
for (int i = 0; i < array.Length; i++)
{
ParticleSystem particleSystem = array[i];
if (particleSystem.Internal_IsAlive())
{
return true;
}
}
return false;
}
return this.Internal_IsAlive();
}
伝達されたwithChildrenパラメータがtrueである場合、関数は、下位gameObjectを含むすべての検出可能なパーティクルシステムコンポーネントを取得するためにGetParticleSystems(this)を呼び出し、その後、これらのパーティクルシステムコンポーネントに対してIsAlive判定を順次呼び出すことを試みる.withChildrenがfalseであれば、自分自身を判断するだけだ.当然、オーバーヘッドの大きさはGetParticleSystemsの実現にかかっています.
internal static ParticleSystem[] GetParticleSystems(ParticleSystem root)
{
if (!root)
{
return null;
}
List<ParticleSystem> list = new List<ParticleSystem>();
list.Add(root);
ParticleSystem.GetDirectParticleSystemChildrenRecursive(root.transform, list);
return list.ToArray();
}
private static void GetDirectParticleSystemChildrenRecursive(Transform transform, List<ParticleSystem> particleSystems)
{
foreach (Transform transform2 in transform)
{
ParticleSystem component = transform2.gameObject.GetComponent<ParticleSystem>();
if (component != null)
{
particleSystems.Add(component);
ParticleSystem.GetDirectParticleSystemChildrenRecursive(transform2, particleSystems);
}
}
}
U 3 Dは、すべての下位gameObjectインスタンス上のパーティクルシステムコンポーネントを取得するために再帰的な方式を用い、再帰終了後に結果リストに戻る際にリスト要素コピー(List.ToArray())を1回行い、パーティクルシステムコンポーネントを取得する際にtransform 2を用いる.gameObject.GetComponent
設計実験——1つの2層構造、1つの親gameObjectは1つのParticleSystemコンポーネントをマウントし、2つのサブgameObjectはそれぞれ1つのPariticleSystemコンポーネントをマウントし、2つの異なる方法でこの組み合わせに対してIsAlive各8を判断する×1024×1024回.
シナリオ1では、親gameObject上のPariticleSystemに対してIsAlive(true)を直接呼び出す.
シナリオ2では、ループ前にGetComponentsInChildrenですべてのPariticleSystemをリストに格納し、ループ中にこのリストを遍歴し、リスト内の各ParticleSystemに対してIsAlive(false)を呼び出す.
実験結果−スキーム1は約3900 ms,スキーム2は約65 msであった.
結果の対比は明らかだ.実際、U 3 Dが提供するこのインタフェースの意味は、そんなに頻繁な呼び出しが必要でない場合、IsAlive(true)を使用してすべてのサブパーティクルシステムを手動で取得する過程を省くことができ、コードを簡潔にすることである.U 3 Dは現在、このインタフェースの実現に考慮に値するところがあるが.ParticleSystemが提供するこのファミリーインタフェース(IsAliveはその1つにすぎないほか、Play、Pause、Stopなどもある)は、使用頻度があまり高くない場合、例えば初期化や破棄の際に使い捨て呼び出しを行うだけであれば、withChildrenパラメータがtrueであっても大したことはなく、多くのコードを少なくすることができ、何をしてもよい.しかし、頻繁に呼び出す必要がある場合、例えばフレームごとにパーティクルシステムの集合に対してIsAliveを判断する場合、怠惰ではなく、書くべきものは書かなければならない.また注意すべき点は、IsAliveというファミリーインタフェースの無参形式は、withChildrenをtrueとデフォルトで使用しているので、間違えないようにしてください.
PSでは、G e t D i r c t P e r icleSystemRecursiveの実装方法に注意すると、ノードにPariticleSystemコンポーネントが必要であることが再帰的な条件であることがわかります.再帰の過程で、あるノードにParticleSystemコンポーネントがないことが発見されると、親子関係ツリーのこの枝が頭打ちになっても、さらに下にはパーティシステムが存在しても無視されます.そのため、もしあなたが直面しているParticleSystemの集合にこのような断層がちょうど存在するならば、それはやはり自分でまめに、自分でGetCoronentsInChildrenを使ってすべての粒子システムのコンポーネントを探したほうがいいです.