- A* version: 5.3.3
- Unity version: 2022.3.60f1
Hi, we’re using Recast Graph navmesh for open-world game.
In the game, a bunch of blocks are removed at once to show water plane, we gather box colliders of those blocks to form one box collider for one UpdateGraphs
dispatch. But it results in significant fps drop (16 FPS), I would not say that the box for UpdateGraphs
is huge, but still is one the main bottlenecks now. Fps spike happens when updatePhysics is true; we really need it, otherwise incorrect behavior for NPC will be introduced [they will jump 2 blocks in height]. I’ve dived into AstarPath.active.UpdateGraphs
and it puts job into queue, so it looks like the calculations are out of the main thread, but still it results in spikes. Are there any walkarounds in here?
Use case:
When player removes blocks, we need to update physics on the place of removed blocks, so the surface of the graph goes down to water bed, signifying the correct height for NPCs
Hi
Do you have a screenshot of your graph and its settings?
Btw, newer versions of unity will have slightly better performance due to being able to use some newer features. Not a huge difference, but could be noticable.
Hi, thank you for your reply and the information about performance benefits of newer unity versions:
Here are the screenshots of the graph’s settings:
Hi
How large is the updated bound relative to the tiles of the graph? Typically, graph updates have the best performance if the tiles are slightly larger than the bounds that you update.
Your tile size is also very small, this has some overhead. I typically recommend values between 64 and 256.
Hi, Aron,
I’ve set 256 as a tile size, speaking about ratio, UpdateGraphs
area’s bounds depend on the spanned volume of blocks in the game by player. When there are no additional objects set in the map that make holes in the graph, with maximum spanned volume by blocks, the volume usually spreads out across 2 tiles[tile should be one triangle visually], one tile is not enough to cover it:
|--\----------|
| \ |
*****\******* |
******\****** | <- current situation with tile size =256
*******\***** | * - part of a volume for UpdateGraphs
********\**** | \ - part of a tile
*********\*** |
**********\** |
| \ |
Yeah, updating 1-4 tiles is very common and expected.
Are you seeing large performance issues with this?
Have you used the profiler to check what is using the cpu?
Btw. Make sure to keep gizmos disabled when doing these tests, as regenerating the graph gizmos can often be more expensive than the graph update itself.
Hi, Aron, it’s been a while because I’ve switched to other critical areas of the game that we’re are crafting. I’ve made profiling [no visualization of the graph], and I can tell that A* takes microns of seconds of CPU when being called once:
But takes 31 % when player places water (you can think about a circle like water cursor, and the player is dragging it around the map with left mouse button being held), so there are multiple sequential dense graph updates. I’m thinking of batching them, or distribute across frames, or queuing them
I think because it’s a dense call of update graph, this performance drop is happening. What do you think?
Do you think you can expand that profiler foldout so that we can see what takes time?
That’s very slow.
How many colliders would you expect are covered here? It looks like it must be finding a TON of colliders? Are you sure the bounding box is relatively small?
208 colliders with single water placement (not dragging the water marker). So, this is the main cause of the issue, the number of colliders within one graph update drives it crazy
bounding box is pretty small relative to the world (radius of water marker circle is 3), but there are pretty small blocks that fall into sphere cast (208 colliders)
I’m thinking of chunking the incoming bounding box on multiple graph updates and adding some small delays between them, so system has some time to regenerate after heavy job
Graph Update1 ---100%----> Handler------Subdivide bounding box---> 25% of initial box-> UpdateGraph()
\--------25% of initial box ------> UpdateGraph()
\--------25% of initial box-----> UpdateGraph()
\---------25 % of initial box------> UpdateGraph()
The core issue is, of course, number of colliders, gotta shrink them down