Improve NavigationRegion2D debug performance

Improves NavigationRegion2D debug performance by replacing the canvas polygon and line commands with a static mesh.
This commit is contained in:
smix8 2024-05-25 22:14:27 +02:00
parent 1e6b11dcd4
commit 5f5fe737d2
2 changed files with 160 additions and 24 deletions

View File

@ -162,8 +162,19 @@ void NavigationRegion2D::_notification(int p_what) {
set_physics_process_internal(true); set_physics_process_internal(true);
} break; } break;
case NOTIFICATION_VISIBILITY_CHANGED: {
#ifdef DEBUG_ENABLED
if (debug_instance_rid.is_valid()) {
RS::get_singleton()->canvas_item_set_visible(debug_instance_rid, is_visible_in_tree());
}
#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
_region_exit_navigation_map(); _region_exit_navigation_map();
#ifdef DEBUG_ENABLED
_free_debug();
#endif // DEBUG_ENABLED
} break; } break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@ -189,6 +200,9 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_
} }
navigation_polygon = p_navigation_polygon; navigation_polygon = p_navigation_polygon;
#ifdef DEBUG_ENABLED
debug_mesh_dirty = true;
#endif // DEBUG_ENABLED
NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon); NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon);
if (navigation_polygon.is_valid()) { if (navigation_polygon.is_valid()) {
@ -420,12 +434,42 @@ void NavigationRegion2D::_region_update_transform() {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
void NavigationRegion2D::_update_debug_mesh() { void NavigationRegion2D::_update_debug_mesh() {
Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices(); if (!is_inside_tree()) {
if (navigation_polygon_vertices.size() < 3) { _free_debug();
return; return;
} }
const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); const NavigationServer2D *ns2d = NavigationServer2D::get_singleton();
RenderingServer *rs = RenderingServer::get_singleton();
if (!debug_instance_rid.is_valid()) {
debug_instance_rid = rs->canvas_item_create();
}
if (!debug_mesh_rid.is_valid()) {
debug_mesh_rid = rs->mesh_create();
}
const Transform2D region_gt = get_global_transform();
rs->canvas_item_set_parent(debug_instance_rid, get_world_2d()->get_canvas());
rs->canvas_item_set_transform(debug_instance_rid, region_gt);
if (!debug_mesh_dirty) {
return;
}
rs->mesh_clear(debug_mesh_rid);
debug_mesh_dirty = false;
const Vector<Vector2> &vertices = navigation_polygon->get_vertices();
if (vertices.size() < 3) {
return;
}
int polygon_count = navigation_polygon->get_polygon_count();
if (polygon_count == 0) {
return;
}
bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color(); bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color();
bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines(); bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines();
@ -438,39 +482,109 @@ void NavigationRegion2D::_update_debug_mesh() {
debug_edge_color = ns2d->get_debug_navigation_geometry_edge_disabled_color(); debug_edge_color = ns2d->get_debug_navigation_geometry_edge_disabled_color();
} }
int vertex_count = 0;
int line_count = 0;
for (int i = 0; i < polygon_count; i++) {
const Vector<int> &polygon = navigation_polygon->get_polygon(i);
int polygon_size = polygon.size();
if (polygon_size < 3) {
continue;
}
line_count += polygon_size * 2;
vertex_count += (polygon_size - 2) * 3;
}
Vector<Vector2> face_vertex_array;
face_vertex_array.resize(vertex_count);
Vector<Color> face_color_array;
if (enabled_geometry_face_random_color) {
face_color_array.resize(vertex_count);
}
Vector<Vector2> line_vertex_array;
if (enabled_edge_lines) {
line_vertex_array.resize(line_count);
}
RandomPCG rand; RandomPCG rand;
Color polygon_color = debug_face_color;
for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { int face_vertex_index = 0;
// An array of vertices for this polygon. int line_vertex_index = 0;
Vector<int> polygon = navigation_polygon->get_polygon(i);
Vector<Vector2> debug_polygon_vertices; Vector2 *face_vertex_array_ptrw = face_vertex_array.ptrw();
debug_polygon_vertices.resize(polygon.size()); Color *face_color_array_ptrw = face_color_array.ptrw();
for (int j = 0; j < polygon.size(); j++) { Vector2 *line_vertex_array_ptrw = line_vertex_array.ptrw();
ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]]; for (int polygon_index = 0; polygon_index < polygon_count; polygon_index++) {
const Vector<int> &polygon_indices = navigation_polygon->get_polygon(polygon_index);
int polygon_indices_size = polygon_indices.size();
if (polygon_indices_size < 3) {
continue;
} }
// Generate the polygon color, slightly randomly modified from the settings one.
Color random_variation_color = debug_face_color;
if (enabled_geometry_face_random_color) { if (enabled_geometry_face_random_color) {
random_variation_color.set_hsv( // Generate the polygon color, slightly randomly modified from the settings one.
debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, polygon_color.set_hsv(debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_face_color.get_s(), debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
debug_face_color.get_s(), polygon_color.a = debug_face_color.a;
debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
} }
random_variation_color.a = debug_face_color.a;
Vector<Color> debug_face_colors; for (int polygon_indices_index = 0; polygon_indices_index < polygon_indices_size - 2; polygon_indices_index++) {
debug_face_colors.push_back(random_variation_color); face_vertex_array_ptrw[face_vertex_index] = vertices[polygon_indices[0]];
RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), debug_polygon_vertices, debug_face_colors); face_vertex_array_ptrw[face_vertex_index + 1] = vertices[polygon_indices[polygon_indices_index + 1]];
face_vertex_array_ptrw[face_vertex_index + 2] = vertices[polygon_indices[polygon_indices_index + 2]];
if (enabled_geometry_face_random_color) {
face_color_array_ptrw[face_vertex_index] = polygon_color;
face_color_array_ptrw[face_vertex_index + 1] = polygon_color;
face_color_array_ptrw[face_vertex_index + 2] = polygon_color;
}
face_vertex_index += 3;
}
if (enabled_edge_lines) { if (enabled_edge_lines) {
Vector<Color> debug_edge_colors; for (int polygon_indices_index = 0; polygon_indices_index < polygon_indices_size; polygon_indices_index++) {
debug_edge_colors.push_back(debug_edge_color); line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[polygon_indices_index]];
debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline. line_vertex_index += 1;
RS::get_singleton()->canvas_item_add_polyline(get_canvas_item(), debug_polygon_vertices, debug_edge_colors); if (polygon_indices_index + 1 == polygon_indices_size) {
line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[0]];
line_vertex_index += 1;
} else {
line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[polygon_indices_index + 1]];
line_vertex_index += 1;
}
}
} }
} }
if (!enabled_geometry_face_random_color) {
face_color_array.resize(face_vertex_array.size());
face_color_array.fill(debug_face_color);
}
Array face_mesh_array;
face_mesh_array.resize(Mesh::ARRAY_MAX);
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
rs->mesh_add_surface_from_arrays(debug_mesh_rid, RS::PRIMITIVE_TRIANGLES, face_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
if (enabled_edge_lines) {
Vector<Color> line_color_array;
line_color_array.resize(line_vertex_array.size());
line_color_array.fill(debug_edge_color);
Array line_mesh_array;
line_mesh_array.resize(Mesh::ARRAY_MAX);
line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
line_mesh_array[Mesh::ARRAY_COLOR] = line_color_array;
rs->mesh_add_surface_from_arrays(debug_mesh_rid, RS::PRIMITIVE_LINES, line_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
}
rs->canvas_item_add_mesh(debug_instance_rid, debug_mesh_rid, Transform2D());
rs->canvas_item_set_visible(debug_instance_rid, is_visible_in_tree());
} }
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
@ -512,3 +626,19 @@ void NavigationRegion2D::_update_debug_baking_rect() {
} }
} }
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
#ifdef DEBUG_ENABLED
void NavigationRegion2D::_free_debug() {
RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs);
if (debug_instance_rid.is_valid()) {
rs->canvas_item_clear(debug_instance_rid);
rs->free(debug_instance_rid);
debug_instance_rid = RID();
}
if (debug_mesh_rid.is_valid()) {
rs->free(debug_mesh_rid);
debug_mesh_rid = RID();
}
}
#endif // DEBUG_ENABLED

View File

@ -52,6 +52,12 @@ class NavigationRegion2D : public Node2D {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
private: private:
RID debug_mesh_rid;
RID debug_instance_rid;
bool debug_mesh_dirty = true;
void _free_debug();
void _update_debug_mesh(); void _update_debug_mesh();
void _update_debug_edge_connections_mesh(); void _update_debug_edge_connections_mesh();
void _update_debug_baking_rect(); void _update_debug_baking_rect();