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

@ -36,6 +36,8 @@
#include "nav_map_iteration_3d.h"
#include "nav_region_iteration_3d.h"
#include "core/config/project_settings.h"
using namespace Nav3D;
PointKey NavMapBuilder3D::get_point_key(const Vector3 &p_pos, const Vector3 &p_cell_size) {
@ -111,6 +113,7 @@ void NavMapBuilder3D::_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<NavRegionIteration3D> &region : map_iteration->region_iterations) {
for (const ConnectableEdge &connectable_edge : region->get_external_edges()) {
@ -139,11 +142,15 @@ void NavMapBuilder3D::_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/3d/merge_rasterizer_cell_scale' to 0.001.");
edge_merge_error_count++;
}
}
}
if (edge_merge_error_count > 0 && GLOBAL_GET_CACHED(bool, "navigation/3d/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/3d/merge_rasterizer_cell_scale' in the project settings.\nThis warning can be toggled under 'navigation/3d/warnings/navmesh_edge_merge_errors' in the project settings.");
}
r_build.free_edge_count = free_edges_count;
}

View File

@ -34,6 +34,8 @@
#include "../nav_region_3d.h"
#include "nav_region_iteration_3d.h"
#include "core/config/project_settings.h"
using namespace Nav3D;
void NavRegionBuilder3D::build_iteration(NavRegionIterationBuild3D &r_build) {
@ -180,6 +182,7 @@ void NavRegionBuilder3D::_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++) {
@ -209,11 +212,15 @@ void NavRegionBuilder3D::_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/3d/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/3d/merge_rasterizer_cell_scale' in the project settings.\nThis warning can be toggled under 'navigation/3d/warnings/navmesh_edge_merge_errors' in the project settings.");
}
performance_data.pm_edge_free_count = free_edges_count;
}

View File

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

View File

@ -62,7 +62,7 @@ class NavMap3D : public NavRid3D {
Vector3 merge_rasterizer_cell_size = Vector3(cell_size, cell_height, 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

@ -100,12 +100,18 @@ void NavRegion3D::set_transform(Transform3D p_transform) {
void NavRegion3D::set_navigation_mesh(Ref<NavigationMesh> 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/3d/warnings/navmesh_cell_size_mismatch")) {
const double map_cell_size = double(map->get_cell_size());
const double map_cell_height = double(map->get_cell_height());
const double navmesh_cell_size = double(p_navigation_mesh->get_cell_size());
const double navmesh_cell_height = double(p_navigation_mesh->get_cell_height());
if (map && p_navigation_mesh.is_valid() && !Math::is_equal_approx(double(map->get_cell_height()), double(p_navigation_mesh->get_cell_height()))) {
ERR_PRINT_ONCE(vformat("Attempted to update a navigation region with a navigation mesh that uses a `cell_height` of %s while assigned to a navigation map set to a `cell_height` of %s. The cell height for navigation maps can be changed by using the NavigationServer map_set_cell_height() function. The cell height for default navigation maps can also be changed in the ProjectSettings.", double(p_navigation_mesh->get_cell_height()), double(map->get_cell_height())));
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/3d/warnings/navmesh_cell_size_mismatch' in the project settings.", navmesh_cell_size, map_cell_size));
}
if (map_cell_height > navmesh_cell_height) {
WARN_PRINT(vformat("A navigation mesh that uses a `cell_height` of %s was assigned to a navigation map set to a larger `cell_height` of %s.\nThis mismatch in cell height can cause rasterization errors with navigation mesh edges on the navigation map.\nThe cell height for navigation maps can be changed by using the NavigationServer map_set_cell_height() function.\nThe cell height for default navigation maps can also be changed in the project settings.\nThis warning can be toggled under 'navigation/3d/warnings/navmesh_cell_size_mismatch' in the project settings.", navmesh_cell_height, map_cell_height));
}
}
#endif // DEBUG_ENABLED