Make navmesh rasterization errors more lenient

Make navmesh rasterization on the navigation regions and map more lenient by starting out with a lower internal cell scale by default and changing the merge error to just warning that can be toggled.
This commit is contained in:
smix8 2025-09-23 22:59:07 +02:00
parent a078895ad2
commit 19df15f1dc
12 changed files with 74 additions and 15 deletions

View file

@ -37,6 +37,8 @@
#include "nav_map_iteration_2d.h"
#include "nav_region_iteration_2d.h"
#include "core/config/project_settings.h"
using namespace Nav2D;
PointKey NavMapBuilder2D::get_point_key(const Vector2 &p_pos, const Vector2 &p_cell_size) {
@ -110,6 +112,7 @@ void NavMapBuilder2D::_build_step_find_edge_connection_pairs(NavMapIterationBuil
connection_pairs_map.clear();
connection_pairs_map.reserve(polygon_count);
int free_edges_count = 0; // How many ConnectionPairs have only one Connection.
int edge_merge_error_count = 0;
for (const Ref<NavRegionIteration2D> &region : map_iteration->region_iterations) {
for (const ConnectableEdge &connectable_edge : region->get_external_edges()) {
@ -138,11 +141,15 @@ void NavMapBuilder2D::_build_step_find_edge_connection_pairs(NavMapIterationBuil
} else {
// The edge is already connected with another edge, skip.
ERR_PRINT_ONCE("Navigation map synchronization error. Attempted to merge a navigation mesh polygon edge with another already-merged edge. This is usually caused by crossing edges, overlapping polygons, or a mismatch of the NavigationMesh / NavigationPolygon baked 'cell_size' and navigation map 'cell_size'. If you're certain none of above is the case, change 'navigation/2d/merge_rasterizer_cell_scale' to 0.001.");
edge_merge_error_count++;
}
}
}
if (edge_merge_error_count > 0 && GLOBAL_GET_CACHED(bool, "navigation/2d/warnings/navmesh_edge_merge_errors")) {
WARN_PRINT("Navigation map synchronization had " + itos(edge_merge_error_count) + " edge error(s).\nMore than 2 edges tried to occupy the same map rasterization space.\nThis causes a logical error in the navigation mesh geometry and is commonly caused by overlap or too densely placed edges.\nConsider baking with a higher 'cell_size', greater geometry margin, and less detailed bake objects to cause fewer edges.\nConsider lowering the 'navigation/2d/merge_rasterizer_cell_scale' in the project settings.\nThis warning can be toggled under 'navigation/2d/warnings/navmesh_edge_merge_errors' in the project settings.");
}
r_build.free_edge_count = free_edges_count;
}

View file

@ -35,6 +35,8 @@
#include "../triangle2.h"
#include "nav_region_iteration_2d.h"
#include "core/config/project_settings.h"
using namespace Nav2D;
void NavRegionBuilder2D::build_iteration(NavRegionIterationBuild2D &r_build) {
@ -179,6 +181,7 @@ void NavRegionBuilder2D::_build_step_find_edge_connection_pairs(NavRegionIterati
region_iteration->external_edges.clear();
int free_edges_count = 0;
int edge_merge_error_count = 0;
for (Polygon &poly : region_iteration->navmesh_polygons) {
for (uint32_t p = 0; p < poly.vertices.size(); p++) {
@ -208,11 +211,15 @@ void NavRegionBuilder2D::_build_step_find_edge_connection_pairs(NavRegionIterati
} else {
// The edge is already connected with another edge, skip.
ERR_FAIL_COND_MSG(pair.size >= 2, "Navigation region synchronization error. More than 2 edges tried to occupy the same map rasterization space. This is a logical error in the navigation mesh caused by overlap or too densely placed edges.");
edge_merge_error_count++;
}
}
}
if (edge_merge_error_count > 0 && GLOBAL_GET_CACHED(bool, "navigation/2d/warnings/navmesh_edge_merge_errors")) {
WARN_PRINT("Navigation region synchronization had " + itos(edge_merge_error_count) + " edge error(s).\nMore than 2 edges tried to occupy the same map rasterization space.\nThis causes a logical error in the navigation mesh geometry and is commonly caused by overlap or too densely placed edges.\nConsider baking with a higher 'cell_size', greater geometry margin, and less detailed bake objects to cause fewer edges.\nConsider lowering the 'navigation/2d/merge_rasterizer_cell_scale' in the project settings.\nThis warning can be toggled under 'navigation/2d/warnings/navmesh_edge_merge_errors' in the project settings.");
}
performance_data.pm_edge_free_count = free_edges_count;
}

View file

@ -80,7 +80,7 @@ void NavMap2D::set_merge_rasterizer_cell_scale(float p_value) {
if (merge_rasterizer_cell_scale == p_value) {
return;
}
merge_rasterizer_cell_scale = MAX(p_value, NavigationDefaults2D::NAV_MESH_CELL_SIZE_MIN);
merge_rasterizer_cell_scale = MAX(MIN(p_value, 0.1), NavigationDefaults2D::NAV_MESH_CELL_SIZE_MIN);
_update_merge_rasterizer_cell_dimensions();
map_settings_dirty = true;
}

View file

@ -56,7 +56,7 @@ class NavMap2D : public NavRid2D {
Vector2 merge_rasterizer_cell_size = Vector2(cell_size, cell_size);
// This value is used to control sensitivity of internal rasterizer.
float merge_rasterizer_cell_scale = 1.0;
float merge_rasterizer_cell_scale = 0.1;
bool use_edge_connections = true;
/// This value is used to detect the near edges to connect.

View file

@ -94,8 +94,13 @@ void NavRegion2D::set_transform(Transform2D p_transform) {
void NavRegion2D::set_navigation_mesh(Ref<NavigationPolygon> p_navigation_mesh) {
#ifdef DEBUG_ENABLED
if (map && p_navigation_mesh.is_valid() && !Math::is_equal_approx(double(map->get_cell_size()), double(p_navigation_mesh->get_cell_size()))) {
ERR_PRINT_ONCE(vformat("Attempted to update a navigation region with a navigation mesh that uses a `cell_size` of %s while assigned to a navigation map set to a `cell_size` of %s. The cell size for navigation maps can be changed by using the NavigationServer map_set_cell_size() function. The cell size for default navigation maps can also be changed in the ProjectSettings.", double(p_navigation_mesh->get_cell_size()), double(map->get_cell_size())));
if (map && p_navigation_mesh.is_valid() && GLOBAL_GET_CACHED(bool, "navigation/2d/warnings/navmesh_cell_size_mismatch")) {
const double map_cell_size = double(map->get_cell_size());
const double navmesh_cell_size = double(p_navigation_mesh->get_cell_size());
if (map_cell_size > navmesh_cell_size) {
WARN_PRINT(vformat("A navigation mesh that uses a `cell_size` of %s was assigned to a navigation map set to a larger `cell_size` of %s.\nThis mismatch in cell size can cause rasterization errors with navigation mesh edges on the navigation map.\nThe cell size for navigation maps can be changed by using the NavigationServer map_set_cell_size() function.\nThe cell size for default navigation maps can also be changed in the project settings.\nThis warning can be toggled under 'navigation/2d/warnings/navmesh_cell_size_mismatch' in the project settings.", navmesh_cell_size, map_cell_size));
}
}
#endif // DEBUG_ENABLED