Navigation
There is plenty of info on the Godot site. Check Godot Navigation Documentation
Useful Nodes
- NavigationRegion3D - Using NavigationRegions
- NavigationMeshSourceGeometryData3D: Container for parsed source geometry data used in navigation mesh baking.
- AStar3D: A basic implementation of A* algorithm. Needs custom management functionality.
Various Ressources
u/smix_eight on Baking Navmesh Regions at Runtime Best Practices
In order to bake something your need source geometry from your level. If you do not provide cached source geometry with a NavigationMeshSourceGeometryData object this source geometry will be directly parsed from the SceneTree nodes. The nodes themself have no data, so what they do when parsed is request that data from e.g. PhysicsServer or RenderingServer. Especially the RenderingServer needs to receive all the mesh geometry data from the GPU and gets stalled in the process. Interrupting the rendering like that can absolutely destroy your frame rate on large and complex meshes or when the RenderingServer runs threaded.
The problem with the SceneTree (and to some extend with nodes in general) is that they are not thread-safe. So this part of the navigation mesh creation process is forced to happen on the main-thread no matter what. The process when run on a thread would have the potential to error or crash your game because nodes or SceneTree can not be accessed by threads outside the main thread by default. SceneTree thread-guards will simply interrupt the parsing and the baking with no data received would give you an empty navigation mesh at best.
What you can do against this is to not parse at runtime with the SceneTree directly involved, or at least not do it with a large scene, but in controlled steps on the main thread. You should preferably use physics shapes as those are faster to parse and receive from the PhysicsServer compared to Meshes and the RenderingServer. As mentioned you can use a NavigationMeshSourceGeometryData to parse your source geometry in advance with the NavigationServer and cache that resource data, then add your changes in script on top. Or you can use that resource to do your entire source geometry procedurally with scripts. This can also be done on threads as long as you do not touch the SceneTree or the PhysicsServer or RenderingServer.
The NavigationMeshSourceGeometryData3D is just 2 arrays of vertices and indices for basic geometry triangle faces. Everything is in world space so if you have a Mesh you need to offset all the mesh vertices by your MeshInstance3D transform.
E.g. you have the mesh arrays you can just add them with the add_mesh_array() function. If you only have faces you can do so with the add_faces() function. If you have the indices and vertices array you can also set them directly.
If you have your static geometry parsed in such a resource you can duplicate the resource and add the more dynamic objects on top everytime a change occurs and you need to update the navmesh. The duplicate might not be super-fast to do when your geometry is very heavy and complex but can be done in background threads because it is just array data.
The 3D navigation mesh baking uses the ReCast lib and expects indices in CCW winding order.
So for a triangle face the vertices are 0, 1, 2 and the indices are 0, 2, 1.
You can use the e.g. add_faces() function as that will add the correct indices for you.