Add more detailed Navigation Debug Visualization

- Adds more customization options to ProjectSettings.
- Displays navregion edge connections and navigation polygon edges in editor and at runtime.
- Majority of debug code moved from SceneTree to NavigationServer.
- Removes the irritating debug MeshInstance child node from NavigationRegion3D and replaces it with direct RenderingServer API.
This commit is contained in:
smix8 2022-07-01 18:58:03 +02:00
parent afdae67cc3
commit c394ea518e
12 changed files with 915 additions and 62 deletions

View file

@ -415,5 +415,10 @@
Emitted when a navigation map is updated, when a region moves or is modified. Emitted when a navigation map is updated, when a region moves or is modified.
</description> </description>
</signal> </signal>
<signal name="navigation_debug_changed">
<description>
Emitted when navigation debug settings are changed. Only available in debug builds.
</description>
</signal>
</signals> </signals>
</class> </class>

View file

@ -491,9 +491,39 @@
<member name="debug/shapes/navigation/disabled_geometry_color" type="Color" setter="" getter="" default="Color(1, 0.7, 0.1, 0.4)"> <member name="debug/shapes/navigation/disabled_geometry_color" type="Color" setter="" getter="" default="Color(1, 0.7, 0.1, 0.4)">
Color of the disabled navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. Color of the disabled navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
</member> </member>
<member name="debug/shapes/navigation/edge_connection_color" type="Color" setter="" getter="" default="Color(1, 0, 1, 1)">
Color to display edge connections between navigation regions, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_edge_connections" type="bool" setter="" getter="" default="true">
If enabled, displays edge connections between navigation regions when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_edge_connections_xray" type="bool" setter="" getter="" default="true">
If enabled, displays edge connections between navigation regions through geometry when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_edge_lines" type="bool" setter="" getter="" default="true">
If enabled, displays navigation mesh polygon edges when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_edge_lines_xray" type="bool" setter="" getter="" default="true">
If enabled, displays navigation mesh polygon edges through geometry when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_geometry_face_random_color" type="bool" setter="" getter="" default="true">
If enabled, colorizes each navigation mesh polygon face with a random color when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)"> <member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
</member> </member>
<member name="debug/shapes/navigation/geometry_edge_color" type="Color" setter="" getter="" default="Color(0.5, 1, 1, 1)">
Color to display enabled navigation mesh polygon edges, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/geometry_edge_disabled_color" type="Color" setter="" getter="" default="Color(0.5, 0.5, 0.5, 1)">
Color to display disabled navigation mesh polygon edges, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/geometry_face_color" type="Color" setter="" getter="" default="Color(0.5, 1, 1, 0.4)">
Color to display enabled navigation mesh polygon faces, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/geometry_face_disabled_color" type="Color" setter="" getter="" default="Color(0.5, 0.5, 0.5, 0.4)">
Color to display disabled navigation mesh polygon faces, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/paths/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)"> <member name="debug/shapes/paths/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu. Color of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu.
</member> </member>

View file

@ -553,6 +553,19 @@ void EditorNode::_update_from_settings() {
tree->set_debug_collision_contact_color(GLOBAL_GET("debug/shapes/collision/contact_color")); tree->set_debug_collision_contact_color(GLOBAL_GET("debug/shapes/collision/contact_color"));
tree->set_debug_navigation_color(GLOBAL_GET("debug/shapes/navigation/geometry_color")); tree->set_debug_navigation_color(GLOBAL_GET("debug/shapes/navigation/geometry_color"));
tree->set_debug_navigation_disabled_color(GLOBAL_GET("debug/shapes/navigation/disabled_geometry_color")); tree->set_debug_navigation_disabled_color(GLOBAL_GET("debug/shapes/navigation/disabled_geometry_color"));
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->set_debug_navigation_edge_connection_color(GLOBAL_GET("debug/shapes/navigation/edge_connection_color"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_geometry_edge_color(GLOBAL_GET("debug/shapes/navigation/geometry_edge_color"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_geometry_face_color(GLOBAL_GET("debug/shapes/navigation/geometry_face_color"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_geometry_edge_disabled_color(GLOBAL_GET("debug/shapes/navigation/geometry_edge_disabled_color"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_geometry_face_disabled_color(GLOBAL_GET("debug/shapes/navigation/geometry_face_disabled_color"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_edge_connections(GLOBAL_GET("debug/shapes/navigation/enable_edge_connections"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_edge_connections_xray(GLOBAL_GET("debug/shapes/navigation/enable_edge_connections_xray"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_edge_lines(GLOBAL_GET("debug/shapes/navigation/enable_edge_lines"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_edge_lines_xray(GLOBAL_GET("debug/shapes/navigation/enable_edge_lines_xray"));
NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_geometry_face_random_color(GLOBAL_GET("debug/shapes/navigation/enable_geometry_face_random_color"));
#endif // DEBUG_ENABLED
} }
void EditorNode::_select_default_main_screen_plugin() { void EditorNode::_select_default_main_screen_plugin() {
@ -5910,7 +5923,11 @@ EditorNode::EditorNode() {
RenderingServer::get_singleton()->set_debug_generate_wireframes(true); RenderingServer::get_singleton()->set_debug_generate_wireframes(true);
// No navigation server by default if in editor. // No navigation server by default if in editor.
NavigationServer3D::get_singleton()->set_active(false); if (NavigationServer3D::get_singleton()->get_debug_enabled()) {
NavigationServer3D::get_singleton()->set_active(true);
} else {
NavigationServer3D::get_singleton()->set_active(false);
}
// No physics by default if in editor. // No physics by default if in editor.
PhysicsServer3D::get_singleton()->set_active(false); PhysicsServer3D::get_singleton()->set_active(false);

View file

@ -74,6 +74,7 @@
#include "scene/resources/sphere_shape_3d.h" #include "scene/resources/sphere_shape_3d.h"
#include "scene/resources/surface_tool.h" #include "scene/resources/surface_tool.h"
#include "scene/resources/world_boundary_shape_3d.h" #include "scene/resources/world_boundary_shape_3d.h"
#include "servers/navigation_server_3d.h"
#define HANDLE_HALF_SIZE 9.5 #define HANDLE_HALF_SIZE 9.5
@ -4798,10 +4799,6 @@ void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
//// ////
NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() { NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() {
create_material("navigation_edge_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)));
create_material("navigation_edge_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)));
create_material("navigation_solid_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)));
create_material("navigation_solid_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4)));
} }
bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@ -4817,24 +4814,19 @@ int NavigationRegion3DGizmoPlugin::get_priority() const {
} }
void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
NavigationRegion3D *navmesh = Object::cast_to<NavigationRegion3D>(p_gizmo->get_spatial_node()); NavigationRegion3D *navigationregion = Object::cast_to<NavigationRegion3D>(p_gizmo->get_spatial_node());
Ref<Material> edge_material = get_material("navigation_edge_material", p_gizmo);
Ref<Material> edge_material_disabled = get_material("navigation_edge_material_disabled", p_gizmo);
Ref<Material> solid_material = get_material("navigation_solid_material", p_gizmo);
Ref<Material> solid_material_disabled = get_material("navigation_solid_material_disabled", p_gizmo);
p_gizmo->clear(); p_gizmo->clear();
Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh(); Ref<NavigationMesh> navigationmesh = navigationregion->get_navigation_mesh();
if (navmeshie.is_null()) { if (navigationmesh.is_null()) {
return; return;
} }
Vector<Vector3> vertices = navmeshie->get_vertices(); Vector<Vector3> vertices = navigationmesh->get_vertices();
const Vector3 *vr = vertices.ptr(); const Vector3 *vr = vertices.ptr();
List<Face3> faces; List<Face3> faces;
for (int i = 0; i < navmeshie->get_polygon_count(); i++) { for (int i = 0; i < navigationmesh->get_polygon_count(); i++) {
Vector<int> p = navmeshie->get_polygon(i); Vector<int> p = navigationmesh->get_polygon(i);
for (int j = 2; j < p.size(); j++) { for (int j = 2; j < p.size(); j++) {
Face3 f; Face3 f;
@ -4891,17 +4883,90 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<TriangleMesh> tmesh = memnew(TriangleMesh); Ref<TriangleMesh> tmesh = memnew(TriangleMesh);
tmesh->create(tmeshfaces); tmesh->create(tmeshfaces);
if (lines.size()) {
p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled);
}
p_gizmo->add_collision_triangles(tmesh); p_gizmo->add_collision_triangles(tmesh);
Ref<ArrayMesh> m = memnew(ArrayMesh);
Array a; Ref<ArrayMesh> debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
a.resize(Mesh::ARRAY_MAX); int polygon_count = navigationmesh->get_polygon_count();
a[0] = tmeshfaces;
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a); // build geometry face surface
m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled); Vector<Vector3> face_vertex_array;
p_gizmo->add_mesh(m); face_vertex_array.resize(polygon_count * 3);
for (int i = 0; i < polygon_count; i++) {
Vector<int> polygon = navigationmesh->get_polygon(i);
face_vertex_array.push_back(vertices[polygon[0]]);
face_vertex_array.push_back(vertices[polygon[1]]);
face_vertex_array.push_back(vertices[polygon[2]]);
}
Array face_mesh_array;
face_mesh_array.resize(Mesh::ARRAY_MAX);
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
// if enabled add vertex colors to colorize each face individually
bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
if (enabled_geometry_face_random_color) {
Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
Color polygon_color = debug_navigation_geometry_face_color;
Vector<Color> face_color_array;
face_color_array.resize(polygon_count * 3);
for (int i = 0; i < polygon_count; i++) {
polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
Vector<int> polygon = navigationmesh->get_polygon(i);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
}
face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
}
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
debug_mesh->surface_set_material(0, debug_geometry_face_material);
// if enabled build geometry edge line surface
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
if (enabled_edge_lines) {
Vector<Vector3> line_vertex_array;
line_vertex_array.resize(polygon_count * 6);
for (int i = 0; i < polygon_count; i++) {
Vector<int> polygon = navigationmesh->get_polygon(i);
line_vertex_array.push_back(vertices[polygon[0]]);
line_vertex_array.push_back(vertices[polygon[1]]);
line_vertex_array.push_back(vertices[polygon[1]]);
line_vertex_array.push_back(vertices[polygon[2]]);
line_vertex_array.push_back(vertices[polygon[2]]);
line_vertex_array.push_back(vertices[polygon[0]]);
}
Array line_mesh_array;
line_mesh_array.resize(Mesh::ARRAY_MAX);
line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
debug_mesh->surface_set_material(1, debug_geometry_edge_material);
}
if (!navigationregion->is_enabled()) {
if (debug_mesh.is_valid()) {
if (debug_mesh->get_surface_count() > 0) {
debug_mesh->surface_set_material(0, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material());
}
if (debug_mesh->get_surface_count() > 1) {
debug_mesh->surface_set_material(1, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material());
}
}
}
p_gizmo->add_mesh(debug_mesh);
p_gizmo->add_collision_segments(lines); p_gizmo->add_collision_segments(lines);
} }

View file

@ -2389,6 +2389,8 @@ bool Main::start() {
} }
if (debug_navigation) { if (debug_navigation) {
sml->set_debug_navigation_hint(true); sml->set_debug_navigation_hint(true);
NavigationServer3D::get_singleton()->set_active(true);
NavigationServer3D::get_singleton_mut()->set_debug_enabled(true);
} }
#endif #endif

View file

@ -35,6 +35,7 @@
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "scene/resources/world_2d.h" #include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h" #include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
#include "thirdparty/misc/polypartition.h" #include "thirdparty/misc/polypartition.h"
@ -371,9 +372,11 @@ void NavigationRegion2D::set_enabled(bool p_enabled) {
NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
} }
if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) { #ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) {
update(); update();
} }
#endif // DEBUG_ENABLED
} }
bool NavigationRegion2D::is_enabled() const { bool NavigationRegion2D::is_enabled() const {
@ -462,7 +465,8 @@ void NavigationRegion2D::_notification(int p_what) {
} break; } break;
case NOTIFICATION_DRAW: { case NOTIFICATION_DRAW: {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { #ifdef DEBUG_ENABLED
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navpoly.is_valid()) {
Vector<Vector2> verts = navpoly->get_vertices(); Vector<Vector2> verts = navpoly->get_vertices();
if (verts.size() < 3) { if (verts.size() < 3) {
return; return;
@ -470,11 +474,11 @@ void NavigationRegion2D::_notification(int p_what) {
Color color; Color color;
if (enabled) { if (enabled) {
color = get_tree()->get_debug_navigation_color(); color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
} else { } else {
color = get_tree()->get_debug_navigation_disabled_color(); color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color();
} }
Color doors_color = color.lightened(0.2); Color doors_color = NavigationServer3D::get_singleton()->get_debug_navigation_edge_connection_color();
RandomPCG rand; RandomPCG rand;
@ -516,6 +520,7 @@ void NavigationRegion2D::_notification(int p_what) {
draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color); draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color);
} }
} }
#endif // DEBUG_ENABLED
} break; } break;
} }
} }
@ -552,10 +557,13 @@ void NavigationRegion2D::_navpoly_changed() {
NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
} }
} }
void NavigationRegion2D::_map_changed(RID p_map) { void NavigationRegion2D::_map_changed(RID p_map) {
if (enabled && get_world_2d()->get_navigation_map() == p_map) { #ifdef DEBUG_ENABLED
if (is_inside_tree() && get_world_2d()->get_navigation_map() == p_map) {
update(); update();
} }
#endif // DEBUG_ENABLED
} }
TypedArray<String> NavigationRegion2D::get_configuration_warnings() const { TypedArray<String> NavigationRegion2D::get_configuration_warnings() const {
@ -605,8 +613,18 @@ NavigationRegion2D::NavigationRegion2D() {
region = NavigationServer2D::get_singleton()->region_create(); region = NavigationServer2D::get_singleton()->region_create();
NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
#endif // DEBUG_ENABLED
} }
NavigationRegion2D::~NavigationRegion2D() { NavigationRegion2D::~NavigationRegion2D() {
NavigationServer2D::get_singleton()->free(region); NavigationServer2D::get_singleton()->free(region);
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
#endif // DEBUG_ENABLED
} }

View file

@ -49,14 +49,29 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
} }
if (debug_view) { #ifdef DEBUG_ENABLED
MeshInstance3D *dm = Object::cast_to<MeshInstance3D>(debug_view); if (debug_instance.is_valid()) {
if (is_enabled()) { if (!is_enabled()) {
dm->set_material_override(get_tree()->get_debug_navigation_material()); if (debug_mesh.is_valid()) {
if (debug_mesh->get_surface_count() > 0) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()->get_rid());
}
if (debug_mesh->get_surface_count() > 1) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()->get_rid());
}
}
} else { } else {
dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); if (debug_mesh.is_valid()) {
if (debug_mesh->get_surface_count() > 0) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, RID());
}
if (debug_mesh->get_surface_count() > 1) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, RID());
}
}
} }
} }
#endif // DEBUG_ENABLED
update_gizmos(); update_gizmos();
} }
@ -124,30 +139,36 @@ void NavigationRegion3D::_notification(int p_what) {
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
} }
if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { #ifdef DEBUG_ENABLED
MeshInstance3D *dm = memnew(MeshInstance3D); if (NavigationServer3D::get_singleton()->get_debug_enabled()) {
dm->set_mesh(navmesh->get_debug_mesh()); _update_debug_mesh();
if (is_enabled()) {
dm->set_material_override(get_tree()->get_debug_navigation_material());
} else {
dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
}
add_child(dm);
debug_view = dm;
} }
#endif // DEBUG_ENABLED
} break; } break;
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform()); NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform());
#ifdef DEBUG_ENABLED
if (is_inside_tree() && debug_instance.is_valid()) {
RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
}
#endif // DEBUG_ENABLED
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
NavigationServer3D::get_singleton()->region_set_map(region, RID()); NavigationServer3D::get_singleton()->region_set_map(region, RID());
if (debug_view) { #ifdef DEBUG_ENABLED
debug_view->queue_delete(); if (debug_instance.is_valid()) {
debug_view = nullptr; RS::get_singleton()->instance_set_visible(debug_instance, false);
} }
if (debug_edge_connections_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
#endif // DEBUG_ENABLED
} break; } break;
} }
} }
@ -169,20 +190,21 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh); NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
if (debug_view == nullptr && is_inside_tree() && navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { #ifdef DEBUG_ENABLED
MeshInstance3D *dm = memnew(MeshInstance3D); if (is_inside_tree() && NavigationServer3D::get_singleton()->get_debug_enabled()) {
dm->set_mesh(navmesh->get_debug_mesh()); if (navmesh.is_valid()) {
if (is_enabled()) { _update_debug_mesh();
dm->set_material_override(get_tree()->get_debug_navigation_material()); _update_debug_edge_connections_mesh();
} else { } else {
dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
}
if (debug_edge_connections_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
} }
add_child(dm);
debug_view = dm;
}
if (debug_view && navmesh.is_valid()) {
Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh());
} }
#endif // DEBUG_ENABLED
emit_signal(SNAME("navigation_mesh_changed")); emit_signal(SNAME("navigation_mesh_changed"));
@ -287,13 +309,31 @@ void NavigationRegion3D::_bind_methods() {
void NavigationRegion3D::_navigation_changed() { void NavigationRegion3D::_navigation_changed() {
update_gizmos(); update_gizmos();
update_configuration_warnings(); update_configuration_warnings();
#ifdef DEBUG_ENABLED
_update_debug_edge_connections_mesh();
#endif // DEBUG_ENABLED
} }
#ifdef DEBUG_ENABLED
void NavigationRegion3D::_navigation_map_changed(RID p_map) {
if (is_inside_tree() && p_map == get_world_3d()->get_navigation_map()) {
_update_debug_edge_connections_mesh();
}
}
#endif // DEBUG_ENABLED
NavigationRegion3D::NavigationRegion3D() { NavigationRegion3D::NavigationRegion3D() {
set_notify_transform(true); set_notify_transform(true);
region = NavigationServer3D::get_singleton()->region_create(); region = NavigationServer3D::get_singleton()->region_create();
NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
#endif // DEBUG_ENABLED
} }
NavigationRegion3D::~NavigationRegion3D() { NavigationRegion3D::~NavigationRegion3D() {
@ -301,4 +341,245 @@ NavigationRegion3D::~NavigationRegion3D() {
navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
} }
NavigationServer3D::get_singleton()->free(region); NavigationServer3D::get_singleton()->free(region);
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_mesh));
NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion3D::_update_debug_edge_connections_mesh));
if (debug_instance.is_valid()) {
RenderingServer::get_singleton()->free(debug_instance);
}
if (debug_mesh.is_valid()) {
RenderingServer::get_singleton()->free(debug_mesh->get_rid());
}
if (debug_edge_connections_instance.is_valid()) {
RenderingServer::get_singleton()->free(debug_edge_connections_instance);
}
if (debug_edge_connections_mesh.is_valid()) {
RenderingServer::get_singleton()->free(debug_edge_connections_mesh->get_rid());
}
#endif // DEBUG_ENABLED
} }
#ifdef DEBUG_ENABLED
void NavigationRegion3D::_update_debug_mesh() {
if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
}
return;
}
if (!navmesh.is_valid()) {
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
}
return;
}
if (!debug_instance.is_valid()) {
debug_instance = RenderingServer::get_singleton()->instance_create();
}
if (!debug_mesh.is_valid()) {
debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
}
debug_mesh->clear_surfaces();
bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
Vector<Vector3> vertices = navmesh->get_vertices();
if (vertices.size() == 0) {
return;
}
int polygon_count = navmesh->get_polygon_count();
if (polygon_count == 0) {
return;
}
Vector<Vector3> face_vertex_array;
face_vertex_array.resize(polygon_count * 3);
Vector<Color> face_color_array;
if (enabled_geometry_face_random_color) {
face_color_array.resize(polygon_count * 3);
}
Vector<Vector3> line_vertex_array;
if (enabled_edge_lines) {
line_vertex_array.resize(polygon_count * 6);
}
Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
Ref<StandardMaterial3D> face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
Ref<StandardMaterial3D> line_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
Color polygon_color = debug_navigation_geometry_face_color;
for (int i = 0; i < polygon_count; i++) {
if (enabled_geometry_face_random_color) {
polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
}
Vector<int> polygon = navmesh->get_polygon(i);
face_vertex_array.push_back(vertices[polygon[0]]);
face_vertex_array.push_back(vertices[polygon[1]]);
face_vertex_array.push_back(vertices[polygon[2]]);
if (enabled_geometry_face_random_color) {
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
}
if (enabled_edge_lines) {
line_vertex_array.push_back(vertices[polygon[0]]);
line_vertex_array.push_back(vertices[polygon[1]]);
line_vertex_array.push_back(vertices[polygon[1]]);
line_vertex_array.push_back(vertices[polygon[2]]);
line_vertex_array.push_back(vertices[polygon[2]]);
line_vertex_array.push_back(vertices[polygon[0]]);
}
}
Array face_mesh_array;
face_mesh_array.resize(Mesh::ARRAY_MAX);
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
if (enabled_geometry_face_random_color) {
face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
}
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
debug_mesh->surface_set_material(0, face_material);
if (enabled_edge_lines) {
Array line_mesh_array;
line_mesh_array.resize(Mesh::ARRAY_MAX);
line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
debug_mesh->surface_set_material(1, line_material);
}
RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree());
}
if (!is_enabled()) {
if (debug_mesh.is_valid()) {
if (debug_mesh->get_surface_count() > 0) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material()->get_rid());
}
if (debug_mesh->get_surface_count() > 1) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material()->get_rid());
}
}
} else {
if (debug_mesh.is_valid()) {
if (debug_mesh->get_surface_count() > 0) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, RID());
}
if (debug_mesh->get_surface_count() > 1) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 1, RID());
}
}
}
}
#endif // DEBUG_ENABLED
#ifdef DEBUG_ENABLED
void NavigationRegion3D::_update_debug_edge_connections_mesh() {
if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
if (debug_edge_connections_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
return;
}
if (!is_inside_tree()) {
return;
}
if (!navmesh.is_valid()) {
if (debug_edge_connections_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
return;
}
if (!debug_edge_connections_instance.is_valid()) {
debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
}
if (!debug_edge_connections_mesh.is_valid()) {
debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
}
debug_edge_connections_mesh->clear_surfaces();
float edge_connection_margin = NavigationServer3D::get_singleton()->map_get_edge_connection_margin(get_world_3d()->get_navigation_map());
float half_edge_connection_margin = edge_connection_margin * 0.5;
int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(region);
if (connections_count == 0) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
return;
}
Vector<Vector3> vertex_array;
for (int i = 0; i < connections_count; i++) {
Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(region, i);
Vector3 connection_pathway_end = NavigationServer3D::get_singleton()->region_get_connection_pathway_end(region, i);
Vector3 direction_start_end = connection_pathway_start.direction_to(connection_pathway_end);
Vector3 direction_end_start = connection_pathway_end.direction_to(connection_pathway_start);
Vector3 start_right_dir = direction_start_end.cross(Vector3(0, 1, 0));
Vector3 start_left_dir = -start_right_dir;
Vector3 end_right_dir = direction_end_start.cross(Vector3(0, 1, 0));
Vector3 end_left_dir = -end_right_dir;
Vector3 left_start_pos = connection_pathway_start + (start_left_dir * half_edge_connection_margin);
Vector3 right_start_pos = connection_pathway_start + (start_right_dir * half_edge_connection_margin);
Vector3 left_end_pos = connection_pathway_end + (end_right_dir * half_edge_connection_margin);
Vector3 right_end_pos = connection_pathway_end + (end_left_dir * half_edge_connection_margin);
vertex_array.push_back(right_end_pos);
vertex_array.push_back(left_start_pos);
vertex_array.push_back(right_start_pos);
vertex_array.push_back(left_end_pos);
vertex_array.push_back(right_end_pos);
vertex_array.push_back(right_start_pos);
}
if (vertex_array.size() == 0) {
return;
}
Ref<StandardMaterial3D> edge_connections_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_edge_connections_material();
Array mesh_array;
mesh_array.resize(Mesh::ARRAY_MAX);
mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
debug_edge_connections_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_array);
debug_edge_connections_mesh->surface_set_material(0, edge_connections_material);
RS::get_singleton()->instance_set_base(debug_edge_connections_instance, debug_edge_connections_mesh->get_rid());
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, is_visible_in_tree());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(debug_edge_connections_instance, get_world_3d()->get_scenario());
}
bool enable_edge_connections = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_connections();
if (!enable_edge_connections) {
RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false);
}
}
#endif // DEBUG_ENABLED

View file

@ -44,11 +44,22 @@ class NavigationRegion3D : public Node3D {
real_t enter_cost = 0.0; real_t enter_cost = 0.0;
real_t travel_cost = 1.0; real_t travel_cost = 1.0;
Node *debug_view = nullptr;
Thread bake_thread; Thread bake_thread;
void _navigation_changed(); void _navigation_changed();
#ifdef DEBUG_ENABLED
RID debug_instance;
RID debug_edge_connections_instance;
Ref<ArrayMesh> debug_mesh;
Ref<ArrayMesh> debug_edge_connections_mesh;
private:
void _update_debug_mesh();
void _update_debug_edge_connections_mesh();
void _navigation_map_changed(RID p_map);
#endif // DEBUG_ENABLED
protected: protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();

View file

@ -30,6 +30,10 @@
#include "navigation_mesh.h" #include "navigation_mesh.h"
#ifdef DEBUG_ENABLED
#include "servers/navigation_server_3d.h"
#endif
void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND(p_mesh.is_null()); ERR_FAIL_COND(p_mesh.is_null());
@ -337,6 +341,7 @@ void NavigationMesh::clear_polygons() {
polygons.clear(); polygons.clear();
} }
#ifndef DISABLE_DEPRECATED
Ref<Mesh> NavigationMesh::get_debug_mesh() { Ref<Mesh> NavigationMesh::get_debug_mesh() {
if (debug_mesh.is_valid()) { if (debug_mesh.is_valid()) {
return debug_mesh; return debug_mesh;
@ -420,6 +425,102 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
return debug_mesh; return debug_mesh;
} }
#endif // DISABLE_DEPRECATED
#ifdef DEBUG_ENABLED
Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
if (debug_mesh.is_valid()) {
// Blocks further updates for now, code below is intended for dynamic updates e.g. when settings change.
return debug_mesh;
}
if (!debug_mesh.is_valid()) {
debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
} else {
debug_mesh->clear_surfaces();
}
if (vertices.size() == 0) {
return debug_mesh;
}
int polygon_count = get_polygon_count();
if (polygon_count < 1) {
// no face, no play
return debug_mesh;
}
// build geometry face surface
Vector<Vector3> face_vertex_array;
face_vertex_array.resize(polygon_count * 3);
for (int i = 0; i < polygon_count; i++) {
Vector<int> polygon = get_polygon(i);
face_vertex_array.push_back(vertices[polygon[0]]);
face_vertex_array.push_back(vertices[polygon[1]]);
face_vertex_array.push_back(vertices[polygon[2]]);
}
Array face_mesh_array;
face_mesh_array.resize(Mesh::ARRAY_MAX);
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
// if enabled add vertex colors to colorize each face individually
bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
if (enabled_geometry_face_random_color) {
Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
Color polygon_color = debug_navigation_geometry_face_color;
Vector<Color> face_color_array;
face_color_array.resize(polygon_count * 3);
for (int i = 0; i < polygon_count; i++) {
polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
Vector<int> polygon = get_polygon(i);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
}
face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
}
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_face_material);
// if enabled build geometry edge line surface
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
if (enabled_edge_lines) {
Vector<Vector3> line_vertex_array;
line_vertex_array.resize(polygon_count * 6);
for (int i = 0; i < polygon_count; i++) {
Vector<int> polygon = get_polygon(i);
line_vertex_array.push_back(vertices[polygon[0]]);
line_vertex_array.push_back(vertices[polygon[1]]);
line_vertex_array.push_back(vertices[polygon[1]]);
line_vertex_array.push_back(vertices[polygon[2]]);
line_vertex_array.push_back(vertices[polygon[2]]);
line_vertex_array.push_back(vertices[polygon[0]]);
}
Array line_mesh_array;
line_mesh_array.resize(Mesh::ARRAY_MAX);
line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_edge_material);
}
return debug_mesh;
}
#endif
void NavigationMesh::_bind_methods() { void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type); ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);

View file

@ -204,7 +204,11 @@ public:
Vector<int> get_polygon(int p_idx); Vector<int> get_polygon(int p_idx);
void clear_polygons(); void clear_polygons();
#ifndef DISABLE_DEPRECATED
Ref<Mesh> get_debug_mesh(); Ref<Mesh> get_debug_mesh();
#endif // DISABLE_DEPRECATED
Ref<ArrayMesh> _get_debug_mesh();
NavigationMesh(); NavigationMesh();
}; };

View file

@ -30,6 +30,10 @@
#include "navigation_server_3d.h" #include "navigation_server_3d.h"
#ifdef DEBUG_ENABLED
#include "core/config/project_settings.h"
#endif // DEBUG_ENABLED
NavigationServer3D *NavigationServer3D::singleton = nullptr; NavigationServer3D *NavigationServer3D::singleton = nullptr;
void NavigationServer3D::_bind_methods() { void NavigationServer3D::_bind_methods() {
@ -92,6 +96,8 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process); ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process);
ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map"))); ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
ADD_SIGNAL(MethodInfo("navigation_debug_changed"));
} }
const NavigationServer3D *NavigationServer3D::get_singleton() { const NavigationServer3D *NavigationServer3D::get_singleton() {
@ -105,6 +111,19 @@ NavigationServer3D *NavigationServer3D::get_singleton_mut() {
NavigationServer3D::NavigationServer3D() { NavigationServer3D::NavigationServer3D() {
ERR_FAIL_COND(singleton != nullptr); ERR_FAIL_COND(singleton != nullptr);
singleton = this; singleton = this;
#ifdef DEBUG_ENABLED
debug_navigation_edge_connection_color = GLOBAL_DEF("debug/shapes/navigation/edge_connection_color", Color(1.0, 0.0, 1.0, 1.0));
debug_navigation_geometry_edge_color = GLOBAL_DEF("debug/shapes/navigation/geometry_edge_color", Color(0.5, 1.0, 1.0, 1.0));
debug_navigation_geometry_face_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_color", Color(0.5, 1.0, 1.0, 0.4));
debug_navigation_geometry_edge_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_edge_disabled_color", Color(0.5, 0.5, 0.5, 1.0));
debug_navigation_geometry_face_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_disabled_color", Color(0.5, 0.5, 0.5, 0.4));
debug_navigation_enable_edge_connections = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections", true);
debug_navigation_enable_edge_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections_xray", true);
debug_navigation_enable_edge_lines = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines", true);
debug_navigation_enable_edge_lines_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines_xray", true);
debug_navigation_enable_geometry_face_random_color = GLOBAL_DEF("debug/shapes/navigation/enable_geometry_face_random_color", true);
#endif // DEBUG_ENABLED
} }
NavigationServer3D::~NavigationServer3D() { NavigationServer3D::~NavigationServer3D() {
@ -121,3 +140,241 @@ NavigationServer3D *NavigationServer3DManager::new_default_server() {
ERR_FAIL_COND_V(create_callback == nullptr, nullptr); ERR_FAIL_COND_V(create_callback == nullptr, nullptr);
return create_callback(); return create_callback();
} }
#ifdef DEBUG_ENABLED
void NavigationServer3D::_emit_navigation_debug_changed_signal() {
if (debug_dirty) {
debug_dirty = false;
emit_signal(SNAME("navigation_debug_changed"));
}
}
#endif // DEBUG_ENABLED
#ifdef DEBUG_ENABLED
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_face_material() {
if (debug_navigation_geometry_face_material.is_valid()) {
return debug_navigation_geometry_face_material;
}
bool enabled_geometry_face_random_color = get_debug_navigation_enable_geometry_face_random_color();
Color debug_navigation_geometry_face_color = get_debug_navigation_geometry_face_color();
Ref<StandardMaterial3D> face_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
face_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
face_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
face_material->set_albedo(debug_navigation_geometry_face_color);
if (enabled_geometry_face_random_color) {
face_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
face_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
}
debug_navigation_geometry_face_material = face_material;
return debug_navigation_geometry_face_material;
}
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_edge_material() {
if (debug_navigation_geometry_edge_material.is_valid()) {
return debug_navigation_geometry_edge_material;
}
bool enabled_edge_lines_xray = get_debug_navigation_enable_edge_lines_xray();
Color debug_navigation_geometry_edge_color = get_debug_navigation_geometry_edge_color();
Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
line_material->set_albedo(debug_navigation_geometry_edge_color);
if (enabled_edge_lines_xray) {
line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
debug_navigation_geometry_edge_material = line_material;
return debug_navigation_geometry_edge_material;
}
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_face_disabled_material() {
if (debug_navigation_geometry_face_disabled_material.is_valid()) {
return debug_navigation_geometry_face_disabled_material;
}
Color debug_navigation_geometry_face_disabled_color = get_debug_navigation_geometry_face_disabled_color();
Ref<StandardMaterial3D> face_disabled_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
face_disabled_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
face_disabled_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
face_disabled_material->set_albedo(debug_navigation_geometry_face_disabled_color);
debug_navigation_geometry_face_disabled_material = face_disabled_material;
return debug_navigation_geometry_face_disabled_material;
}
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_edge_disabled_material() {
if (debug_navigation_geometry_edge_disabled_material.is_valid()) {
return debug_navigation_geometry_edge_disabled_material;
}
bool enabled_edge_lines_xray = get_debug_navigation_enable_edge_lines_xray();
Color debug_navigation_geometry_edge_disabled_color = get_debug_navigation_geometry_edge_disabled_color();
Ref<StandardMaterial3D> line_disabled_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_disabled_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
line_disabled_material->set_albedo(debug_navigation_geometry_edge_disabled_color);
if (enabled_edge_lines_xray) {
line_disabled_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
debug_navigation_geometry_edge_disabled_material = line_disabled_material;
return debug_navigation_geometry_edge_disabled_material;
}
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_edge_connections_material() {
if (debug_navigation_edge_connections_material.is_valid()) {
return debug_navigation_edge_connections_material;
}
bool enabled_edge_connections_xray = get_debug_navigation_enable_edge_connections_xray();
Color debug_navigation_edge_connection_color = get_debug_navigation_edge_connection_color();
Ref<StandardMaterial3D> edge_connections_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
edge_connections_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
edge_connections_material->set_albedo(debug_navigation_edge_connection_color);
if (enabled_edge_connections_xray) {
edge_connections_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
edge_connections_material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MAX - 2);
debug_navigation_edge_connections_material = edge_connections_material;
return debug_navigation_edge_connections_material;
}
void NavigationServer3D::set_debug_navigation_edge_connection_color(const Color &p_color) {
debug_navigation_edge_connection_color = p_color;
if (debug_navigation_edge_connections_material.is_valid()) {
debug_navigation_edge_connections_material->set_albedo(debug_navigation_edge_connection_color);
}
}
Color NavigationServer3D::get_debug_navigation_edge_connection_color() const {
return debug_navigation_edge_connection_color;
}
void NavigationServer3D::set_debug_navigation_geometry_edge_color(const Color &p_color) {
debug_navigation_geometry_edge_color = p_color;
if (debug_navigation_geometry_edge_material.is_valid()) {
debug_navigation_geometry_edge_material->set_albedo(debug_navigation_geometry_edge_color);
}
}
Color NavigationServer3D::get_debug_navigation_geometry_edge_color() const {
return debug_navigation_geometry_edge_color;
}
void NavigationServer3D::set_debug_navigation_geometry_face_color(const Color &p_color) {
debug_navigation_geometry_face_color = p_color;
if (debug_navigation_geometry_face_material.is_valid()) {
debug_navigation_geometry_face_material->set_albedo(debug_navigation_geometry_face_color);
}
}
Color NavigationServer3D::get_debug_navigation_geometry_face_color() const {
return debug_navigation_geometry_face_color;
}
void NavigationServer3D::set_debug_navigation_geometry_edge_disabled_color(const Color &p_color) {
debug_navigation_geometry_edge_disabled_color = p_color;
if (debug_navigation_geometry_edge_disabled_material.is_valid()) {
debug_navigation_geometry_edge_disabled_material->set_albedo(debug_navigation_geometry_edge_disabled_color);
}
}
Color NavigationServer3D::get_debug_navigation_geometry_edge_disabled_color() const {
return debug_navigation_geometry_edge_disabled_color;
}
void NavigationServer3D::set_debug_navigation_geometry_face_disabled_color(const Color &p_color) {
debug_navigation_geometry_face_disabled_color = p_color;
if (debug_navigation_geometry_face_disabled_material.is_valid()) {
debug_navigation_geometry_face_disabled_material->set_albedo(debug_navigation_geometry_face_disabled_color);
}
}
Color NavigationServer3D::get_debug_navigation_geometry_face_disabled_color() const {
return debug_navigation_geometry_face_disabled_color;
}
void NavigationServer3D::set_debug_navigation_enable_edge_connections(const bool p_value) {
debug_navigation_enable_edge_connections = p_value;
debug_dirty = true;
call_deferred("_emit_navigation_debug_changed_signal");
}
bool NavigationServer3D::get_debug_navigation_enable_edge_connections() const {
return debug_navigation_enable_edge_connections;
}
void NavigationServer3D::set_debug_navigation_enable_edge_connections_xray(const bool p_value) {
debug_navigation_enable_edge_connections_xray = p_value;
if (debug_navigation_edge_connections_material.is_valid()) {
debug_navigation_edge_connections_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, debug_navigation_enable_edge_connections_xray);
}
}
bool NavigationServer3D::get_debug_navigation_enable_edge_connections_xray() const {
return debug_navigation_enable_edge_connections_xray;
}
void NavigationServer3D::set_debug_navigation_enable_edge_lines(const bool p_value) {
debug_navigation_enable_edge_lines = p_value;
debug_dirty = true;
call_deferred("_emit_navigation_debug_changed_signal");
}
bool NavigationServer3D::get_debug_navigation_enable_edge_lines() const {
return debug_navigation_enable_edge_lines;
}
void NavigationServer3D::set_debug_navigation_enable_edge_lines_xray(const bool p_value) {
debug_navigation_enable_edge_lines_xray = p_value;
if (debug_navigation_geometry_edge_material.is_valid()) {
debug_navigation_geometry_edge_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, debug_navigation_enable_edge_lines_xray);
}
}
bool NavigationServer3D::get_debug_navigation_enable_edge_lines_xray() const {
return debug_navigation_enable_edge_lines_xray;
}
void NavigationServer3D::set_debug_navigation_enable_geometry_face_random_color(const bool p_value) {
debug_navigation_enable_geometry_face_random_color = p_value;
debug_dirty = true;
call_deferred("_emit_navigation_debug_changed_signal");
}
bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color() const {
return debug_navigation_enable_geometry_face_random_color;
}
void NavigationServer3D::set_debug_enabled(bool p_enabled) {
if (debug_enabled != p_enabled) {
debug_dirty = true;
}
debug_enabled = p_enabled;
if (debug_dirty) {
call_deferred("_emit_navigation_debug_changed_signal");
}
}
bool NavigationServer3D::get_debug_enabled() const {
return debug_enabled;
}
#endif // DEBUG_ENABLED

View file

@ -207,6 +207,68 @@ public:
NavigationServer3D(); NavigationServer3D();
virtual ~NavigationServer3D(); virtual ~NavigationServer3D();
#ifdef DEBUG_ENABLED
bool debug_enabled = true;
bool debug_dirty = true;
void _emit_navigation_debug_changed_signal();
void set_debug_enabled(bool p_enabled);
bool get_debug_enabled() const;
Color debug_navigation_edge_connection_color = Color(1.0, 0.0, 1.0, 1.0);
Color debug_navigation_geometry_edge_color = Color(0.5, 1.0, 1.0, 1.0);
Color debug_navigation_geometry_face_color = Color(0.5, 1.0, 1.0, 0.4);
Color debug_navigation_geometry_edge_disabled_color = Color(0.5, 0.5, 0.5, 1.0);
Color debug_navigation_geometry_face_disabled_color = Color(0.5, 0.5, 0.5, 0.4);
bool debug_navigation_enable_edge_connections = true;
bool debug_navigation_enable_edge_connections_xray = true;
bool debug_navigation_enable_edge_lines = true;
bool debug_navigation_enable_edge_lines_xray = true;
bool debug_navigation_enable_geometry_face_random_color = true;
Ref<StandardMaterial3D> debug_navigation_geometry_edge_material;
Ref<StandardMaterial3D> debug_navigation_geometry_face_material;
Ref<StandardMaterial3D> debug_navigation_geometry_edge_disabled_material;
Ref<StandardMaterial3D> debug_navigation_geometry_face_disabled_material;
Ref<StandardMaterial3D> debug_navigation_edge_connections_material;
void set_debug_navigation_edge_connection_color(const Color &p_color);
Color get_debug_navigation_edge_connection_color() const;
void set_debug_navigation_geometry_edge_color(const Color &p_color);
Color get_debug_navigation_geometry_edge_color() const;
void set_debug_navigation_geometry_face_color(const Color &p_color);
Color get_debug_navigation_geometry_face_color() const;
void set_debug_navigation_geometry_edge_disabled_color(const Color &p_color);
Color get_debug_navigation_geometry_edge_disabled_color() const;
void set_debug_navigation_geometry_face_disabled_color(const Color &p_color);
Color get_debug_navigation_geometry_face_disabled_color() const;
void set_debug_navigation_enable_edge_connections(const bool p_value);
bool get_debug_navigation_enable_edge_connections() const;
void set_debug_navigation_enable_edge_connections_xray(const bool p_value);
bool get_debug_navigation_enable_edge_connections_xray() const;
void set_debug_navigation_enable_edge_lines(const bool p_value);
bool get_debug_navigation_enable_edge_lines() const;
void set_debug_navigation_enable_edge_lines_xray(const bool p_value);
bool get_debug_navigation_enable_edge_lines_xray() const;
void set_debug_navigation_enable_geometry_face_random_color(const bool p_value);
bool get_debug_navigation_enable_geometry_face_random_color() const;
Ref<StandardMaterial3D> get_debug_navigation_geometry_face_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_edge_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_face_disabled_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_edge_disabled_material();
Ref<StandardMaterial3D> get_debug_navigation_edge_connections_material();
#endif // DEBUG_ENABLED
}; };
typedef NavigationServer3D *(*NavigationServer3DCallback)(); typedef NavigationServer3D *(*NavigationServer3DCallback)();