From 085bc9504b7db92d19903f345af1a7f398c22041 Mon Sep 17 00:00:00 2001 From: smix8 <52464204+smix8@users.noreply.github.com> Date: Sun, 4 Feb 2024 18:54:23 +0100 Subject: [PATCH] Add NavigationPolygon border_size property for tile baking Adds NavigationPolygon border_size property for tile baking. Also adds baking Rect2 bounds. --- doc/classes/NavigationPolygon.xml | 10 +++++ modules/navigation/nav_mesh_generator_2d.cpp | 38 +++++++++++++++++++ scene/resources/navigation_polygon.cpp | 39 ++++++++++++++++++++ scene/resources/navigation_polygon.h | 13 +++++++ 4 files changed, 100 insertions(+) diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml index e0ad6032deff..54c5c80b78c6 100644 --- a/doc/classes/NavigationPolygon.xml +++ b/doc/classes/NavigationPolygon.xml @@ -174,6 +174,16 @@ The distance to erode/shrink the walkable surface when baking the navigation mesh. + + If the baking [Rect2] has an area the navigation mesh baking will be restricted to its enclosing area. + + + The position offset applied to the [member baking_rect] [Rect2]. + + + The size of the non-navigable border around the bake bounding area defined by the [member baking_rect] [Rect2]. + In conjunction with the [member baking_rect] the border size can be used to bake tile aligned navigation meshes without the tile edges being shrunk by [member agent_radius]. + The cell size used to rasterize the navigation mesh vertices. Must match with the cell size on the navigation map. diff --git a/modules/navigation/nav_mesh_generator_2d.cpp b/modules/navigation/nav_mesh_generator_2d.cpp index 6dfafa4e91e5..e202473e68c3 100644 --- a/modules/navigation/nav_mesh_generator_2d.cpp +++ b/modules/navigation/nav_mesh_generator_2d.cpp @@ -738,9 +738,13 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref &traversable_outline = p_navigation_mesh->get_outline(i); Path64 subject_path; + subject_path.reserve(traversable_outline.size()); for (const Vector2 &traversable_point : traversable_outline) { const Point64 &point = Point64(traversable_point.x, traversable_point.y); subject_path.push_back(point); @@ -750,6 +754,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref &traversable_outline : traversable_outlines) { Path64 subject_path; + subject_path.reserve(traversable_outline.size()); for (const Vector2 &traversable_point : traversable_outline) { const Point64 &point = Point64(traversable_point.x, traversable_point.y); subject_path.push_back(point); @@ -759,6 +764,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref &obstruction_outline : obstruction_outlines) { Path64 clip_path; + clip_path.reserve(obstruction_outline.size()); for (const Vector2 &obstruction_point : obstruction_outline) { const Point64 &point = Point64(obstruction_point.x, obstruction_point.y); clip_path.push_back(point); @@ -766,6 +772,22 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Refget_baking_rect(); + if (baking_rect.has_area()) { + Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset(); + + const int rect_begin_x = baking_rect.position[0] + baking_rect_offset.x; + const int rect_begin_y = baking_rect.position[1] + baking_rect_offset.y; + const int rect_end_x = baking_rect.position[0] + baking_rect.size[0] + baking_rect_offset.x; + const int rect_end_y = baking_rect.position[1] + baking_rect.size[1] + baking_rect_offset.y; + + Rect64 clipper_rect = Rect64(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y); + RectClip rect_clip = RectClip(clipper_rect); + + traversable_polygon_paths = rect_clip.Execute(traversable_polygon_paths); + obstruction_polygon_paths = rect_clip.Execute(obstruction_polygon_paths); + } + Paths64 path_solution; // first merge all traversable polygons according to user specified fill rule @@ -782,6 +804,21 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Refget_border_size(); + if (baking_rect.has_area() && border_size > 0.0) { + Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset(); + + const int rect_begin_x = baking_rect.position[0] + baking_rect_offset.x + border_size; + const int rect_begin_y = baking_rect.position[1] + baking_rect_offset.y + border_size; + const int rect_end_x = baking_rect.position[0] + baking_rect.size[0] + baking_rect_offset.x - border_size; + const int rect_end_y = baking_rect.position[1] + baking_rect.size[1] + baking_rect_offset.y - border_size; + + Rect64 clipper_rect = Rect64(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y); + RectClip rect_clip = RectClip(clipper_rect); + + path_solution = rect_clip.Execute(path_solution); + } + Vector> new_baked_outlines; for (const Path64 &scaled_path : path_solution) { @@ -799,6 +836,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref &baked_outline : new_baked_outlines) { Path64 polygon_path; diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp index 2770cb0b87e7..4e537f04b778 100644 --- a/scene/resources/navigation_polygon.cpp +++ b/scene/resources/navigation_polygon.cpp @@ -347,6 +347,15 @@ real_t NavigationPolygon::get_cell_size() const { return cell_size; } +void NavigationPolygon::set_border_size(real_t p_value) { + ERR_FAIL_COND(p_value < 0.0); + border_size = p_value; +} + +real_t NavigationPolygon::get_border_size() const { + return border_size; +} + void NavigationPolygon::set_parsed_geometry_type(ParsedGeometryType p_geometry_type) { ERR_FAIL_INDEX(p_geometry_type, PARSED_GEOMETRY_MAX); parsed_geometry_type = p_geometry_type; @@ -410,6 +419,24 @@ real_t NavigationPolygon::get_agent_radius() const { return agent_radius; } +void NavigationPolygon::set_baking_rect(const Rect2 &p_rect) { + baking_rect = p_rect; + emit_changed(); +} + +Rect2 NavigationPolygon::get_baking_rect() const { + return baking_rect; +} + +void NavigationPolygon::set_baking_rect_offset(const Vector2 &p_rect_offset) { + baking_rect_offset = p_rect_offset; + emit_changed(); +} + +Vector2 NavigationPolygon::get_baking_rect_offset() const { + return baking_rect_offset; +} + void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices); ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices); @@ -440,6 +467,9 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationPolygon::set_cell_size); ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationPolygon::get_cell_size); + ClassDB::bind_method(D_METHOD("set_border_size", "border_size"), &NavigationPolygon::set_border_size); + ClassDB::bind_method(D_METHOD("get_border_size"), &NavigationPolygon::get_border_size); + ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationPolygon::set_parsed_geometry_type); ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationPolygon::get_parsed_geometry_type); @@ -458,6 +488,11 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_agent_radius", "agent_radius"), &NavigationPolygon::set_agent_radius); ClassDB::bind_method(D_METHOD("get_agent_radius"), &NavigationPolygon::get_agent_radius); + ClassDB::bind_method(D_METHOD("set_baking_rect", "rect"), &NavigationPolygon::set_baking_rect); + ClassDB::bind_method(D_METHOD("get_baking_rect"), &NavigationPolygon::get_baking_rect); + ClassDB::bind_method(D_METHOD("set_baking_rect_offset", "rect_offset"), &NavigationPolygon::set_baking_rect_offset); + ClassDB::bind_method(D_METHOD("get_baking_rect_offset"), &NavigationPolygon::get_baking_rect_offset); + ClassDB::bind_method(D_METHOD("clear"), &NavigationPolygon::clear); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); @@ -473,8 +508,12 @@ void NavigationPolygon::_bind_methods() { ADD_PROPERTY_DEFAULT("source_geometry_group_name", StringName("navigation_polygon_source_geometry_group")); ADD_GROUP("Cells", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "1.0,50.0,1.0,or_greater,suffix:px"), "set_cell_size", "get_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "border_size", PROPERTY_HINT_RANGE, "0.0,500.0,1.0,or_greater,suffix:px"), "set_border_size", "get_border_size"); ADD_GROUP("Agents", "agent_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:px"), "set_agent_radius", "get_agent_radius"); + ADD_GROUP("Filters", ""); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "baking_rect"), "set_baking_rect", "get_baking_rect"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "baking_rect_offset"), "set_baking_rect_offset", "get_baking_rect_offset"); BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES); BIND_ENUM_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS); diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h index e589ad6dce2c..cfd9b497e089 100644 --- a/scene/resources/navigation_polygon.h +++ b/scene/resources/navigation_polygon.h @@ -53,6 +53,10 @@ class NavigationPolygon : public Resource { Ref navigation_mesh; real_t cell_size = 1.0f; // Must match ProjectSettings default 2D cell_size. + real_t border_size = 0.0f; + + Rect2 baking_rect; + Vector2 baking_rect_offset; protected: static void _bind_methods(); @@ -138,6 +142,15 @@ public: void set_cell_size(real_t p_cell_size); real_t get_cell_size() const; + void set_border_size(real_t p_value); + real_t get_border_size() const; + + void set_baking_rect(const Rect2 &p_rect); + Rect2 get_baking_rect() const; + + void set_baking_rect_offset(const Vector2 &p_rect_offset); + Vector2 get_baking_rect_offset() const; + void clear(); NavigationPolygon();