From 9ea8d4fa3890324832c9b2b7f8d1222bcfd6363f Mon Sep 17 00:00:00 2001 From: Pawel Lampe Date: Sun, 4 Feb 2024 21:31:07 +0100 Subject: [PATCH] Add means for fixing navmap synchronization errors --- doc/classes/NavigationServer3D.xml | 15 ++++++++++++ doc/classes/ProjectSettings.xml | 3 +++ .../navigation/godot_navigation_server.cpp | 14 +++++++++++ modules/navigation/godot_navigation_server.h | 3 +++ modules/navigation/nav_map.cpp | 24 +++++++++++++++---- modules/navigation/nav_map.h | 13 ++++++++++ scene/resources/world_3d.cpp | 1 + servers/navigation_server_3d.cpp | 3 +++ servers/navigation_server_3d.h | 3 +++ servers/navigation_server_3d_dummy.h | 2 ++ 10 files changed, 77 insertions(+), 4 deletions(-) diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 0d1744162d0c..caadb844f174 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -582,6 +582,13 @@ Returns all navigation link [RID]s that are currently assigned to the requested navigation [param map]. + + + + + Returns map's internal merge rasterizer cell scale. + + @@ -679,6 +686,14 @@ Set the map's link connection radius used to connect links to navigation polygons. + + + + + + Set the map's internal merge rasterizer cell scale used to control merging sensitivity. + + diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 6f65572f343e..d76ac7c6d1a5 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2045,6 +2045,9 @@ Default up orientation for 3D navigation maps. See [method NavigationServer3D.map_set_up]. + + Default merge rasterizer cell scale for 3D navigation maps. See [method NavigationServer3D.map_set_merge_rasterizer_cell_scale]. + If enabled 3D navigation regions will use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin. This setting only affects World3D default navigation maps. diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index f6d94f280b85..14c72f3db402 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -180,6 +180,20 @@ real_t GodotNavigationServer::map_get_cell_height(RID p_map) const { return map->get_cell_height(); } +COMMAND_2(map_set_merge_rasterizer_cell_scale, RID, p_map, float, p_value) { + NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_NULL(map); + + map->set_merge_rasterizer_cell_scale(p_value); +} + +float GodotNavigationServer::map_get_merge_rasterizer_cell_scale(RID p_map) const { + NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_NULL_V(map, false); + + return map->get_merge_rasterizer_cell_scale(); +} + COMMAND_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled) { NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 6798978d218e..f3bc1185d82c 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -117,6 +117,9 @@ public: COMMAND_2(map_set_cell_height, RID, p_map, real_t, p_cell_height); virtual real_t map_get_cell_height(RID p_map) const override; + COMMAND_2(map_set_merge_rasterizer_cell_scale, RID, p_map, float, p_value); + virtual float map_get_merge_rasterizer_cell_scale(RID p_map) const override; + COMMAND_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled); virtual bool map_get_use_edge_connections(RID p_map) const override; diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 6429513b5372..7edf4a0bd1d0 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -67,6 +67,7 @@ void NavMap::set_cell_size(real_t p_cell_size) { return; } cell_size = p_cell_size; + _update_merge_rasterizer_cell_dimensions(); regenerate_polygons = true; } @@ -75,6 +76,16 @@ void NavMap::set_cell_height(real_t p_cell_height) { return; } cell_height = p_cell_height; + _update_merge_rasterizer_cell_dimensions(); + regenerate_polygons = true; +} + +void NavMap::set_merge_rasterizer_cell_scale(float p_value) { + if (merge_rasterizer_cell_scale == p_value) { + return; + } + merge_rasterizer_cell_scale = p_value; + _update_merge_rasterizer_cell_dimensions(); regenerate_polygons = true; } @@ -103,9 +114,9 @@ void NavMap::set_link_connection_radius(real_t p_link_connection_radius) { } gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const { - const int x = static_cast(Math::floor(p_pos.x / cell_size)); - const int y = static_cast(Math::floor(p_pos.y / cell_height)); - const int z = static_cast(Math::floor(p_pos.z / cell_size)); + const int x = static_cast(Math::floor(p_pos.x / merge_rasterizer_cell_size)); + const int y = static_cast(Math::floor(p_pos.y / merge_rasterizer_cell_height)); + const int z = static_cast(Math::floor(p_pos.z / merge_rasterizer_cell_size)); gd::PointKey p; p.key = 0; @@ -923,7 +934,7 @@ void NavMap::sync() { connections[ek].push_back(new_connection); } 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'."); + 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."); } } } @@ -1365,6 +1376,11 @@ void NavMap::clip_path(const LocalVector &p_navigation_polys } } +void NavMap::_update_merge_rasterizer_cell_dimensions() { + merge_rasterizer_cell_size = cell_size * merge_rasterizer_cell_scale; + merge_rasterizer_cell_height = cell_height * merge_rasterizer_cell_scale; +} + NavMap::NavMap() { avoidance_use_multiple_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_multiple_threads"); avoidance_use_high_priority_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_high_priority_threads"); diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index e8cbe7e2474e..b00bddc0ab93 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -56,6 +56,12 @@ class NavMap : public NavRid { real_t cell_size = 0.25; // Must match ProjectSettings default 3D cell_size and NavigationMesh cell_size. real_t cell_height = 0.25; // Must match ProjectSettings default 3D cell_height and NavigationMesh cell_height. + // For the inter-region merging to work, internal rasterization is performed. + float merge_rasterizer_cell_size = 0.25; + float merge_rasterizer_cell_height = 0.25; + // This value is used to control sensitivity of internal rasterizer. + float merge_rasterizer_cell_scale = 1.0; + bool use_edge_connections = true; /// This value is used to detect the near edges to connect. real_t edge_connection_margin = 0.25; @@ -133,6 +139,11 @@ public: void set_cell_height(real_t p_cell_height); real_t get_cell_height() const { return cell_height; } + void set_merge_rasterizer_cell_scale(float p_value); + float get_merge_rasterizer_cell_scale() const { + return merge_rasterizer_cell_scale; + } + void set_use_edge_connections(bool p_enabled); bool get_use_edge_connections() const { return use_edge_connections; @@ -217,6 +228,8 @@ private: void _update_rvo_obstacles_tree_2d(); void _update_rvo_agents_tree_2d(); void _update_rvo_agents_tree_3d(); + + void _update_merge_rasterizer_cell_dimensions(); }; #endif // NAV_MAP_H diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index b8646c538712..81e261d6b794 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -69,6 +69,7 @@ RID World3D::get_navigation_map() const { NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_GET("navigation/3d/default_cell_size")); NavigationServer3D::get_singleton()->map_set_cell_height(navigation_map, GLOBAL_GET("navigation/3d/default_cell_height")); NavigationServer3D::get_singleton()->map_set_up(navigation_map, GLOBAL_GET("navigation/3d/default_up")); + NavigationServer3D::get_singleton()->map_set_merge_rasterizer_cell_scale(navigation_map, GLOBAL_GET("navigation/3d/merge_rasterizer_cell_scale")); NavigationServer3D::get_singleton()->map_set_use_edge_connections(navigation_map, GLOBAL_GET("navigation/3d/use_edge_connections")); NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_GET("navigation/3d/default_edge_connection_margin")); NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_GET("navigation/3d/default_link_connection_radius")); diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 9ea1e8f59d7c..7fc027284bc7 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -45,6 +45,8 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer3D::map_get_cell_size); ClassDB::bind_method(D_METHOD("map_set_cell_height", "map", "cell_height"), &NavigationServer3D::map_set_cell_height); ClassDB::bind_method(D_METHOD("map_get_cell_height", "map"), &NavigationServer3D::map_get_cell_height); + ClassDB::bind_method(D_METHOD("map_set_merge_rasterizer_cell_scale", "map", "scale"), &NavigationServer3D::map_set_merge_rasterizer_cell_scale); + ClassDB::bind_method(D_METHOD("map_get_merge_rasterizer_cell_scale", "map"), &NavigationServer3D::map_get_merge_rasterizer_cell_scale); ClassDB::bind_method(D_METHOD("map_set_use_edge_connections", "map", "enabled"), &NavigationServer3D::map_set_use_edge_connections); ClassDB::bind_method(D_METHOD("map_get_use_edge_connections", "map"), &NavigationServer3D::map_get_use_edge_connections); ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer3D::map_set_edge_connection_margin); @@ -222,6 +224,7 @@ NavigationServer3D::NavigationServer3D() { GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "navigation/3d/default_cell_size", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), 0.25); GLOBAL_DEF_BASIC("navigation/3d/default_cell_height", 0.25); GLOBAL_DEF("navigation/3d/default_up", Vector3(0, 1, 0)); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "navigation/3d/merge_rasterizer_cell_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001,or_greater"), 1.0); GLOBAL_DEF("navigation/3d/use_edge_connections", true); GLOBAL_DEF_BASIC("navigation/3d/default_edge_connection_margin", 0.25); GLOBAL_DEF_BASIC("navigation/3d/default_link_connection_radius", 1.0); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 02985ec6c1c3..552e3185868a 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -84,6 +84,9 @@ public: virtual void map_set_cell_height(RID p_map, real_t p_height) = 0; virtual real_t map_get_cell_height(RID p_map) const = 0; + virtual void map_set_merge_rasterizer_cell_scale(RID p_map, float p_value) = 0; + virtual float map_get_merge_rasterizer_cell_scale(RID p_map) const = 0; + virtual void map_set_use_edge_connections(RID p_map, bool p_enabled) = 0; virtual bool map_get_use_edge_connections(RID p_map) const = 0; diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h index c93953eb27e0..d595fcde7ebf 100644 --- a/servers/navigation_server_3d_dummy.h +++ b/servers/navigation_server_3d_dummy.h @@ -47,6 +47,8 @@ public: real_t map_get_cell_size(RID p_map) const override { return 0; } void map_set_cell_height(RID p_map, real_t p_cell_height) override {} real_t map_get_cell_height(RID p_map) const override { return 0; } + void map_set_merge_rasterizer_cell_scale(RID p_map, float p_value) override {} + float map_get_merge_rasterizer_cell_scale(RID p_map) const override { return 1.0; } void map_set_use_edge_connections(RID p_map, bool p_enabled) override {} bool map_get_use_edge_connections(RID p_map) const override { return false; } void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) override {}