Hi,
Our project uses Recast Navmesh actors with bIsWorldPartitioned enabled, set to Dynamic generation. We cannot use invokers to generate the navmesh around players only due to design reasons.
Looking at performance, especially on lower end hardware we noticed that the navmesh was regenerating tiles for various reasons and I’d like to describe what we put in place, if you have general feedback, and possibly see if some of these changes could be brought to the engine to ease our future upgrade process.
The goal we wanted to achieve was to have a base navmesh that is valid and is rebuilt as little as possible at runtime.
When a ANavigationDataChunkActor is streamed in, many navmesh tiles were rebuilt (ARecastNavMesh::OnStreamingNavDataAdded)
Pre-existing elements dirty the navmesh, this is expected since the engine cannot know how pre-existing elements might have changed before streaming in the WP cell. Problem is that for some elements that are non-spatially loaded have huge bounds (i.e. LandscapeHeightfieldCollisionComponent) - these dirty the navmesh with bounds unclamped to the ANavDataChunkActor bounds.
We ended up creating a custom Navmesh actor that inherits from ARecastNavMesh, overriding OnStreamingNavDataAdded to allow filtering out invalidations on specific classes (that by design we know these will never be scaled/moved/.., so we can retain the base navmesh). This was the main thing with WP Recast navmeshes that was “hiding” a lot of other issues that are described after. This required a small tweak to ARecastNavMesh.h (see attachment).
NAVMESH NEEDS TO BE REBUILT always displayed
This caused confusion amongst designers, we fixed it like seen in the attached file. This is not really a fix, what are your recommendations here ?
ISM / HISM do not properly invalidate the navmesh when streamed in
This was reported in these issues, we fixed it like seen in the attached file
[Content removed]
[Content removed]
Some Navlinks are missing from the base navmesh if they are parented to another actor
This was hidden due to constant rebuild of the navmesh, the issue appeared since we have ANavLinkProxy actors parented to other actors in the level. See fix in attached file
Runtime data layers
Overall, it was not clear what is part of the base navmesh when in editor. We added to the custom RecastNavMeshActor a boolean ‘bVisualizeBaseNavmesh’ that simply forbids dirtying the Navmesh when in editor and outside of PIE. It could be useful to have this part of ARecastNavMesh instead.
Custom navmesh build commandlet
The default behavior of the WP navigation build commandlet is to load in all Runtime Data Layers set to initially active, and all editor-only data layers. This caused issues such as some of our Runtime Data Layers were editor-only data layers (i.e. they contain blockout actors), so we ended up with the base navmesh (not always rebuilt at runtime for many reasons anymore) to be built from blockout meshes too.
These editor-only runtime data layers were processed during cook using the WP Cells transformers stack, but the WP Cell transformers stack is not applied when running the WP Navigation build commandlet.
Our solution for this to clarify what the base navmesh is was to create a custom WP Navigation build commandlet that inherits from the default one. This commandlet disables bCanEverAffectNavigation on components / deletes ANavModifierVolume and ANavMeshBoundsVolume part of Runtime Data Layers, unless the RDL is allowed in the world settings
This provided a base navmesh that is predictable and seems always valid, the result of this is greatly reduced number of invalidated tiles when streaming in WP cells at runtime (less main thread stutters).
Thanks in advance for your feedback / thoughts on this topic,
Best,
Hugo
[Attachment Removed]