Spherical Worlds
Tutorial on how to use pathfinding on non-planar surfaces.
Contents
- Introduction
- Configuring a graph
- Movement scripts
- Local avoidance
- Tips for good non-planar navmeshes
- Graph updates
Introduction
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 above, you can see a few example shapes of worlds. However, you can make them as complex as you'd like (almost, see below for some tips).
In the package, you can find an example scene called Spherical world which shows how one can configure pathfinding and local avoidance for a spherical world.
Configuring a graph
It is not possible to automatically generate a navmesh on a spherical world (or any other shape that is not at least somewhat planar) using either grid graphs or recast graphs. So you will have to model the navmesh by hand in a 3D modeling application and then import it into Unity.
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 the FollowerEntity component, the AIPathAlignedToSurface component, or write your own movement script.
FollowerEntity
The FollowerEntity component supports spherical worlds out-of-the-box. The only thing you need to do is to change the FollowerEntity.movementPlaneSource field to NavmeshNormal. This will make the FollowerEntity use the normal of the navmesh below it to align itself to the surface. The FollowerEntity will also make sure that the gravity is relative to the character's up direction instead of the world's up direction.
How to calculate which direction is "up" for the agent.
The FollowerEntity is generally more robust compared to AIPathAlignedToSurface.
AIPathAlignedToSurface
The AIPathAlignedToSurface 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 the 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 splitAtEveryPortal is enabled.
If you use a mesh collider as ground, the AIPathAlignedToSurface 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 AIPathAlignedToSurface 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 set the RVOController.movementPlane property to update the orientation.
If you use the FollowerEntity component, you have to enable the local avoidance section on that component, instead of adding an RVOController to the agent.
Tips for good non-planar navmeshes
A good navmesh should have roughly equally sized triangles which are not too small (as that will cause pathfinding to be unnecessarily 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. |
| Not recommended. |
| Not recommended. |
| Recommended. |
| Recommended. |
| Not recommended. |
| Recommended. |
Graph updates
Spherical graphs unfortunately do not support navmesh cutting at all. However, you can use regular graph updates to mark triangles as unwalkable or walkable as you see fit.