Godot Version
4.4.1.stable
Question
I have a 3D room based game and built a system on top of the navmesh to allow the AI to pathfind between rooms since some can be locked / non-traversable until some arbitrary event in the game changes it. The reason I decided to use a chunked system was because it allowed me to constrain paths to specific navigation regions ie. each room gets it’s own navigation region, so I could control the regions that the AI’s path traverses through. The problem is that there are problematic discrepancies between the navmesh generated when it’s not chunked vs the chunked navmesh system. My question is why is this happening and how can I fix it or work around it?
Heres a small test map I generated in Trenchbroom to eliminate as many edge cases as I could. It’s a flat map and each room is compromised of AABB’s
This is the runtime navmesh. The dark green lines represent each regions baking bounds. This image is showcasing specifically CON_Hallway
As you can see this room is composed of multiple regions and the bug occurs at the edges where these regions are “joined”. In this image the underlying disabled navmesh is what I’m generating in the editor with no chunking (only doing this for debugging), the overlaying enabled region is the chunked version of the navmesh (the actual navmesh used by the game). As you can see the edges aren’t merging properly even though this is a straight corridor
This problem gets amplified on an actual level from the game which has elevation changes and rooms that overlap on the y axis ie.
Here you can see some edges just don’t exist and some regions aren’t even connecting despite the debug navmesh which has no chunking shows that the area should be marked as traversable. This version also generates an error regarding merging edges.
Here is a condensed version of the code I’m using to generate the chunked navmesh at runtime.
It’s based on what I read from the docs
and the Navigation Mesh Chunks 3D demo project
var map: NavigationRegion3D = get_tree().get_nodes_in_group("Map")[0]
await map.ready
map.enabled = false
# The generated navmeshes are configured using editor specified values
var navmesh: NavigationMesh = map.navigation_mesh
# Parse geometry for the baking step
var source_geometry := NavigationMeshSourceGeometryData3D.new()
NavigationServer3D.parse_source_geometry_data(navmesh, source_geometry, map)
# Rooms is an array of a structure that stores it's associated baking bounds, navregions and it's navmap rid
for room in rooms:
room.navmap = NavigationServer3D.map_create()
NavigationServer3D.map_set_active(room.navmap, true)
NavigationServer3D.map_set_cell_size(room.navmap, navmesh.cell_size)
NavigationServer3D.map_set_cell_height(room.navmap, navmesh.cell_height)
# This is disabled because of the merging conflicts. Ideally this should be uncommented but can't since the edges are not lining up
#NavigationServer3D.map_set_merge_rasterizer_cell_scale(room.navmap, 0.0)
#NavigationServer3D.map_set_use_edge_connections(room.navmap, false)
# Bake navregions for each baking_bound in a room
for bounds_index in room.bounds.size():
var aabb: AABB = room.bounds[bounds_index]
var chunk_navmesh: NavigationMesh = navmesh.duplicate()
chunk_navmesh.border_size = chunk_navmesh.agent_radius
chunk_navmesh.filter_baking_aabb = aabb.grow(chunk_navmesh.border_size)
NavigationServer3D.bake_from_source_geometry_data(
chunk_navmesh,
source_geometry,
)
# @NOTE: Don't really understand this code. I took it from the Navigation Mesh Chunks 3D demo
# but don't understand how this exactly works. Any explanation would be
# appreciated!
# Snap vertex positions to avoid most rasterization issues with float precision.
var navmesh_vertices: PackedVector3Array = chunk_navmesh.vertices
for i in navmesh_vertices.size():
var vertex: Vector3 = navmesh_vertices[i]
navmesh_vertices[i] = vertex.snappedf(chunk_navmesh.cell_size * 0.1)
chunk_navmesh.vertices = navmesh_vertices
#end
var region := NavigationRegion3D.new()
region.name = "%s_%s" % [room.gd_node.name, bounds_index]
region.navigation_mesh = chunk_navmesh
map.get_node("../NavRegions").add_child(region)
NavigationServer3D.region_set_map(region.get_rid(), room.navmap)
NavigationServer3D.region_set_navigation_mesh(region.get_rid(), chunk_navmesh)
room.nav_regions.append(region)
#end
print("Done baking the map!")
This is the way it looks in the scene tree

and my navmesh settings
Any help would be greatly appreciated!







