NavMeshのRuntimeGenerationの切り替えについて

【開発環境】

  • Windows 11
  • UE 5.5.4-0 カスタムビルド

<br/>

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

NavMeshのRuntimeGenerationについて、いくつか質問をさせてください。

<br/>

【当方の状況】

これまではStaticでの使用を考えており、ProjectSettingsで「Static」に設定していました。

しかし、一部ゲーム仕様で、DynamicModifiersOnly(以下、DMO)で対処したほうが良さそうな要素がでてきたため、できる限り変更や影響範囲を抑えた対応法がとれないかを模索しております。

<br/>

【質問】

  1. NavMeshを使用しているパーシスタントレベルが複数ある場合、それらレベルごとにRuntimeGenerationを別々にすることは可能でしょうか?(あるレベルはStaticだが、別のレベルはDMOにするなど)また、可能な場合、そのやり方は、レベルに置かれたRecastNavMeshの詳細ビュー内の「RuntimeGenerationプロパティ」を変更する、という方法でしょうか?
  2. RuntimeGenerationをプレイ中に切り替えるということは可能でしょうか?例えば、デフォルトはStaticにしておいて、プレイ中に任意のタイミングでDMOに切り替える、というようなことです。
  3. (1.がTrueのとき前提の話しですが、)Agentが複数ある場合、1つのレベル内でAgentごとにRuntimeGenerationを別々にすることは可能でしょうか?例えば、DefaultのAgentはStaticで、別のAgentはDMOにするなどです。

<br/>

たくさん質問してしまい恐縮ですが、ご教示よろしくお願いします。

> 1. NavMeshを使用しているパーシスタントレベルが複数ある場合~

はい。RecastNavMeshのRuntimeGenerationを書き換えることで動作を変更することが出来ます。

> RuntimeGenerationをプレイ中に切り替えるということは可能でしょうか?

RuntimeGenerationモードを切り替えることは想定されておりません。

しかし一時的にUNavigationSystemV1::SetUpdateNavOctreeOnComponentChangeを用いて更新をブロックしたりすることは可能です。

> 3.(1.がTrueのとき前提の話しですが、)Agentが複数ある場合、1つのレベル内でAgentごとにRuntimeGenerationを別々にすることは可能でしょうか?

RecastNavMeshアクターはAgent毎に分離しているのでそれぞれに設定することが可能です。

Suzuki様

ご回答ありがとうございます。

ご回答を踏まえ、追加で質問させてください。

----------------------------------------------

改めて、当方のやりたいことは以下のとおりです。

  1. マップはWorldPartitionを使用。
  2. NavMeshはWorldPartitioned方式ではなく、従来方式を使用。
  3. NavMeshは全面に張られた状態をデフォルトとする。
  4. InitialRuntimeStateがUnloadedであるDataLayerをプレイ時にロードしたときだけ、NavMeshの指定領域をNull(またはObstacle)にしたい。

これを実現するには、

  1. RecastNavMeshのRuntimeGenerationをDMOにする。
  2. DataLayerにNavModifierを置く。
  3. エディタ時に、NevMeshを更新するときは、DataLayerパネルで当該DataLayerをアンロード状態にしておく。これで全面に張られる。
  4. プレイ時に、当該DataLayerをロードする。これでDataLayer内のNavModifierがNavMeshに動的影響を与える。

Q1. 実現方法として、↑の考えは妥当でしょうか?

----------------------------------------------

>一時的にUNavigationSystemV1::SetUpdateNavOctreeOnComponentChangeを用いて更新をブロックしたりすることは可能です。

こちらについて、ミニマルプロジェクトで試してみました。

↑のやりたいことを踏襲して、以下のようにテストしてみました。

  1. InitialRuntimeStateがUnloadedであるDataLayer「DL_Test」を用意。
  2. マップに、NavModifierVolume(前者)と、TriggerBoxにNavModifierComponentをつけたもの(後者)を設置。AreaTypeはどちらも「NavArea_Null」。
  3. エディタ時に「DL_Test」をアンロード状態にして、NavMeshを全面に張っておく。
  4. プレイ時に、まずSetUpdateNavOctreeOnComponentChange(false)にする。続いて、「DL_Test」をロードする。
  5. すると、NavMeshに対し、前者のほうは影響を与え、後者の方は与えなかった

Q2. SetUpdateNavOctreeOnComponentChange(false)でNavMeshへの影響を抑制できるのはNavModifierComponentだけで、NavModifierVolumeのほうはできない、ということでしょうか?

----------------------------------------------

これまで、RuntimeGenerationをStaticで使ってきました。これをDMOにすると、例えNavModifierなどのNavMeshに影響を与えるものが存在しなくても

Q3. 毎フレームの処理負荷は若干増える、という認識で正しいでしょうか?

Q4. 増えるとして、SetUpdateNavOctreeOnComponentChange(false)をしておけば、増加分を少しでも減らすことができますでしょうか?

----------------------------------------------

「RuntimeGenerationモードをプレイ時に切り替えることは想定されていない」とのことですが、

Q5. これはエンジン改造により可能にするには大変な改修を伴う、という理解でよろしいでしょうか?(「関数内の数行をちょっと書き換える」とか、そんなレベルではない、ということでしょうか?)

----------------------------------------------

質問が多く大変恐縮ではございますが、何卒ご回答よろしくお願いします。

----------------------------------------------

最後に、Q2で言及したミニマルプロジェクト(添付ファイル)の説明を以下に記載させていただきます。

TestDynamicNav.uproject:ランチャー版 5.5.4

Content/TestWPMap.umapを開いてください。

[Image Removed]

このWPマップには、InitialRuntimeStateがUnloadedであるDataLayer「DL_Test」があります。

[Image Removed]また、NavModifierVolumeと、TriggerBoxにNavModifierComponentをつけた「TriggerBoxWithNavModifier」が置かれており、どちらも「DL_Test」に属しています。

[Image Removed]

NavMeshは全面に張っています。

また、BP_ControlActorが置かれており、これはプレイ開始10秒後に「DL_Test」をActiveにします。

[Image Removed]を切り替えます。(C++親クラスAControlActorに定義があります。)

[Image Removed]

`void AControlActor::EnableUpdateNavOctreeOnComponentChange()
{
UNavigationSystemV1::SetUpdateNavOctreeOnComponentChange(true);
}

void AControlActor::DisableUpdateNavOctreeOnComponentChange()
{
UNavigationSystemV1::SetUpdateNavOctreeOnComponentChange(false);
}`

プレイ開始して、(「DL_Test」がロードされる前に)「0」キーを押してSetUpdateNavOctreeOnComponentChange(false)をします。

「show Navigation」をしてNavMeshを可視化すると、↓のようにNavModifierVolumeのほうはNavMeshに影響を与えています。

[Image Removed]

再現プロジェクトのご用意ありがとうございます。

SetUpdateNavOctreeOnComponentChangeの動作について混乱を与えてしまった件失礼しました。

SetUpdateNavOctreeOnComponentChangeはNavModifierComponentなどのコンポーネントをブロックしますが、

INavRelevantInterfaceを継承したアクター(ANavModifierVolume,ANavLinkProxy,AWaterBody等)の影響は受け入れます。

動作の詳細はUNavigationSystemV1::UpdateActorAndComponentsInNavOctreeを参照してください。

> Q1. 実現方法として、↑の考えは妥当でしょうか?

はい。問題ないと思います。

> 2. SetUpdateNavOctreeOnComponentChange(false)でNavMeshへの影響を抑制できるのはNavModifierComponentだけで、NavModifierVolumeのほうはできない、ということでしょうか?

はい。冒頭で回答させていただいた通りComponent単位で影響を与えるもののみをブロックできます。

ご自身でUNavigationSystemV1::UpdateActorAndComponentsInNavOctreeに手を入れアクター単位の変更もブロックできるようにすることは大きな変更点にはならないと思います。

> Q3. 毎フレームの処理負荷は若干増える、という認識で正しいでしょうか?

> Q4. 増えるとして、SetUpdateNavOctreeOnComponentChange(false)をしておけば、増加分を少しでも減らすことができますでしょうか?

レベルやアクターに対して操作が行われると、NavigationSystem.cpp内の関数が呼び出されますが、Static設定であればほとんどの関数はアーリーリターンを行い負荷が軽減されます。SetUpdateNavOctreeOnComponentChangeを有効化しておくと、Static以外でもいくつかの関数がアーリーリターンを行うようになり、いくつかの関数呼び出しにおいてStaticと同等の負荷になるはずです。

> Q5. これはエンジン改造により可能にするには大変な改修を伴う、という理解でよろしいでしょうか?

Static<->DMO間の変更であればそこまで大きな変更にはならないと思いますが、思い通りのナビメッシュになるようにタイトル側のコードで切り替え時にナビメッシュに影響を与えるアクターやコンポーネントを正しくシステムに伝える必要があります。

Dynamicモードを含む切り替えは、静的に生成されたナビメッシュをどう扱うのかなど検証や改修を行う必要のある部分はかなり多くなるのではないかと思います。

ご回答ありがとうございます。

教えていただいたことを参考に、DMOへの変更を検討したいと思います。

そのうえでまた色々ご相談させていただくかもしれませんが、このスレッドでは知りたいことは知れたので、クローズでお願いします。