予測カリング
はじめに
予測カリング(Prediction Culling)によって、予測時にシミュレートするエンティティを制限することで、Quantumの予測ロールバックフェーズにおけるCPU負荷を軽減できます。これを有効にすると、ローカルプレイヤーにとって重要かつ視認できるエンティティのみを予測して、視野外のエンティティは確定フレームでのみシミュレートされます。プレイヤーがワールドの一部しか視認できないゲームに最適で、安全かつ簡単に有効にすることができます。
パフォーマンス向上率はゲームによって異なりますが、特に多くのエンティティが存在し、その大部分がローカルプレイヤーの視認範囲外にあるようなゲームでは、大きな効果が期待できます。
Quantum SDKは、エンティティの予測対象エリアを定義する単純な球体によるカリング機能をデフォルトで提供しています。その位置と半径はゲームプレイ中に動的に調整可能で、例えば、ローカルプレイヤーのエンティティの位置に追従させつつ、画面全体をカバーできる十分な半径を設定することができます。
カリングされたエンティティは、確定フレームでのみロジックを実行するため、ローカルプレイヤー視点では顕著に動作が異なります。これは、予測処理がスムーズなゲームプレイと応答性に大きな役割を果しているためです。そのため、プレイヤーが実際にカリングされたエンティティを視認することがないように、適切なカメラ制御と慎重なカリング領域の設定が重要になります。
予測カリングのセットアップ
予測カリングのセットアップには2ステップが必要で、1つはQuantum、もう1つはUnityで行います。
Quantumでの設定
デフォルトでは、予測カリングシステムはAssets/Photon/Quantum/Samples/SampleScenes/ResourcesにあるサンプルのSystemsConfigアセットで既に有効になっています。
Unityでの設定
Unityでは、予測エリアを設定する必要があります。予測エリアは、どのエンティティを予測からカリングするかを決定するために使用されます。
Unityの更新ごとにSetPredictionArea()を呼び出して、予測エリアを更新します。これにはQuantumのGameが必要ですが、アクセスには通常2つの方法(QuantumSceneViewComponent/QuantumEntityViewComponent)が存在します:
C#
using Quantum;
using UnityEngine;
public class PredictionCullingUpdater : QuantumSceneViewComponent
{
public override void OnUpdateView()
{
Game.SetPredictionArea(position, radius);
}
}
または、QuantumRunner経由でGameにアクセスします:
C#
using Quantum;
using UnityEngine;
public class PredictionCullingUpdater : MonoBehaviour
{
private void Update()
{
QuantumRunner.Default.Game.SetPredictionArea(position, radius);
}
}
イテレーター
ゲームコードも予測カリングの恩恵を受けます。Transform2D/Transform3Dを含むフィルターは、位置に基づくカリングの対象になります。
予測フレーム実行中、以下のメソッド呼び出しでは、予測半径内のエンティティのみが返されます。一方で(検証済み入力受信後の)確定フレームでは、すべてのアクティブなインスタンスが返されます。
frame.Filter()frame.Unsafe.FilterStruct()
注意: フィルターとは異なり、コンポーネントイテレーターは予測カリングの影響を受けません。
frame.GetComponentIterator()frame.Unsafe.GetComponentBlockIterator()
手動カリング制御フラグ
フレームAPIから、予測フレームのエンティティをカリングするためのフラグを手動で設定することができます。
| メソッド | 説明 | |
|---|---|---|
| SetCullable(EntityRef entityRef, bool cullable) | エンティティがカリング可能かどうかを設定します。エンティティが存在しない(無効なEntityRefを含む)場合は何も起こりません。 | |
| IsCulled(EntityRef entityRef) | フレームの状態(予測か確定か)に関わらず、現在のエンティティがシミュレーションからカリングされているかどうかを返します。
エンティティがカリングされている場合(例:予測エリア内に存在しない場合)や、存在しない場合はTrueになります。 それ以外の場合(エンティティが存在し、カリングされていない場合)はFalseです。 |
|
| Culled(EntityRef entityRef) | エンティティが予測カリングされているかどうかを返します。
予測フレーム中かつエンティティがカリングされている場合はTrueになります。 それ以外の場合(確定フレーム中であるか、またはエンティティがカリングされていない場合)はFalseです。 |
|
| Cull(EntityRef entityRef) | カリング可能な既存エンティティを、現在のティックでカリングするように手動でマークします。 | エンティティが存在しないか、カリング可能でない場合は何も起こりません。 |
| ClearCulledState() | そのフレームのすべてのエンティティのカリング状態をリセットします。 | 毎シミュレーションフレーム開始時、自動的に呼び出されます。 |
一貫した状態を保って同期ズレを避けるには、フラグを設定したシステムの確定フレームで、カリングされたエンティティのフラグを解除するようにしてください。
RNG問題の回避
予測カリングと合わせてRNGSessionインスタンスを使用することは、完全に安全で、決定論性が保証されます。ただし、複数のエンティティが一つのセッション(QuantumのGlobalデフォルトのRNGSessionなど)を共有している場合、これらを併用することで挙動にチラつきが生じる可能性があります。
予測フレームでシミュレートされるエンティティと、スキップされるエンティティが、同じRNGSessionを使用していると仮定します。予測フレームでは、シミュレートされるエンティティのみで特定の乱数列が生成されます。その後、確定フレームのシミュレーションでは、すべてのエンティティがシミュレートされるため、異なる乱数列が生成されます。予測フレームと確定フレーム間の不一致は、乱数値がシミュレーションでどう使用されるかにもよりますが、ゲームプレイ中に気付かれる可能性があります。
例えば、キャラクター移動をランダムに決定している場合、確定フレームで乱数列が修正された際に、キャラクターの位置が突然変化したことに気付くかもしれません。この種の問題が発生するケースは他にもあり、特に上記のようにRNGSessionを共有している場合には顕著です。
この問題の解決策は、カリング対象の各エンティティ個別にRNGSessionコンポーネントを保持させることです。このように分離することで、ロールバックが実際に必要になる場合を除き、カリングが最終的な乱数列に影響を与えないことが保証されます。
C#
component RandomNumberProvider {
RNGSession RNGSession;
}
セッションの初期化や通常の使用方法については、RNGSessionドキュメントをご覧ください。
カスタム予測ロジック
予測カリングについて、どのエンティティを予測するかしないかを選択するカスタムロジックを定義することができます。
Quantumでは球体エリアの実装が提供されていますが、自由にカスタマイズすることも可能です。例えば、フラスタム予測カリングで説明されているように、カメラの視錐台カリングを使用することもできます。どのようなカリングエリアが最適なのかは、ゲーム次第です。
Back to top