Navmesh Does Not Update for Hierarchical Instanced Static Mesh Components

Hello,

We have rock actors with HISM components, which can be loaded and unloaded by World Partition. When we teleport to a certain location, the WP loads that part of the level containing the rocks, but the navmesh is not updated — even though the rocks have proper collision and CanEverAffectNavigation set. With navmesh preview enabled in the editor (while the game is not running), the rocks correctly affect navigation (the problem occurs only during gameplay), so it seems that the issue arises when loading actors with HISM components (during PIE or playing on standalone build).

As far as I’ve investigated, the HISM component tries to update the navmesh before it’s registered in the navigation system:

1) AActor::IncrementalRegisterComponents is called. At this point, the actor is not yet registered with the navigation system (it will be registered in PostRegisterAllComponents).

2) UInstancedStaticMeshComponent::OnRegister is called for each HISM component of the rock actor. From here, UPrimitiveComponent::OnRegister() is also called, which attempts to register the component with the navigation system (FNavigationSystem::OnComponentRegistered(*this)). However, due to the following lines in UNavigationSystemV1::RegisterComponentToNavOctree, the registration is skipped:

if (UE::Navigation::Private::ShouldComponentWaitForActorToRegister(Comp))
{
    return;
}

By default, ShouldComponentWaitForActorToRegister returns true, so the component is not registered at this point.

3) At the end of UInstancedStaticMeshComponent::OnRegister, PartialNavigateUpdateForCurrentInstances() is called. However, since neither the actor nor its components are registered yet, the navmesh ignores their collision.

4) When AActor::IncrementalRegisterComponents finishes, the actor calls PostRegisterAllComponents and finally registers itself and its components to the navigation system. But because HISM components support partial navigation updates, adding them to the navigation system at this stage doesn’t trigger a navmesh update.

So my question is:

Should PartialNavigateUpdateForCurrentInstances() be called later — after the components are registered in the navigation system (which would make this an Unreal Engine issue)? Or could this problem be caused by our HISM setup or configuration?

We have been moving away from HISM to only ISM internally, but HISM should be affecting navmesh. In your project, are you using WP navmesh or a regular navmesh? Is this setup for use with dynamic generation of navmesh at runtime? Is the actor containing the HISM component loading instances that are in a different WP cell? In your project, can you test regeneration by intentionally dirtying the area with the instance(s) to see if the system notices the instance in the octree/repository but failed to dirty/regenerate originally?

-James

So I can repro this in 5.6, but out latest on Main appears to not have the issue. I believe CL 43372254 in UE5 Main addresses this problem with instances invalidating cached bounds. I could cause this problem with both HISM and ISM in 5.6. They should follow the same navigation flow now. The fix is included in 5.7.

Could you try to add that CL to your repo to see if it addresses the problem? If it does not, I will try to find any other applicable CLs that may be needed as well.

-James

Thank you for letting me know. Here is another CL to grab that fixes some issues with partial navigation update and recomputes bounds when adding an individual instance. UE5 Main CL 44593725 which should fix an ensure as well.

-James

Those are the two CLs that have been made for direct navigation support. The other CL I found that may be needed is one for the physics body of instances. It is CL 45013939 in UE5 Main. Speaking with others on the team, we all thought the previous 2 CLs would have been the fixes needed. Other changes for ISM have largely been around HWRT and materials. I know with the new FastGeo plugin, there have been changes made for ISM to support it.

We are using a regular dynamic navmesh (not WP), generated only around nav invokers. The issue also occurs for an actor that has only one HISM component with a single instance. When I manually force a navmesh update, the rock actor will affect the navmesh correctly — so it is registered in the navigation system, but it doesn’t trigger a navmesh update on its own.

So it looks like PartialNavigateUpdateForCurrentInstances() is called too early for ISM (as in the steps I described in my first message).

As a workaround, I modified this line in UInstancedStaticMeshComponent::OnRegister():

if (bNavigationRelevant && SupportsPartialNavigationUpdate())
{
    PartialNavigateUpdateForCurrentInstances(); 
}

to:

if (bNavigationRelevant && SupportsPartialNavigationUpdate())
{
    TWeakObjectPtr<UInstancedStaticMeshComponent> WeakThis(this);
    GetWorld()->GetTimerManager().SetTimerForNextTick([WeakThis]()
    {
        if (WeakThis.IsValid() && WeakThis.Get())
        {
            WeakThis->PartialNavigateUpdateForCurrentInstances();
        }
    });
}

This seems to help, but I’m not sure if this is the correct solution.

Unfortunately, that CL doesn’t help.

With CL43372254 and CL44593725 it still doesn’t work.