Using tags on a Recast Graph in a large open world

Hello! I am currently using version 4.3.46 with a single Recast graph spanning over a large open world. I am trying to figure out the best way to partition different parts of the navmesh baked from terrain tiles. For example, there are large bodies of water that only aquatic npc agents should be able to go in/out of, while terrestrial agents should stick to the basic ground. These bodies of water are essentially just large hollowed out sections of the terrain tile that are filled with a flat plane that uses a stylized water shader.

I had originally thought to use tags with the GraphUpdateScene compenent for this purpose of marking general areas in the world in which only particular agents can traverse. However, I also happen to use navmesh cuts for a few abilities such as a “rock wall” where the player draws a path that spawns a temporary wall of rocks. These rocks cut a hole in the navmesh so that agents have to path around them. Anytime a navmesh cut is applied, I am seeing every node on the entire navmesh having it’s tag reset to basic ground. I understand that you can re-apply the tags from the GraphUpdateScene component after the cutting has occurred, but it is too costly to do this every time the navmesh is cut throughout the entire large world. It’s also true that tags aren’t super exact for recast graphs since the navmesh does not have uniformly spaced nodes, but so far it has seemed like an okay solution for providing vague boundaries within the world if they can better coexist with navmesh cuts.

I was wondering if you had any recommendations on solving this problem in a large world with a recast graph? So far I have been wondering if navmesh cuts could instead only reset the tags of nodes inside the tiles effected by the cut, and either save a copy of the effected tiles before they are cut, and then reapply their original values once this temporary cut disappears, or just recalculate those specific tiles.

However, I am open to any other recommendations if you would approach this problem in a vastly different way. I have been really impressed by your pathfinding solutions and have thoroughly enjoyed working with them! To give more information, in this open world the player may have up to 10 npc agents within a closer proximity who are actively pathfinding while fighting, and possibly 10-30 agents off in the distance patrolling. The world is currently somewhat static other than occasional abilities that cut the navmesh, and is roughly 8 x 8 kilometers large at the moment. We are world streaming the terrain tiles as the player moves around, and I just load all the terrain tiles at once to bake the recast graph as one large graph for the whole world, which has been working really nicely so far! Any help with this problem of partitioning the world so that only certain Npcs will traverse through certain areas would be greatly appreciated. Thank You!

maybe this option will be usful -recastmeshobj/ / didnt tested walking areas(they work in 2020+ unity as i understand) but first two (exlude .unwalk)works fast if update graph within obj bounds
https://arongranberg.com/astar/docs/recastmeshobj.html
recast23

I need certain npcs to be able to walk through certain areas while others can’t. So I can’t just mark these spots in the graph as unwalkable, unless I created multiple graphs and each different npc type used a different graph. However, the world is extremely large, (8 km x 8 km) so I don’t think I can have multiple of these large graphs loaded at once.

This is why I was hoping to have a single graph with tags for certain areas, but anytime a navmesh cut is used, ALL nodes in the entire graph are having their tags reset to nothing, instead of just the nodes in the effected tile.

Hi

Sorry for the late reply.
If you use the beta version you can, as @Nikita mentions set it to WalkableSurfaceWithTag. That means you can have different NPCs have different rules for if they are allowed to walk there and for any penalties for walking there.

Sadly navmesh cutting is not particularly compatible with tags. Navmesh cutting uses a triangulation step, and it’s not really possible to keep tag information in the general case. :confused:
In the beta I think I at least changed the code to only discard tag information from nodes that actually changed, not all nodes. But I’m not sure how much this helps.

Hello! No worries, sorry for my late response, I had tabled this while working on some other aspects of the game. Because we do use navmesh cuts quite often, I think a workable solution that avoids using tags could be to have one graph for the land, and one graph for the water. I could then set on each different npc which graphs it’s able to traverse, and still have the option to cut the navmesh.

It seems I could add the RecastMeshObj component set to ‘unwalkable surface’ and ‘solid’, on the box colliders of my water planes, to exclude the water when baking the graph for the land. But, is there a way to do the reverse for the water only graph? Like a way to bake the graph for the entire world which only includes just the water? If I use these same RecastMeshObj components at the water plane’s level but now set ‘to walkable surface’, it comes close to that but also creates a navmesh along the entire plane, including parts that are below the terrain.


The water plane is highlighted in orange, I would like to create a water graph that specifically only has nodes that would be bound within what I outlined in blue, creating a seam where the water plane intersects the terrain tile, for all my water spread across the world.

Hi

You might be able to use the RecastGraph - A* Pathfinding Project for this. Also you may want to use the beta version, because I think the relevantGraphSurfaceMode might have some bugs in the currently released version.

Hi Aron,

Sorry to be so indecisive, but after some tinkering I think I will give tags another try. Currently I am using the beta with version 4.3.46, and I am seeing navmesh cuts discard tag information from all nodes in the entire graph. Is it somewhere between 4.3.47 and 4.3.50 where you made the change for tag information to only be discarded from nodes that changed? I couldn’t find it in any of the change logs.

Also, on a somewhat unrelated note, the RecastMeshObj component seems really useful for being able to fine tune where and how the navmesh is baked, but it feels a little bit limited in that it requires a collider. It would be really cool if you could set the bounds of the RecastMeshObj in a way that was more similar to how the “GraphUpdateScene” component is so convenient for setting bounds. Maybe after setting the bounds, there could be a button for generating a mesh that fits to the terrain within those bounds, and the RecastMeshObj would use a mesh collider with that newly generated mesh. I think I might try my luck at making something like that, but wanted to bring it up since I think it’d be so useful! Like a really convenient way to draw the bounds of where you want the recast graph to have a seam or be walkable/unwalkable.
It would also be nice if RecastMeshObj components obey the layermasks set for each graph, so someone could for example, have one graph for “water” that only scans RecastMeshObjects set to the water layer. Right now it seems that all RecastMeshObjects are included in every graph, regardless of what each graph’s layermask/tagmask is set to.

Hmm, no that should have been done much earlier. Yeah, it seems I forgot to write about it in the changelog.
It’s possible that it still clears all tags the first time cuts are applied, I’m not 100% sure.

Hmm, often people use RecastMeshObj components to add exceptions to the layer mask rules. But I agree it is a bit limiting.