diff options
-rw-r--r-- | doc/classes/NavigationServer3D.xml | 5 | ||||
-rw-r--r-- | doc/classes/ProjectSettings.xml | 30 | ||||
-rw-r--r-- | editor/editor_node.cpp | 19 | ||||
-rw-r--r-- | editor/plugins/node_3d_editor_gizmos.cpp | 115 | ||||
-rw-r--r-- | main/main.cpp | 2 | ||||
-rw-r--r-- | scene/2d/navigation_region_2d.cpp | 30 | ||||
-rw-r--r-- | scene/3d/navigation_region_3d.cpp | 339 | ||||
-rw-r--r-- | scene/3d/navigation_region_3d.h | 13 | ||||
-rw-r--r-- | scene/resources/navigation_mesh.cpp | 101 | ||||
-rw-r--r-- | scene/resources/navigation_mesh.h | 4 | ||||
-rw-r--r-- | servers/navigation_server_3d.cpp | 257 | ||||
-rw-r--r-- | servers/navigation_server_3d.h | 62 |
12 files changed, 915 insertions, 62 deletions
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 5185b353bc..8600c2643a 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -415,5 +415,10 @@ Emitted when a navigation map is updated, when a region moves or is modified. </description> </signal> + <signal name="navigation_debug_changed"> + <description> + Emitted when navigation debug settings are changed. Only available in debug builds. + </description> + </signal> </signals> </class> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index a2e92fb61b..b1e3d2f628 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -494,9 +494,39 @@ <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. </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)"> Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. </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)"> Color of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu. </member> diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8294e2229a..f5cdc63042 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -552,6 +552,19 @@ void EditorNode::_update_from_settings() { 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_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() { @@ -5928,7 +5941,11 @@ EditorNode::EditorNode() { AudioServer::get_singleton()->set_enable_tagging_used_audio_streams(true); // 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. PhysicsServer3D::get_singleton()->set_active(false); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index f7a2915ea2..5c66026c1b 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -75,6 +75,7 @@ #include "scene/resources/sphere_shape_3d.h" #include "scene/resources/surface_tool.h" #include "scene/resources/world_boundary_shape_3d.h" +#include "servers/navigation_server_3d.h" #define HANDLE_HALF_SIZE 9.5 @@ -4835,10 +4836,6 @@ void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { //// 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) { @@ -4854,24 +4851,19 @@ int NavigationRegion3DGizmoPlugin::get_priority() const { } void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - NavigationRegion3D *navmesh = 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); + NavigationRegion3D *navigationregion = Object::cast_to<NavigationRegion3D>(p_gizmo->get_spatial_node()); p_gizmo->clear(); - Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh(); - if (navmeshie.is_null()) { + Ref<NavigationMesh> navigationmesh = navigationregion->get_navigation_mesh(); + if (navigationmesh.is_null()) { return; } - Vector<Vector3> vertices = navmeshie->get_vertices(); + Vector<Vector3> vertices = navigationmesh->get_vertices(); const Vector3 *vr = vertices.ptr(); List<Face3> faces; - for (int i = 0; i < navmeshie->get_polygon_count(); i++) { - Vector<int> p = navmeshie->get_polygon(i); + for (int i = 0; i < navigationmesh->get_polygon_count(); i++) { + Vector<int> p = navigationmesh->get_polygon(i); for (int j = 2; j < p.size(); j++) { Face3 f; @@ -4928,17 +4920,90 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Ref<TriangleMesh> tmesh = memnew(TriangleMesh); 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); - Ref<ArrayMesh> m = memnew(ArrayMesh); - Array a; - a.resize(Mesh::ARRAY_MAX); - a[0] = tmeshfaces; - m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a); - m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled); - p_gizmo->add_mesh(m); + + Ref<ArrayMesh> debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + int polygon_count = navigationmesh->get_polygon_count(); + + // 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 = 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); } diff --git a/main/main.cpp b/main/main.cpp index a9037806bf..42a866317e 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2430,6 +2430,8 @@ bool Main::start() { } if (debug_navigation) { sml->set_debug_navigation_hint(true); + NavigationServer3D::get_singleton()->set_active(true); + NavigationServer3D::get_singleton_mut()->set_debug_enabled(true); } #endif diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 6e8fd891cb..6f189a57e8 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" +#include "servers/navigation_server_3d.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)); } - 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(); } +#endif // DEBUG_ENABLED } bool NavigationRegion2D::is_enabled() const { @@ -462,7 +465,8 @@ void NavigationRegion2D::_notification(int p_what) { } break; 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(); if (verts.size() < 3) { return; @@ -470,11 +474,11 @@ void NavigationRegion2D::_notification(int p_what) { Color color; if (enabled) { - color = get_tree()->get_debug_navigation_color(); + color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(); } 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; @@ -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); } } +#endif // DEBUG_ENABLED } break; } } @@ -552,10 +557,13 @@ void NavigationRegion2D::_navpoly_changed() { NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); } } + 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(); } +#endif // DEBUG_ENABLED } TypedArray<String> NavigationRegion2D::get_configuration_warnings() const { @@ -605,8 +613,18 @@ NavigationRegion2D::NavigationRegion2D() { region = NavigationServer2D::get_singleton()->region_create(); NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_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() { 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 } diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 2a8149c6f6..0abb0e8dea 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -49,14 +49,29 @@ void NavigationRegion3D::set_enabled(bool p_enabled) { NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); } - if (debug_view) { - MeshInstance3D *dm = Object::cast_to<MeshInstance3D>(debug_view); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + 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 { - 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(); } @@ -124,30 +139,36 @@ void NavigationRegion3D::_notification(int p_what) { NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); } - if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { - MeshInstance3D *dm = memnew(MeshInstance3D); - dm->set_mesh(navmesh->get_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; +#ifdef DEBUG_ENABLED + if (NavigationServer3D::get_singleton()->get_debug_enabled()) { + _update_debug_mesh(); } +#endif // DEBUG_ENABLED + } break; case NOTIFICATION_TRANSFORM_CHANGED: { 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; case NOTIFICATION_EXIT_TREE: { NavigationServer3D::get_singleton()->region_set_map(region, RID()); - if (debug_view) { - debug_view->queue_delete(); - debug_view = nullptr; +#ifdef DEBUG_ENABLED + 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); } +#endif // DEBUG_ENABLED } break; } } @@ -169,20 +190,21 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes 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()) { - MeshInstance3D *dm = memnew(MeshInstance3D); - dm->set_mesh(navmesh->get_debug_mesh()); - if (is_enabled()) { - dm->set_material_override(get_tree()->get_debug_navigation_material()); +#ifdef DEBUG_ENABLED + if (is_inside_tree() && NavigationServer3D::get_singleton()->get_debug_enabled()) { + if (navmesh.is_valid()) { + _update_debug_mesh(); + _update_debug_edge_connections_mesh(); } 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")); @@ -287,13 +309,31 @@ void NavigationRegion3D::_bind_methods() { void NavigationRegion3D::_navigation_changed() { update_gizmos(); 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() { set_notify_transform(true); region = NavigationServer3D::get_singleton()->region_create(); NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_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() { @@ -301,4 +341,245 @@ NavigationRegion3D::~NavigationRegion3D() { navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } 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 diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index b15e97de6a..ba326abb46 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -44,11 +44,22 @@ class NavigationRegion3D : public Node3D { real_t enter_cost = 0.0; real_t travel_cost = 1.0; - Node *debug_view = nullptr; Thread bake_thread; 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: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index a808ead66b..ac5493efdc 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -30,6 +30,10 @@ #include "navigation_mesh.h" +#ifdef DEBUG_ENABLED +#include "servers/navigation_server_3d.h" +#endif + void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { ERR_FAIL_COND(p_mesh.is_null()); @@ -337,6 +341,7 @@ void NavigationMesh::clear_polygons() { polygons.clear(); } +#ifndef DISABLE_DEPRECATED Ref<Mesh> NavigationMesh::get_debug_mesh() { if (debug_mesh.is_valid()) { return debug_mesh; @@ -420,6 +425,102 @@ Ref<Mesh> NavigationMesh::get_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() { ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type); diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 40b275c792..79d8962d24 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -204,7 +204,11 @@ public: Vector<int> get_polygon(int p_idx); void clear_polygons(); +#ifndef DISABLE_DEPRECATED Ref<Mesh> get_debug_mesh(); +#endif // DISABLE_DEPRECATED + + Ref<ArrayMesh> _get_debug_mesh(); NavigationMesh(); }; diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 6c48c4a8de..52855c5931 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -30,6 +30,10 @@ #include "navigation_server_3d.h" +#ifdef DEBUG_ENABLED +#include "core/config/project_settings.h" +#endif // DEBUG_ENABLED + NavigationServer3D *NavigationServer3D::singleton = nullptr; void NavigationServer3D::_bind_methods() { @@ -92,6 +96,8 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process); ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map"))); + + ADD_SIGNAL(MethodInfo("navigation_debug_changed")); } const NavigationServer3D *NavigationServer3D::get_singleton() { @@ -105,6 +111,19 @@ NavigationServer3D *NavigationServer3D::get_singleton_mut() { NavigationServer3D::NavigationServer3D() { ERR_FAIL_COND(singleton != nullptr); 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() { @@ -121,3 +140,241 @@ NavigationServer3D *NavigationServer3DManager::new_default_server() { ERR_FAIL_COND_V(create_callback == nullptr, nullptr); 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 diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index cf91596604..1a22597243 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -207,6 +207,68 @@ public: 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)(); |