Hi there!
I’m currently working on integrating Fog of War data into the navigation system. The goal is to prevent AIs from selecting polygons that pass through unrevealed fog areas. To achieve this, several navigation-related classes have been overridden (see repro steps) so the A* pathfinding algorithm can check the fog state between points `PA` and `PB` during `getVirtualCost`. If the area is hidden by fog, `FLT_MAX` is returned to mark the polygon as invalid.
However, when this code is executed, the agent initially follows the correct A* path, but the **Crowd Manager** takes over and reroutes the agent through the fogged (and supposedly blocked) area. I’ve tried debugging with the Visual Logger, but it doesn’t log anything from the Crowd Manager, and the path itself seems correct.
What I’ve observed is that the Crowd Manager doesn’t appear to use the **NavFilter** class specified by the controller and I haven’t found a way to force it to use the correct one.
The navigation works as intended if the Crowd Manager is disabled, but the goal is to make it work *with* the Crowd Manager using the custom NavFilter to properly avoid fogged areas.
I’m including media from my current project:
- In the first video, you can see the AI going through the FOW when the Crowd Manager is **enabled**.
- In the second video, you’ll see the **expected** behavior when the Crowd Manager is disabled.
The repro project simulates fog using a simple box collider instead of actual FOW.
Any help or insights on getting the Crowd Manager to respect the custom NavFilter would be greatly appreciated!
Thanks for your time ! 
Hello again!
Did I provide the files correctly ? Does anyone have an idea of the origin of the issue ?
Don’t hesitate to ask for new files or if you need more information 
Thanks you have a good day !
Hi Jerome,
My sincerest apologies for the delay on this thread. DetourCrowd should use the virtual filter provided. DetourCrowd/CrowdManager should work with virtual filters. You may also find what is causing the repath by debugging inside of UCrowdFollowingComponent::OnNavNodeChanged as the repath/velocity changes upon reaching the next poly in the path from looking at the videos.
Our setup for creating filters is to have a struct that inherits from FRecastQueryFilter and a class that inherits from UNavigationQueryFilter. Your custom UNavigationQueryFilter then sets its FilterType to your created FRecastQueryFilter inside of InitializeFilter where you can also call methods from your FRecastQueryFilter to initialize or set data to be used. We do wrap some
As an FYI (and I realize your actual filter is likely different than the one attached), you want to ensure that any calculations done in getVirtualCost are as low as possible as the function is run for every poly visited when pathfinding for each agent using the filter. This can add up very quickly to a perf issue. The same precaution applies to all of the virtual filter functions as well.
-James
Hey Jerome,
I have spent some time looking at this. While custom filters have support, the decision to not support virtual filters was very deliberate. It has been done to keep the CrowdManager as performant as possible. Following pointers already adds some overhead, but there are chances for large performance hits due to virtual cost methods which could be run for many agents.
To use the virtual costs, you could either change the Detour code to allow for using pointers to the agent filters. You could alternatively create your own pathfollowing component derived from CrowdFollowingComponent, and override ApplyCrowdAgentVelocity. You can check if there is an obstacle around that truly needs avoided on your path and call the Super implementation to get Detour’s velocity changes, or if there is no obstacle, continue towards the next corner point in the path. You can also use this to have custom ways to deal with an obstacle. For example in FN, we can deal with destructible obstacles or other special cases rather than moving away from the obstacle.
-James
Hi no worries 
Well, everything you’re describing is essentially what I’ve implemented. What really bothers me, though, is how the
`CrowdManager` is structured, it seems to completely break the inheritance model. From what I can tell, this line:
dtQueryFilter m_filters[DT_CROWD_MAX_FILTERS];
essentially fixes the size of the filter objects in memory at compile-time. That means there’s no room for Polymorphism here, copying an instance of a derived class into this array will inevitably slice the object. The actual copy happens inside `updateAgentFilter`, where the code calls:
m_filters[i].copyFrom(filter);
This only copies the base class data, not the virtual table pointer, so any virtual function overrides, like:
passVirtualFilter getVirtualCost
are effectively ignored. The system falls back to the base class implementation, completely bypassing any custom logic in derived filters. I might be wrong, but from what I see, this design makes it impossible to safely extend `dtQueryFilter` through inheritance when using the crowd system.
Have a good day!
Hi James,
Alright, thanks for taking the time to check, I’ll try to spend some time on it to tweak the dtCrowd a bit and see if an eventual outcome is possible. But I might not go further.
Thanks for your time, bye !
Jerome