Significance Manager

Significance Manager を使用して、プロジェクト固有の方法でパフォーマンスを調整します。

「ゲーム出荷時のパフォーマンス目標に適合させる」ための作業には、通常、シーンの複雑度を下げ、ターゲットの解像度やフレーム レートに合わせるという内容が含まれます。それには、ジオメトリ、アニメーション、およびオーディオに対するレベルオブディテールシステムが一般的に使用されますが、これらの距離ベースの手法、アクタ単位の手法では十分と言えない場合もあります。特に、プレイヤー数が多いマルチプレイヤー ゲームや、AI 制御のキャラクター群がひとつのエリアに集まることがある場合に当てはまります。

Significance Manager は、一元化されたフレームワークで、ここではオブジェクトを相対的に評価および優先順位付けするための、柔軟性のあるプロジェクトに固有なコードの記述をサポートします。この評価を使用すると、パーティクル エミッター などのコンポーネントを遮断したり、複雑な AI コードの頻度を減らして実行したりすることによって、オブジェクトは自身の動作を修正することが可能です。

Significance Manager 自体が実際にパフォーマンスを向上するということではありません。プロジェクト固有のニーズに適合するようにオーバーライドおよびカスタマイズできるシステムを提供するというのがその役目です。

セットアップ

Significance Manager はプラグイン内に存在するため、[編集] > [プラグイン] メニューで有効にし、そのモジュールをプロジェクトの「*.Build.cs」ファイルに追加する必要があります。

SignificancePlugin.png

Significance Manager は [Plugins] メニューの [Programming] セクションにあります。

Significance Manager プラグインを有効にした後に、エンジンの再起動が必要になることがあります。

このプラグインが有効になったら、プロジェクトの「*.Build.cs」ファイルの PublicDependencyModuleNames に「SignficanceManager」を追加します。次の例は「Basic C++」プロジェクト テンプレートの 1 行であり、Significance Manager を使用するように修正されています。

    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "SignificanceManager" });

Significance Manager の基本的な機能

Significance Manager プラグインには 1 つのクラス USignificanceManager が入っていて、このクラスは、管理対象オブジェクトの「重要度」を評価するための拡張可能なフレームワークとして機能します。これらのオブジェクトは、重要度の値に基づいてパフォーマンスへの影響を軽減するカスタムな方法で自身の動作を調整できます。パフォーマンスの向上をもたらす特定の動作は、ゲーム コードでオブジェクト自身によってカスタム定義されます。たとえば、かすかなオーディオ キューやパーティクル エフェクトを再生するアクタは、重要度の値が小さい場合には再生しないようにすることができます。高度な使用事例として、類似したアクタをまとめてグループ化して、アクタ単位のタイプの割り当てを演奏することもできます。これを使用して、プレイヤー制御のポーンが、カメラに近いときは常に高詳細で実行され、複数のプレイヤーがカメラの回りに集まっているときは、高詳細で実行される AI 制御のポーンの数をそれに応じて制限することにより補うようにすることもできます。

RegisterObject / UnregisterObject

オブジェクトを Significance Manager に登録し、ユーザー指定の名前に基づいて他の登録済みオブジェクトとまとめてグループ化できます。登録プロセスでは、オブジェクトの重要度を評価するために使用する関数と、評価の実施後に実行されるオプションの関数をユーザーを指定できます。登録時に、可能であれば Significance Manager の Update 関数の直近の呼び出しで使用された Transform を使用して、オブジェクトの初期重要度が計算されます。そのときに、既知の登録済みオブジェクトのリスト (通常はタイプごとに異なるリストを使用) に基づいた内部データ構造のビルドなどの高レベルの処理を行うこともできます。これは、ゲームでオブジェクトのタイプごとに異なるカテゴリベースの割り当てを実装する場合に役立ちます。

GetSignificance / QuerySignificance

これらの関数は、オブジェクトのキャッシュされている重要度の値をレポートします。指定したオブジェクトが Significance Manager に登録されていない場合、この値はゼロになります。GetSignificance とは異なり、QuerySignificance 関数は、false を返すことによって、そのオブジェクトが登録されていないことを表します。

Update

この関数は、Transform の配列を受け取って、オブジェクトに関連付けられている重要度関数を使用して、各管理対象オブジェクトの各 Transform に基づく重要度を評価します。返された値の最大値 (bSortSignificanceAscendingtrue に設定されている場合は最小値) が最終的な結果になります。この関数はゲームのニーズに適合するように (たとえば、新しい前処理や後処理のステップをシステムに実装することにより) オーバーライドできます。オブジェクトの重要度が評価された後に、重要度後処理関数が呼び出されます (指定されていた場合)。この関数は、オブジェクトの [Post Significance Type (重要度後処理タイプ)] が [Concurrent (並列)] である場合は直ちに呼び出されます。そのタイプが [Sequential (順次)] である場合は、シーケンシャルなポストアップデートを使用して、他のすべての管理対象オブジェクトと一緒に、重要度が高い順序で後処理関数が呼び出されます。Transform が指定されていない場合、重要度の値はゼロになります。

重要度評価関数と重要度評価後処理関数は並列に実行されるため、これらの関数にはスレッドセーフであるという要件が追加されます。重要度評価後処理関数では、順次実行することによってこの要件を回避できます (詳細については、後述の「FPostSignificanceFunction」セクションを参照)。

Update 関数は自動的には実行されません。ほとんどの場合、デベロッパーはこの関数をすべてのフレームで 1 回ずつ呼び出します。この関数を呼び出すのに適切な場所として、次のコード例で示しているように、オーバーライド版の UGameViewportClient であることが考えられます。

    #include "MyGameViewportClient.h"
    #include "SignificanceManager.h"
    #include "Kismet/GameplayStatics.h"
    void UMyGameViewportClient::Tick(float DeltaTime)
    {
        // スーパークラスのティック関数を呼び出します。
        Super::Tick(DeltaTime);
        // 有効な World and Significance Manager インスタンスがあることを確認します。
        if (UWorld* World = GetWorld())
        {
            if (USignificanceManager* SignificanceManager = FSignificanceManagerModule::Get(World))
            {
                // Player 0 のワールド トランスフォームのみを使用し、1 フレームに1に対して 1 回更新する。
                if (APawn *PlayerPawn = UGameplayStatics::GetPlayerPawn(World, 0))
                {
                    // Significance Manager は ArrayView を使用します。トランスフォームを保持するために 1 要素の Array を構築する。
                    TArray<FTransform> TransformArray;
                    TransformArray.Add(PlayerPawn->GetTransform());
                    // ArrayView で渡された1 要素の ArrayでSignificance Manager を更新します。
                    SignificanceManager->Update(TArrayView<FTransform>(TransformArray));
                }
            }
        }
    }

プロジェクト側の機能

Significance Manager では、オブジェクトの重要度を判定するためのフレームワークだけが提供されていて、実際の計算はプロジェクトでの定義に任されています。オブジェクトを Significance Manager に登録する際に、次のタイプに一致する関数も登録します。

  • FSignificanceFunction

  • FPostSignificanceFunction

これらの関数は、Significance Manager のアップデート時にオブジェクトに対して呼び出されます。

FSignificanceFunction

この関数は、Significance Manager を使用するために記述する必要があるプライマリ評価関数です。この関数は 1 つのオブジェクト パラメータと 1 つの Transform を受け取り、オブジェクトの重要度を計算して、その値を float として返します。Significance Manager のアップデート プロセス中に、この関数は渡された各 Transform に対して 1 回呼び出されます。最終的な結果は Significance Manager の Update 関数によって判定され、デフォルトでは最大値が使用されます。登録される各オブジェクトは、登録時に FSignificanceFunction タイプの関数と関連付けられている必要があります。

FPostSignificanceFunction

このタイプの関数はオブジェクト自体、以前の重要度の値、新しい重要度の値 (オブジェクトが未登録である場合以外。未登録の場合この値は 1)、およびオブジェクトが現在未登録であるかかどうかを表す bool と一緒に指定されます。重要度評価関数とは異なり、この関数は値を返しません。この関数は、オブジェクトの重要度の変更や管理対象オブジェクトの全体的な順序での配置の変更をゲームが処理する手段として提供されます。Significance Manager は、オブジェクトがどのように登録されたかに基づいて、次のようにこの関数を呼び出します。

Post Significance Type (重要度後処理タイプ)

動作

なし

関数は null であることを前提としています。重要度評価後処理コールバックはありません。

Concurrent (並列)

関数は null でないことを前提としていて、オブジェクトの重要度が評価された直後に呼び出されます。この方法で呼び出される関数は、並列で実行されるためスレッドセーフである必要があります。

Sequential (順次)

関数は null でないことを前提としていて、[Sequential (順次)] であるすべてのオブジェクトの重要度が評価された後に、それらのオブジェクトと一緒にソート順序で呼び出されます。

この関数ではスレッドセーフの要件は免除されています。

Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
キャンセル