Spherical Worlds
Tutorial on how to use pathfinding on non-planar surfaces.
In some games, you may need to use pathfinding and local avoidance on surfaces like planets or rings that do not always have the same direction as 'up'. In the image below you can see a few example shapes of worlds. However you can make them as crazy as you'd like (almost, see below for some tips).
Configuring a graph
Both navmesh graphs and point graphs can be used. However for most purposes navmesh graphs are recommended. The way you set them up is pretty much identical to how it's done in the navmesh tutorial (see Creating a navmesh manually) with the difference that instead of a planar surface, you create for example a sphere.
You should make sure that 'Recalculate Normals' is disabled in the navmesh graph settings. If that is left enabled, then normals will be recalculated assuming that the Y+ axis is up, which in this case it will not be everywhere.
Movement scripts
For moving characters across a curved surface you can either use a custom movement script, or you can use the included AIPathAlignToSurface component. The AIPathAlignToSurface script inherits from AIPath and it changes a few things to make it more suitable for a curved surface. Firstly it uses the normal of the ground below it to align itself to the surface. Secondly it makes the gravity be relative to character's up direction instead of the world's up direction. So if you for example set the gravity to (0, -10, 0) the character will be pulled downwards towards the surface it is standing on, even if it is on the bottom side of say a sphere.
It is recommended to use the funnel modifier on navmesh graphs for a higher path quality, however for that to work correctly on curved surfaces you need to make sure both the unwrap and splitAtEveryPortal options are enabled.
If you use a mesh collider as ground, the AIPathAlignToSurface script will try to interpolate the surface normal to make movement across it much smoother. This will however only work if the mesh used for the collider is readable. So make sure you check the 'Read/Write Enabled' checkbox in the mesh asset importer.
Local avoidance
Local avoidance is supported on curved surfaces out of the box. The only thing you need to do is to, as usual, add an RVOSimulator to the scene and an RVOController to your agent (see Local Avoidance for more info about this) and then you have to set the movement plane option on the RVOSimulator to 'Arbitrary'. The AIPathAlignToSurface script takes care of informing the RVOController about the orientation of the surface it is standing on. If you are writing your own movement script you will have to call the RVOController.SetMovementPlane method to update the orientation.
Tips for good spherical navmeshes
A good navmesh should have roughly equally sized triangles which are not too small (as that will cause pathfinding to be unecessarily slow as it has to search more nodes) or too large (as that will reduce the precision too much). If you use the built-in movement scripts you should try to avoid very drastic surface changes as then movement across the edge may look pretty bad. E.g use a rounded cube instead of a normal cube.
Below you can see some examples of good and bad navmeshes. These are of course very simple example navmeshes, but hopefully the general idea of what to avoid should come across.
Not recommended. This navmesh both has sharp corners (hard to move over them) and very large triangles (may be too large for good paths, note that paths are searched on a node by node basis). Not recommended This navmesh is subdivided so the size of the nodes is better, but it still has very sharp corners. Not recommened This navmesh has no sharp corners, but the triangles are of very different sizes, which is generally bad for the path quality. Recommended This is a nice navmesh. Recommended This is a nice navmesh. Not recommended This navmesh has triangles of very different sizes (especially near the poles), which is generally bad for the path quality. Recommended This is a nice navmesh.