How to setup Unity NavMesh on sphere

Hi there! After sharing this video, I was several times asked about how is it done, so, here it is - step-by-step guide.

3D model

First, you need a spherical surface itself. You can use unity`s default sphere, placing some boxes on it, I started from that too. But it turns out for me, that it`s much better to have the mesh, modelled in some 3D editing software. Here is the mine:

The reason why I have to model the mesh by myself, is pretty simple: when you dealing with complex shape, NavMesh baking leads to artifacts, like this:

Definitely, there are a lot of surfaces baked, which I don`t want my character go on. Also, the core of technique used, is to bake several NavMesh pieces, covering whole surface, but not overlaped each other.  It`s can be difficult to have clearly separated NavMesh zones from baking raw surface.

So, I deteached from my mesh all walkable surfaces, and saved it to 6 separate files. Each of which, again, contains only the walkable surface - no side walls, bottom sides, etc.

Here they are, slightly dragged from center, to be more clearly visible (of course, for baking, all of them must be percisely aligned to initial mesh):

Note the file naming: I decided to encode the piece orientation to every file name. 0_0_0 means that when this piece is on top, sphere`s euler rotation is X = 0, Y = 0, Z = 0. 

270_0_0 means that we should set sphere`s euler rotation to X = 270, Y = 0, Z = 0 to have this piece oriented upwards. Upwards is basic direction for us, because NavMesh is baked from top.

Baking NavMesh

Ok, so we have to put 6 walkable surfaces into our scene, as a child objects of main spherical mesh. Then disable sphere`s renderer (just for more clarity), and mark all 6 walkable surfaces as "navigation static". Then disable all of them, except first one to bake - lets it be the top one, 0_0_0. And press the "Bake" button:

You can see here my NavMesh baking settings. Note also, that sphere rotation is zero on all axes - which equals to currently baked surface.

After that, baked NavMeshData object appears as the file in project, in folder namet exactly as your scene name. Default name for this is "NavMesh", let`s rename it to "NavMesh_0_0_0", keeping our naming convention to avoid the mess.

Deactivate top piece, and activate next one - in my case it was "Planet2_walkable_90_0_0". It will appear on a side of our sphere. To get it on top, set sphere`s euler rotation equal to mentioned in the file name - X = 90, Y = 0, Z = 0.

Repeat baking:

New NavMeshData object appears - rename it, keeping the convention: "NavMesh_90_0_0".

Repeat this operations for every 6 walkable surfaces, until you`ll have 6 NavMeshData objects, properly named:


Reset sphere rotation, enable it`s MeshRenderer, and disable all the walkable surfaces - if we did all in right way, we don`t need them any more.

Scripting

Then we need to setup script. I attached NavMeshSphere.cs script, and a custom editor script for this one, to this post. Alternatively you can see code on GitHub Gist.

At the top of NavMeshSphere script you can find  NavMeshChunk struct defined. It includes the reference on NavMeshData object, Vector3 for euler rotation, and boolean flag "Enabled". 

Inside  NavMeshSphere class you can find a list of  NavMeshChunks, which actually stores all our baked data. When we call  LoadNavmeshData() method, all list items, which boolean flag "Enabled" set to "true", will be added into scene with given euler rotation. For this we`ll use unity`s standard routine  NavMesh.AddNavMeshData( NavMeshData data, Vector3 position, Quaternion rotation)

Here is how looks the first one (top) setup:

...and all of them set up properly:

Note, that for 90 and 270 degrees baked pieces, euler rotation set to opposite: 270 for 90, and vice versa. It`s because our naming means, how we should rotate sphere, to have this piece on top. And euler rotation defines, how this NavMeshData piece, baked from top, will be rotated on spawn - e.g., it`s opposit.

You can use "Load navmesh data" button to see it in editor, or, alternatively, you can hit "Play", then go back to scene view, keeping "Navigation" tab open.

Also, it useful for debug, to disable all the pieces, except one or two:

If you did all right, and enabled all the chunks, your sphere will be covered by NavMesh from all sides, like that:

Is that`s all? Nope. If you take a closer look, you`ll notice, that all the NavMesh chunks are isolated from each other:

Off Mesh Links

To handle this, I used approach, well described in unity`s oficial document: Creating an Off-mesh Link 

Of course, it`s an ugly piece of manual hand-work. I have an idea, how to create these links automatically:

Our NavMesh chunks are just a sides of box, projected on a sphere. If we`ll raycast from box`s edge in direction to opposite edge, rays will go exactly on the border between chunks. Then we need to define, if our hit point on navmesh, using NavMesh.SamplePosition(), with minimal distance a bit large than Agent Radius parameter, used during baking. If so, we can create an Off-Mesh Link here.

It`s in theory, I haven`t this job done yet. 

Instead, I just placed all the Off-mesh Links manually. And it works (huh, ok, most of them works, I just need to be more percise)!

And that`s, finally, all. To not force you to scroll back to the top of this post, here it is again youtube video of how it acts. For this test, I used MeshCollider on my surface, trivial NavMesh Agent, and raycast by mouse click - it`s all unity basics, so I`ll not share it here to not bloat my post any more.


I hope, it will help somebody to create an amazing game. 

Subscribe on my youtube channel, Visit my blog, and find some cool stuff on my GitHub account (don`t forget to give me a start)