Merge pull request #101505 from smix8/region_bounds

Add functions to get axis-aligned bounds of navigation regions
This commit is contained in:
Rémi Verschelde 2025-01-14 15:06:06 +01:00
commit a69ccee151
18 changed files with 119 additions and 0 deletions

View File

@ -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.
</description>
</method>
<method name="get_bounds" qualifiers="const">
<return type="Rect2" />
<description>
Returns the axis-aligned rectangle for the region's transformed navigation mesh.
</description>
</method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />

View File

@ -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).
</description>
</method>
<method name="get_bounds" qualifiers="const">
<return type="AABB" />
<description>
Returns the axis-aligned bounding box for the region's transformed navigation mesh.
</description>
</method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />

View File

@ -784,6 +784,13 @@
Creates a new region.
</description>
</method>
<method name="region_get_bounds" qualifiers="const">
<return type="Rect2" />
<param index="0" name="region" type="RID" />
<description>
Returns the axis-aligned rectangle for the [param region]'s transformed navigation mesh.
</description>
</method>
<method name="region_get_closest_point" qualifiers="const">
<return type="Vector2" />
<param index="0" name="region" type="RID" />

View File

@ -925,6 +925,13 @@
Creates a new region.
</description>
</method>
<method name="region_get_bounds" qualifiers="const">
<return type="AABB" />
<param index="0" name="region" type="RID" />
<description>
Returns the axis-aligned bounding box for the [param region]'s transformed navigation mesh.
</description>
</method>
<method name="region_get_closest_point" qualifiers="const">
<return type="Vector3" />
<param index="0" name="region" type="RID" />

View File

@ -158,6 +158,13 @@ static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> 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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -200,6 +200,9 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &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<Vector2> &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;
}

View File

@ -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<NavigationPolygon> 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();

View File

@ -193,6 +193,8 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &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<Vector3> &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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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 {}

View File

@ -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);

View File

@ -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;

View File

@ -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 {}