WorldPartiton HLODについて、データレイヤーをUnloadにしても即時に非表示とならない

お世話になっております。

<br/>

表題の通りなのですが、DataLayerをUnloadにして一部のHLODを非表示にしたかったのですが、即時に非表示とならない現象が発生しています。DataLayerをUnloadにしてから実際に非表示となるまで5~10秒ほどのラグがあります。

こちら、原因と解決法に心当たりありましたらご教授いただけると助かります。

<br/>

以下は補足情報です。

  • シーケンサーによるムービーシーンで発生する
  • wp.Runtime.HLOD 0 コマンドを実行すると即時非表示となる

<br/>

よろしくお願いいたします。

[Attachment Removed]

DataLayerをLoadedまたはUnloadedにすると、通常レベルストリーミングセルがアンロードされて対応するHLODが表示されるようになると思いますが、

ご質問の内容をそのまま受け取るとHLOD自体をデータレイヤーの操作で​非表示にしているように受け取れます。この認識は正しいですか?

通常の動作の上では ActivatedからLoaded/Unloadedへの移行ではリクエストに応じてRemoveFromWorldが処理されます。

他のストリーミングリクエストの兼ね合いで遅延が発生したり、コンテンツ量に応じて複数フレームに処理が時分割されることがありますが​、

同時に他のストリーミングセルのロード処理やアンロード処理が行われている可能性はありますか?

UnrealInsightsで動作を確認するとデータレイヤーのUnloadedリクエストからRemoveFrom​Worldが処理されるまでの周辺の動作を確認できると思います。​

wp.Runtime.HLOD 0でレスポンスが完全するということから、IsSpatiallyLoadedが有効なHLODLayerを含む1段または複数段のHLODをセットアップしてたりする可能性もありそうです。

状況を再現するためにHLOD周辺のセットアップの情報をご共有いただけますと幸いです。​

[Attachment Removed]

ご確認ありがとうございます。

> HLOD自体をデータレイヤーの操作で非表示にしているように受け取れます

はい、間違いありません。HLODをデータレイヤーで非表示にしようとしています。

> 同時に他のストリーミングセルのロード処理やアンロード処理が行われている可能性はありますか?

可能性はあります

> UnrealInsightsで動作を確認するとデータレイヤーのUnloadedリクエストからRemoveFromWorldが処理されるまでの周辺の動作を確認できると思います。

こちら、試してみます

> wp.Runtime.HLOD 0でレスポンスが完全するということから、IsSpatiallyLoadedが有効なHLODLayerを含む1段または複数段のHLODをセットアップしてたりする可能性もありそうです。

こちら、確認します

[Attachment Removed]

> はい、間違いありません。HLODをデータレイヤーで非表示にしようとしています。

これは単純にデータレイヤーに属しているストリーミングセルとそのHLODActorをまるごとデータレイヤーのON/OFF消しているという意味で良かったでしょうか?

それともストリーミングセルには影響を与えずに、HLODだけに作用するデータレイヤーがありますか?

> > UnrealInsightsで動作を確認するとデータレイヤーのUnloadedリクエストからRemoveFromWorldが処理されるまでの周辺の動作を確認できると思います。

> こちら、試してみます

お待ちしております。

[Attachment Removed]

>これは単純にデータレイヤーに属しているストリーミングセルとそのHLODActorをまるごとデータレイヤーのON/OFF消しているという意味で良かったでしょうか?

>それともストリーミングセルには影響を与えずに、HLODだけに作用するデータレイヤーがありますか?

「ストリーミングセルとそのHLODActorをまるごとデータレイヤーのON/OFF消している」ということになります。

HLODだけに作用するデータレイヤーは作成していません。

UnrealInsightで確認した結果、次のことがわかりました。

  • 「AWorldDataLayers::SetDataLayerRuntimeState(…)」を使用して指定したデータレイヤーをUnloadにしている。このとき大量のRemoveFromWorldが数十フレームに渡って実行されている
  • 表示異常が起こる直前にガベージコレクションが実行されている。ただし、ガベージコレクションが終わった後も表示異常はつづいていた
  • 「`wp.Runtime.SetDataLayerRuntimeState Unload _data_layer_name_`」コマンドを実行すると即非表示となる。このときRemoveFromWorldは実行されていない
    [Attachment Removed]

> 「ストリーミングセルとそのHLODActorをまるごとデータレイヤーのON/OFF消している」ということになります。

承知しました。一般的なデータレイヤーの使用方法だと思われます。

>「AWorldDataLayers::SetDataLayerRuntimeState(…)」を使用して指定したデータレイヤーをUnloadにしている。このとき大量のRemoveFromWorldが数十フレームに渡って実行されている

データレイヤーによって操作されるアクターやコンポーネント数はどの程度でしょうか?

処理量やTickの負荷によっては処理の時分割によって長時間処理が継続している可能性がありそうです

>「`wp.Runtime.SetDataLayerRuntimeState Unload _data_layer_name_`」コマンドを実行すると即非表示となる。このときRemoveFromWorldは実行されていない

wp.Runtime.SetDataLayerRuntimeStateを使った場合でも最終的に AWorldDataLayers::SetDataLayerRuntimeState が呼ばれており、両者はおなじようにRemoveFromWorldが処理されているはずです。それでも差が出ていることからデータレイヤーの再帰的なステート変更が行われているなどでステートを変更したデータレイヤーの数が違う可能性がありそうです。

データレイヤーへの操作によってログが出ていると思いますが出力に差が無いかご確認ください。

> シーケンサーによるムービーシーンで発生する

制御はDataLayerトラックによる制御ですか?それともイベントなどからSetDataLayerRuntimeStateを呼び出していますか?

> 表示異常が起こる直前にガベージコレクションが実行されている。ただし、ガベージコレクションが終わった後も表示異常はつづいていた

ガベージコレクションは毎回起きているわけではないでしょうか?ガベージコレクションを抑制することで改善がみられるかもしれません。

ステート変更でActivated > Unloadに移行しているところを loadedに遷移するようにすることで動作は変わりますか?

[Attachment Removed]

お世話になっております。

>データレイヤーによって操作されるアクターやコンポーネント数はどの程度でしょうか?

445,531 actors(48 selected)

でした。Data Layers Outliner → Select Actors in Data Layer を使って選択されたアクターの数です。

> データレイヤーへの操作によってログが出ていると思いますが出力に差が無いかご確認ください。

こちら確認します

> 制御はDataLayerトラックによる制御ですか?それともイベントなどからSetDataLayerRuntimeStateを呼び出していますか?

SetDataLayerRuntimeStateを呼び出しています。DataLayerトラックは使用していません。

> ステート変更でActivated > Unloadに移行しているところを loadedに遷移するようにすることで動作は変わりますか?

確認します

[Attachment Removed]

ランタイムでは範囲内のセルのみが対象になるので40万全てがロードされていないと思いますがそれでもかなりの数がありそうなので

RemoveFromWorldが数フレームにまたがって処理され遅延が発生することはありえそうです。

即時非表示にしたいのであれば数次第ではまとまった負荷になる可能性はありますが、データレイヤーの操作と同時にアクターを列挙してAActor::ContainsDataLayer( targetdatalayer)で判定し SetHiddenInGame等を呼び出してしまう方が遅延は少なくなると思います。

セルのアンロードに伴うGCが負荷の原因であればUnloadステートへの遷移を避けることでGCを抑制することが出来るはずですが、

もしGCの有無が原因でないのに関わらずコンソールコマンドを利用した時だけRemoveFromWorldが発生せずにデータレイヤーを非表示にできるのであれば、両者にどんな差があるのか調査するためにUnrealInsightsのトレースを頂きたいのですが可能でしょうか?

[Attachment Removed]

>UnrealInsightsのトレースを頂きたいのですが可能でしょうか?

はい、可能です。ただ、公開できない情報になるので、Boxで受け渡しをお願いします。

[Attachment Removed]

>AActor::ContainsDataLayer( targetdatalayer)で判定し SetHiddenInGame等を呼び出してしまう方が遅延は少なくなると思います。

こちら試してみます

[Attachment Removed]

クラウドストレージへのリンクをメールアドレスに送信させていただきました。ご確認ください。

[Attachment Removed]

お世話になっております。

BoxにUnrealInsightの結果をアップロードしました。提出が遅れてしまい、大変申し訳ありません。

[Attachment Removed]

トレースデータのアップロードありがとうございます。動作を確認できました。

1分55秒周辺の DataLayer-DL_****Exist_Fo から2分15秒周辺の DataLayer-DL_****Exist_Spindle のアンロードまで

断続的にRemoveFromWorldが処理されています。そのため2分15秒のリクエストが即座に処理されず反応が遅れています。

コマンドの場合は先行するアンロードリクエストが無いためすぐに処理が終わっています。

(InsightsでUWorld::UpdateLevelStreamingの負荷を確認いただけるとわかりやすいです)

対策として先行するアンロード処理を素早く終わらせることができれば遅延は解消されます。

アンロード順序のコントロールや、ゲームスレッドに余裕があるのでs.LevelStreamingActorsUpdateTimeLimitを一時的に変更したり、

AWorldSettings::bHighPriorityLoadingを有効化してs.PriorityLevelStreamingActorsUpdateExtraTimeを更新処理時間に加算するなどの方法も検討できます。

[Attachment Removed]

ご確認ありがとうございます

> アンロード順序のコントロールや、ゲームスレッドに余裕があるのでs.LevelStreamingActorsUpdateTimeLimitを一時的に変更したり、

AWorldSettings::bHighPriorityLoadingを有効化してs.PriorityLevelStreamingActorsUpdateExtraTimeを更新処理時間に加算するなどの方法も検討できます。

こちら試してみます。

[Attachment Removed]

トラッキングのためにコメントしております。

対策による改善は確認いただけましたでしょうか?

[Attachment Removed]

こちら、何度か試したのですが、問題が解決できていない状態です。

  • s.LevelStreamingActorsUpdateTimeLimitを一時的に変更
  • AWorldSettings::bHighPriorityLoadingを有効化してs.PriorityLevelStreamingActorsUpdateExtraTimeを更新処理時間に加算する

こちらを試しましたが、問題は解決しませんでした。

他、わかったこととしては以下のとおりです

  • シーケンサーの再生速度の制限をなくして40 - 50fps程度まであげればロード遅れは発生しなくなる
    • 現在は UCinematicInstance→PlayWithFrameRate( FFrameRate( 30, 1 ) ) で30FPS制限をつけています。ただし、ゲーム仕様上シネマティックシーンの30FPS制限は必須となっています。
  • wp.RUntime.MaxLoadingStreamingCells の値を上げても効果はなかった
  • 1フレームあたりのRemoveFromWorldの数がだいたい200-210程度で頭打ちとなり、それ以上増えない
    [Attachment Removed]

確認ありがとうございます。時間制限を解除しても遅延が解消されていない旨承知しました。

改めてトレースデータを確認した所、HLODの表示前のウォームアップを待っているセルが沢山処理されていることに気付きました。(UWorldPartitionHLODRuntimeSubsystem::CanMakeInvisibleというマーカーです)

通常5フレームの遅延が設定されていますがそれより長い時間待ち状態に入っているようです。

これが影響を与えているか確認するために以下のどちらかのコンソール変数を操作して挙動が変化するかご確認いただけますでしょうか。

wp.Runtime.HLOD.WarmupEnabled=0 //warmup自体を完全に無効に
wp.Runtime.HLOD.WarmupNumFrames=1 //warmupframeを5から短縮

[Attachment Removed]

情報ありがとうございます。取り急ぎ、下記を試しましたが、結果は変わらずでした。

  1. wp.Runtime.HLOD.WarmupEnabled=0 //warmup自体を完全に無効に
  2. wp.Runtime.HLOD.WarmupNumFrames=1 //warmupframeを5から短縮

UnrealInsightで確認したところ、上記のコマンドを実行したばあいでも「UWorldPartitionHLODRuntimeSubsystem::CanMakeInvisible」の件数は減っていないようでした(だいたい1フレームあたり200~230件程度処理されていました)

Boxに取得したUnrealInsightを追加しました。

お手数をおかけしますが、ご確認をよろしくお願いします。引き続きこちらでも調査を進めていきます。

[Attachment Removed]

お世話になっております。進展がありましたので共有いたします。

「UWorld::RemoveFromWorld(…)」内で定義される「double TimeLimit = FMath::Max<double>(0.0, GLevelStreamingUnregisterComponentsTimeLimit - GRemoveFromWorldUnregisterComponentTimeCumul);」という時間制限に引っかかっていたようでした。「GLevelStreamingUnregisterComponentsTimeLimit 」はコマンド「s.UnregisterComponentsTimeLimit」で更新できるので、こちらをつかってTimeLimitを1000ミリ秒程度にしたところ、ロード遅れはなくなりました。ただし、ロード数が多くなったためヒッチングが発生しています。こちらは「s.UnregisterComponentsTimeLimit」の値を調整してなんとかならないか試してみます。

長期にわたり相談に乗っていただき、ありがとうございました。このスレッドで提起した問題は解決されたと思います。

[Attachment Removed]

解決の目途が見えた旨承知しました。​

LevelStreamingとRemoveFromWorldの遅延が問題だったので、s.LevelStreamingActorsUpdateTimeLimitと一緒に​s.UnregisterComponentsTimeLimitをお伝えするべきでした。お手数をおかけしました。

[Attachment Removed]