Recast update locks main thread

Hi,

I was under the impression that recast graph updates in runtime was threaded, backed up also by this thread:

However, when i’m doing an AstarPath.active.UpdateGraphs(guo), it locks the main thread for a couple of frames each time.
In my settings i have my thread count to automatic high load, and enabled batch graph updates, and im using tiles of size 16.

What could i be doing wrong?

Thanks in advance!

Hi

Even though most things run on a separate thread, there are a few things that need to run on the Unity thread, maybe that is what is causing the lag? For example it still needs to find all the meshes that could be contained inside that tile (which requires a FindObjectsOfType call unfortunately). To improve performance you can turn off ‘rasterize meshes’ and ‘rasterize colliders’ in the recast graph settings and instead add RecastMeshObj components (with dynamic=false if they do not move) to everything you want to include in the scan.
Also. A tile size of 16 sounds very low, you probably want to increase that.

Make sure it says that it runs on more than one thread in A* Inspector -> Settings.

Thanks for getting back to me.
I doubled the tile size, with no improvement, so i don’t think that’s a part of the issue. Also, i’m pretty sure it’s set to run on more than one thread - it says when running that it’s running on eight threads.

I’ll look into using the RecastMeshObj component!

Yeah, the tile size was an unrelated thing I noticed.

The GetSceneMeshes takes up to 146ms to perform, so that’s the one. I’ll fiddle around with it.

Well, i got it down to around 113ms, but it’s still not enough.

Is there any way of saving graph meshes in prefabs, and attach them to a graph in runtime? I believe i read somewhere earlier that you were working on a baking function?

Hi

You can save and load graphs, see http://arongranberg.com/astar/docs/save-load-graphs.php. However that doesn’t really help you if you want to update the graph during runtime.

Did you use RecastMeshObj and it still took 113ms?

No, i just edited the code a bit in the static function GetSceneMeshes to try to get it to take less time.

The game im working on, you construct your own building. When adding a floor, or a building block (room) at the sides of the building, i need to update the graph to also include that new added room. There will be a whole array of different options on what room type to add to the building, and the player chooses freely. So there is a need to be able to either update the active graph (in this case, recast), or to add a graph mesh stored in a prefab - to the active graph. Preferably without locking up the main thread so much that the game stutters.
Will loading graphs from prefabs do the trick?

Here’s a screenshot to show you what im talking about. Each wall encloses a room type of the players choosing.

Hi Aaron - as I’ve mentioned before there really is no need to use FindObjectsOfType. A simple OverlapCube does the job perfectly well in a tiny fraction of the time.

Realtime recast graph updating unfortunately has a long way to go, we’ve had to rewrite a lot of it to reduce memory allocations.

@cow_trix yes, for colliders that can be done and it is definitely something I should fix. Meshes can however not be found using an overlap call and they have to fall back to FindObjectsOfType. Yeah, I have also been doing some work to reduce allocations and structure the code better, but most of that is just in my dev version so far.

The voxelising renderers thing was always a feature I didn’t really understand to be honest. I mean sure, you can do it, but it leads to these kinds of design problems and blurs the logical seperation of renderer and collider. Saying that you can only use colliders as a base for recast voxelisation seems like a consistent and reasonable constraint to me.

I know what is the problem. You need another “hint” convex collider for every mesh collider, so you can detect it also if you are inside mesh (or outside). You can then also check if point is inside concave mesh or not.

Though this requires topologically closed meshes or “IsPointInside” function will fail.

Sometimes it might make sense to use the rendered mesh geometry as that is usually more detailed and thus it can be possible to get a higher quality navmesh. But it is very dependent on the game.

@vilivolcini Which problem were you referring to?

@aron_granberg

For example it still needs to find all the meshes that could be contained inside that tile (which requires a FindObjectsOfType call unfortunately)

I hope I understood correctly: I know when I did my voxelizing code, I couldn’t find concave meshes with Physics.CheckBox(…) if I was inside that mesh (but didn’t touch any walls).

This is why I did another convex ‘hint’ collider (I fitted box or sphere, whichever had less volume). This Hint collider is on separate Hint layer and has component “HintSolid” which refereed to original concave mesh collider.

This way, you don’t need to call FindObjectsOfType, but just Physics.OverlapBox on Hint layer, then collect meshes from HintSolid component and do operations on those meshes.

You know, if Hint collides then maybe you collide with original mesh collider, but if you do not collide with Hint then 100% you don’t collide with original mesh.

Well, my scripts have no way of knowing if the user has added any other mesh objects, so even if it could add a collider to everything, it would not necessarily find all of them.

Yeah it would require separate script that users would need to add to every mesh collider + meshes would need to be closed.