Extend baked navigation region to edge of terrain

Godot Version

4.3

Question

How can I bake a navigation region that extends exactly to the edges of the terrain it’s baking from? Right now it will essentially add a margin around the terrain that is half the agent radius, but I want it to extend up until the bounds of the terrain so that I can align my chunked nav regions perfectly and not have to use edge connections, because it adds about 25s onto my level generation.

The only thing I can think of is extending the terrain chunks to what they are now plus the agent radius, but then I’d have overlapping at the seams/corners which I’d rather not have.

This is what I currently have:

decrease agent_radius property of navregion to 0 or increase cell size (will merge chunk borders) purple line between means borders are merged.

try to spawn navregions disabled from start and enable only needed regions. Baking happens almost immediately (in 2D). When one new regions joins map it generates significant impact on perf

Neither of those are really an option for me. If I increase the cell size then I get less granularity throughout my navmesh, and if I reduce the agent radius to 0 then they don’t avoid obstacles properly and get stuck all of the time.

I found only that 2 options when used 2dnavmesh. You can only trade between these 2 parameters, or enable edge-centred path calc

Yeah I definitely can’t go with any of those options unfortunately, but thanks for the suggestions.

well thing that comes on mind that you can increase size of NavigationPolygon during .add_outline(PackedVector3Array()) just by offset of agent_radius to compensate border eroding

I tried in mine project and it seems working.
how it looks as code:

	var nav_poly:=NavigationPolygon.new()
	const agent_radius:=24
	const multiplier:=1.6
	nav_poly.add_outline(PackedVector2Array([Vector2(-Chunk.GRID_STEP.x-agent_radius*multiplier, 0), Vector2(0, -Chunk.GRID_STEP.y-agent_radius*multiplier), Vector2(Chunk.GRID_STEP.x+agent_radius*multiplier,0), Vector2(0, Chunk.GRID_STEP.y+agent_radius*multiplier)]))

Use the baking bounds and border size. See documentation here Using navigation meshes — Godot Engine (latest) documentation in English

looks like it intended to use only with square type maps if its 2D, it’s not clear how bake mesh if it is an isometric polygon, and .backing_rect and border is useless in this case. I’m not using TileMapLayer, I’m using my own variant of it that relies on Polygon2D.


its enabled by script, thats why it looks disabled in debug.
agents walk correctly but sometimes agents try to enter in chunk from left/top/right/down corners of chunk

I don’t think I can use that, I’m doing this in 3D with NavigationMesh rather than NavigationPolygon.

I had a look at the example code and I think that’s exactly what I want, but does that mean that I can’t also chunk the terrain? Right now I have a terrain mesh/collider for each navigation region, so everything is chunked, but if I use the example in godot-demo-projects/3d/navigation_mesh_chunks/navmesh_chhunks_demo_3d.gd at master · godotengine/godot-demo-projects · GitHub then I can’t extend the filter AABB to include the neighbouring terrain chunks because they’re isolated to only their own chunks.

I think just making the terrain one big mesh should be ok performance-wise, I’m using 400 vertices per terrain mesh per chunk (chunk size is 50) and 100 chunks, so 40000 vertices, but I’m just wondering if it’s possible without having to do that.

Actually I’m thinking to do this I’ll need to use NavigationMeshSourceGeometryData3D anyway, so that I can reference the surrounding terrain for each navigation region and not be bound to only its children, so if I’m already doing that then I should be able to keep my chunked terrain and just pass in the neighbouring chunks for each chunk. I’ll try out some things and then get back to you @smix8

Using BorderSize like the example in godot-demo-projects/3d/navigation_mesh_chunks/navmesh_chhunks_demo_3d.gd at master · godotengine/godot-demo-projects · GitHub worked for me and shaved about 12 seconds off the generation, from 40s to 28s.

Not exactly what this post is about, but my main reason for doing this was to speed up the level generation, so some other things that helped performance a lot were changing tree colliders from cylinders to rectangles (reduced it by about 16s which I was very surprised about), and then previously I was shooting rays down to place trees and grass and whatnot, so I changed it to sample the height from the noise wherever it can, which got rid of about 4s. So, now I’m down from ~40s to ~8s, which I’m happy with!

Cylinders (or more complex shapes in general) are very inefficient shapes to parse. Especially round shape have so many edges that need to be processed which is slow.

In 3D all the geometry gets rastered into a voxel grid for the navmesh baking. So what also helps with performance is to cap the height of the baking bounds as this usually creates less vertical voxel layers than the auto-calculated bounds.

Without the baking bounds set the auto-calculated bounds will be as height as the highest parsed geometry object. So a single high “tree” object can cause x-amount of pointless vertical voxel layers. For those kind of objects parsing a “tree stump” would be usually enough to bake the ground navmesh avoiding additional vertical voxel layers.