diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml index 31ce1dba4a3..731245fb488 100644 --- a/doc/classes/NavigationRegion2D.xml +++ b/doc/classes/NavigationRegion2D.xml @@ -23,6 +23,12 @@ Bakes the [NavigationPolygon]. If [param on_thread] is set to [code]true[/code] (default), the baking is done on a separate thread. + + + + Returns the axis-aligned rectangle for the region's transformed navigation mesh. + + diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml index ad31fd06324..019afce30bd 100644 --- a/doc/classes/NavigationRegion3D.xml +++ b/doc/classes/NavigationRegion3D.xml @@ -23,6 +23,12 @@ Bakes the [NavigationMesh]. If [param on_thread] is set to [code]true[/code] (default), the baking is done on a separate thread. Baking on separate thread is useful because navigation baking is not a cheap operation. When it is completed, it automatically sets the new [NavigationMesh]. Please note that baking on separate thread may be very slow if geometry is parsed from meshes as async access to each mesh involves heavy synchronization. Also, please note that baking on a separate thread is automatically disabled on operating systems that cannot use threads (such as Web with threads disabled). + + + + Returns the axis-aligned bounding box for the region's transformed navigation mesh. + + diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index 41ef298bc3b..95db5591d05 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -784,6 +784,13 @@ Creates a new region. + + + + + Returns the axis-aligned rectangle for the [param region]'s transformed navigation mesh. + + diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 6f0c68740a5..64da1cdade7 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -925,6 +925,13 @@ Creates a new region. + + + + + Returns the axis-aligned bounding box for the [param region]'s transformed navigation mesh. + + diff --git a/modules/navigation/2d/godot_navigation_server_2d.cpp b/modules/navigation/2d/godot_navigation_server_2d.cpp index f6876b31e2a..89e4de3b022 100644 --- a/modules/navigation/2d/godot_navigation_server_2d.cpp +++ b/modules/navigation/2d/godot_navigation_server_2d.cpp @@ -158,6 +158,13 @@ static Ref poly_to_mesh(Ref d) { } } +static Rect2 aabb_to_rect2(AABB aabb) { + Rect2 rect2; + rect2.position = Vector2(aabb.position.x, aabb.position.z); + rect2.size = Vector2(aabb.size.x, aabb.size.z); + return rect2; +} + void GodotNavigationServer2D::init() { #ifdef CLIPPER2_ENABLED navmesh_generator_2d = memnew(NavMeshGenerator2D); @@ -332,6 +339,11 @@ Vector2 GodotNavigationServer2D::region_get_random_point(RID p_region, uint32_t return v3_to_v2(result); } +Rect2 GodotNavigationServer2D::region_get_bounds(RID p_region) const { + AABB bounds = NavigationServer3D::get_singleton()->region_get_bounds(p_region); + return aabb_to_rect2(bounds); +} + RID FORWARD_0(link_create); void FORWARD_2(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid); diff --git a/modules/navigation/2d/godot_navigation_server_2d.h b/modules/navigation/2d/godot_navigation_server_2d.h index f4a5023a0df..361b812bdf3 100644 --- a/modules/navigation/2d/godot_navigation_server_2d.h +++ b/modules/navigation/2d/godot_navigation_server_2d.h @@ -105,6 +105,7 @@ public: virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; virtual Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const override; virtual Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override; + virtual Rect2 region_get_bounds(RID p_region) const override; virtual RID link_create() override; diff --git a/modules/navigation/3d/godot_navigation_server_3d.cpp b/modules/navigation/3d/godot_navigation_server_3d.cpp index e2b8d0509b7..ef15bcd6a3d 100644 --- a/modules/navigation/3d/godot_navigation_server_3d.cpp +++ b/modules/navigation/3d/godot_navigation_server_3d.cpp @@ -595,6 +595,13 @@ Vector3 GodotNavigationServer3D::region_get_random_point(RID p_region, uint32_t return region->get_random_point(p_navigation_layers, p_uniformly); } +AABB GodotNavigationServer3D::region_get_bounds(RID p_region) const { + const NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL_V(region, AABB()); + + return region->get_bounds(); +} + RID GodotNavigationServer3D::link_create() { MutexLock lock(operations_mutex); diff --git a/modules/navigation/3d/godot_navigation_server_3d.h b/modules/navigation/3d/godot_navigation_server_3d.h index 268dbee8e73..c595fbc02e4 100644 --- a/modules/navigation/3d/godot_navigation_server_3d.h +++ b/modules/navigation/3d/godot_navigation_server_3d.h @@ -187,6 +187,7 @@ public: virtual Vector3 region_get_closest_point(RID p_region, const Vector3 &p_point) const override; virtual Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const override; virtual Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override; + virtual AABB region_get_bounds(RID p_region) const override; virtual RID link_create() override; COMMAND_2(link_set_map, RID, p_link, RID, p_map); diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index e33c7c08f97..365d5ba4f68 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -200,6 +200,9 @@ void NavigationRegion2D::set_navigation_polygon(const Ref &p_ #ifdef DEBUG_ENABLED debug_mesh_dirty = true; #endif // DEBUG_ENABLED + + _update_bounds(); + NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon); if (navigation_polygon.is_valid()) { @@ -341,6 +344,8 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_navigation_polygon_changed"), &NavigationRegion2D::_navigation_polygon_changed); + ClassDB::bind_method(D_METHOD("get_bounds"), &NavigationRegion2D::get_bounds); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_polygon", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_edge_connections"), "set_use_edge_connections", "get_use_edge_connections"); @@ -648,3 +653,26 @@ void NavigationRegion2D::_set_debug_visible(bool p_visible) { } } #endif // DEBUG_ENABLED + +void NavigationRegion2D::_update_bounds() { + if (navigation_polygon.is_null()) { + bounds = Rect2(); + return; + } + + const Vector &vertices = navigation_polygon->get_vertices(); + if (vertices.is_empty()) { + bounds = Rect2(); + return; + } + + const Transform2D gt = is_inside_tree() ? get_global_transform() : get_transform(); + + Rect2 new_bounds; + new_bounds.position = gt.xform(vertices[0]); + + for (const Vector2 &vertex : vertices) { + new_bounds.expand_to(gt.xform(vertex)); + } + bounds = new_bounds; +} diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 761eaef5ce0..9ea87b1d900 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -50,6 +50,8 @@ class NavigationRegion2D : public Node2D { void _navigation_polygon_changed(); + Rect2 bounds; + #ifdef DEBUG_ENABLED private: RID debug_mesh_rid; @@ -113,10 +115,13 @@ public: void _bake_finished(Ref p_navigation_polygon); bool is_baking() const; + Rect2 get_bounds() const { return bounds; } + NavigationRegion2D(); ~NavigationRegion2D(); private: + void _update_bounds(); void _region_enter_navigation_map(); void _region_exit_navigation_map(); void _region_update_transform(); diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index ce8cef56990..34be901eef8 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -193,6 +193,8 @@ void NavigationRegion3D::set_navigation_mesh(const Ref &p_naviga navigation_mesh->connect_changed(callable_mp(this, &NavigationRegion3D::_navigation_mesh_changed)); } + _update_bounds(); + NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, p_navigation_mesh); #ifdef DEBUG_ENABLED @@ -314,6 +316,8 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_baking"), &NavigationRegion3D::is_baking); + ClassDB::bind_method(D_METHOD("get_bounds"), &NavigationRegion3D::get_bounds); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_mesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_edge_connections"), "set_use_edge_connections", "get_use_edge_connections"); @@ -740,3 +744,26 @@ void NavigationRegion3D::_update_debug_edge_connections_mesh() { } } #endif // DEBUG_ENABLED + +void NavigationRegion3D::_update_bounds() { + if (navigation_mesh.is_null()) { + bounds = AABB(); + return; + } + + const Vector &vertices = navigation_mesh->get_vertices(); + if (vertices.is_empty()) { + bounds = AABB(); + return; + } + + const Transform3D gt = is_inside_tree() ? get_global_transform() : get_transform(); + + AABB new_bounds; + new_bounds.position = gt.xform(vertices[0]); + + for (const Vector3 &vertex : vertices) { + new_bounds.expand_to(gt.xform(vertex)); + } + bounds = new_bounds; +} diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 82468627deb..97abe3979ca 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -51,6 +51,8 @@ class NavigationRegion3D : public Node3D { void _navigation_mesh_changed(); + AABB bounds; + #ifdef DEBUG_ENABLED RID debug_instance; RID debug_edge_connections_instance; @@ -110,10 +112,13 @@ public: PackedStringArray get_configuration_warnings() const override; + AABB get_bounds() const { return bounds; } + NavigationRegion3D(); ~NavigationRegion3D(); private: + void _update_bounds(); void _region_enter_navigation_map(); void _region_exit_navigation_map(); void _region_update_transform(); diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index a24a3312684..7994cd1758e 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -91,6 +91,7 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end); ClassDB::bind_method(D_METHOD("region_get_closest_point", "region", "to_point"), &NavigationServer2D::region_get_closest_point); ClassDB::bind_method(D_METHOD("region_get_random_point", "region", "navigation_layers", "uniformly"), &NavigationServer2D::region_get_random_point); + ClassDB::bind_method(D_METHOD("region_get_bounds", "region"), &NavigationServer2D::region_get_bounds); ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create); ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer2D::link_set_map); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 510cf396525..e53d84aef1a 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -154,6 +154,7 @@ public: virtual Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const = 0; virtual Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const = 0; + virtual Rect2 region_get_bounds(RID p_region) const = 0; /// Creates a new link between positions in the nav map. virtual RID link_create() = 0; diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h index dd6e618e0b4..4e16c00e4b9 100644 --- a/servers/navigation_server_2d_dummy.h +++ b/servers/navigation_server_2d_dummy.h @@ -87,6 +87,7 @@ public: Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector2(); } Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const override { return Vector2(); } Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector2(); } + Rect2 region_get_bounds(RID p_region) const override { return Rect2(); } RID link_create() override { return RID(); } void link_set_map(RID p_link, RID p_map) override {} diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 702439e4af6..a34eeb36f9d 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -106,6 +106,7 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("region_get_closest_point", "region", "to_point"), &NavigationServer3D::region_get_closest_point); ClassDB::bind_method(D_METHOD("region_get_closest_point_normal", "region", "to_point"), &NavigationServer3D::region_get_closest_point_normal); ClassDB::bind_method(D_METHOD("region_get_random_point", "region", "navigation_layers", "uniformly"), &NavigationServer3D::region_get_random_point); + ClassDB::bind_method(D_METHOD("region_get_bounds", "region"), &NavigationServer3D::region_get_bounds); ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer3D::link_create); ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer3D::link_set_map); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 5a9896a86a3..e94ca5a415c 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -176,6 +176,8 @@ public: virtual Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const = 0; virtual Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const = 0; + virtual AABB region_get_bounds(RID p_region) const = 0; + /// Creates a new link between positions in the nav map. virtual RID link_create() = 0; diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h index 2ab4c6e6e2c..c3f1420bfac 100644 --- a/servers/navigation_server_3d_dummy.h +++ b/servers/navigation_server_3d_dummy.h @@ -99,6 +99,7 @@ public: Vector3 region_get_closest_point(RID p_region, const Vector3 &p_point) const override { return Vector3(); } Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const override { return Vector3(); } Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector3(); } + AABB region_get_bounds(RID p_region) const override { return AABB(); } RID link_create() override { return RID(); } void link_set_map(RID p_link, RID p_map) override {}