From 44ef3d35eb928abbe51260e33b86dcb3368aa1d9 Mon Sep 17 00:00:00 2001 From: Rie Date: Sun, 8 Sep 2024 21:55:15 +0200 Subject: [PATCH] Make use of NavigationObstacle3D's transform Co-authored-by: a0kami --- .../navigation_obstacle_3d_editor_plugin.cpp | 71 ++++--------------- .../navigation/3d/nav_mesh_generator_3d.cpp | 19 +++-- scene/3d/navigation_obstacle_3d.cpp | 33 +++++++-- scene/3d/navigation_obstacle_3d.h | 2 + 4 files changed, 57 insertions(+), 68 deletions(-) diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp index 2eaab0fcbde..262050ecf6d 100644 --- a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp +++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp @@ -115,9 +115,14 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam return EditorPlugin::AFTER_GUI_INPUT_PASS; } - Transform3D gt = obstacle_node->get_global_transform(); + // Use special transformation rules for NavigationObstacle3D: Only take global y-rotation into account and limit scaling to positive values. + Transform3D gt; + gt.origin = obstacle_node->get_global_position(); + gt.scale_basis(obstacle_node->get_global_basis().get_scale().abs().maxf(0.001)); + gt.rotate_basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y); Transform3D gi = gt.affine_inverse(); Plane p(Vector3(0.0, 1.0, 0.0), gt.origin); + point_lines_meshinstance->set_transform(gt.translated(Vector3(0.0, 0.0, 0.00001))); Ref mb = p_event; @@ -374,9 +379,12 @@ void NavigationObstacle3DEditor::_polygon_draw() { point_handle_mesh->clear_surfaces(); point_lines_mesh->clear_surfaces(); point_lines_meshinstance->set_material_override(line_material); - point_lines_mesh->surface_begin(Mesh::PRIMITIVE_LINES); - Rect2 rect; + if (poly.is_empty()) { + return; + } + + point_lines_mesh->surface_begin(Mesh::PRIMITIVE_LINES); for (int i = 0; i < poly.size(); i++) { Vector2 p, p2; @@ -392,12 +400,6 @@ void NavigationObstacle3DEditor::_polygon_draw() { p2 = poly[(i + 1) % poly.size()]; } - if (i == 0) { - rect.position = p; - } else { - rect.expand_to(p); - } - Vector3 point = Vector3(p.x, 0.0, p.y); Vector3 next_point = Vector3(p2.x, 0.0, p2.y); @@ -411,58 +413,8 @@ void NavigationObstacle3DEditor::_polygon_draw() { //vpc->draw_texture(handle,point-handle->get_size()*0.5); } - rect = rect.grow(1); - - AABB r; - r.position.x = rect.position.x; - r.position.y = 0.0; - r.position.z = rect.position.y; - r.size.x = rect.size.x; - r.size.y = 0; - r.size.z = rect.size.y; - - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(0.3, 0, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(0.0, 0.3, 0)); - - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0) - Vector3(0.3, 0, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0) + Vector3(0, 0.3, 0)); - - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0) - Vector3(0, 0.3, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0) + Vector3(0.3, 0, 0)); - - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + r.size); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + r.size - Vector3(0.3, 0, 0)); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + r.size); - point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); - point_lines_mesh->surface_add_vertex(r.position + r.size - Vector3(0.0, 0.3, 0)); - point_lines_mesh->surface_end(); - if (poly.size() == 0) { - return; - } - Array point_handle_mesh_array; point_handle_mesh_array.resize(Mesh::ARRAY_MAX); Vector point_handle_mesh_vertices; @@ -541,6 +493,7 @@ NavigationObstacle3DEditor::NavigationObstacle3DEditor() { point_lines_mesh.instantiate(); point_lines_meshinstance->set_mesh(point_lines_mesh); point_lines_meshinstance->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001))); + point_lines_meshinstance->set_as_top_level(true); line_material = Ref(memnew(StandardMaterial3D)); line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); diff --git a/modules/navigation/3d/nav_mesh_generator_3d.cpp b/modules/navigation/3d/nav_mesh_generator_3d.cpp index ce1551e5842..3d0697a7cf9 100644 --- a/modules/navigation/3d/nav_mesh_generator_3d.cpp +++ b/modules/navigation/3d/nav_mesh_generator_3d.cpp @@ -595,11 +595,17 @@ void NavMeshGenerator3D::generator_parse_navigationobstacle_node(const Refroot_node_transform * Transform3D(Basis(), obstacle->get_global_position()); - + const float elevation = obstacle->get_global_position().y + p_source_geometry_data->root_node_transform.origin.y; + // Prevent non-positive scaling. + const Vector3 safe_scale = obstacle->get_global_basis().get_scale().abs().maxf(0.001); const float obstacle_radius = obstacle->get_radius(); if (obstacle_radius > 0.0) { + // Radius defined obstacle should be uniformly scaled from obstacle basis max scale axis. + const float scaling_max_value = safe_scale[safe_scale.max_axis_index()]; + const Vector3 uniform_max_scale = Vector3(scaling_max_value, scaling_max_value, scaling_max_value); + const Transform3D obstacle_circle_transform = p_source_geometry_data->root_node_transform * Transform3D(Basis().scaled(uniform_max_scale), obstacle->get_global_position()); + Vector obstruction_circle_vertices; // The point of this is that the moving obstacle can make a simple hole in the navigation mesh and affect the pathfinding. @@ -613,12 +619,15 @@ void NavMeshGenerator3D::generator_parse_navigationobstacle_node(const Refadd_projected_obstruction(obstruction_circle_vertices, obstacle->get_global_position().y + p_source_geometry_data->root_node_transform.origin.y - obstacle_radius, obstacle_radius, obstacle->get_carve_navigation_mesh()); + p_source_geometry_data->add_projected_obstruction(obstruction_circle_vertices, elevation - obstacle_radius, scaling_max_value * obstacle_radius, obstacle->get_carve_navigation_mesh()); } + // Obstacles are projected to the xz-plane, so only rotation around the y-axis can be taken into account. + const Transform3D node_xform = p_source_geometry_data->root_node_transform * Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle->get_global_rotation().y), obstacle->get_global_position()); + const Vector &obstacle_vertices = obstacle->get_vertices(); if (obstacle_vertices.is_empty()) { @@ -635,7 +644,7 @@ void NavMeshGenerator3D::generator_parse_navigationobstacle_node(const Refadd_projected_obstruction(obstruction_shape_vertices, obstacle->get_global_position().y + p_source_geometry_data->root_node_transform.origin.y, obstacle->get_height(), obstacle->get_carve_navigation_mesh()); + p_source_geometry_data->add_projected_obstruction(obstruction_shape_vertices, elevation, safe_scale.y * obstacle->get_height(), obstacle->get_carve_navigation_mesh()); } void NavMeshGenerator3D::generator_parse_source_geometry_data(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_root_node) { diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index 2eb04a0054e..71c77174d6f 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -176,13 +176,19 @@ void NavigationObstacle3D::_notification(int p_what) { } #ifdef DEBUG_ENABLED if (fake_agent_radius_debug_instance.is_valid() && radius > 0.0) { - Transform3D debug_transform; - debug_transform.origin = get_global_position(); + // Prevent non-positive scaling. + const Vector3 safe_scale = get_global_basis().get_scale().abs().maxf(0.001); + // Agent radius is a scalar value and does not support non-uniform scaling, choose the largest axis. + const float scaling_max_value = safe_scale[safe_scale.max_axis_index()]; + const Vector3 uniform_max_scale = Vector3(scaling_max_value, scaling_max_value, scaling_max_value); + const Transform3D debug_transform = Transform3D(Basis().scaled(uniform_max_scale), get_global_position()); RS::get_singleton()->instance_set_transform(fake_agent_radius_debug_instance, debug_transform); } if (static_obstacle_debug_instance.is_valid() && get_vertices().size() > 0) { - Transform3D debug_transform; - debug_transform.origin = get_global_position(); + // Prevent non-positive scaling. + const Vector3 safe_scale = get_global_basis().get_scale().abs().maxf(0.001); + // Obstacles are projected to the xz-plane, so only rotation around the y-axis can be taken into account. + const Transform3D debug_transform = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), get_global_rotation().y), get_global_position()); RS::get_singleton()->instance_set_transform(static_obstacle_debug_instance, debug_transform); } #endif // DEBUG_ENABLED @@ -354,6 +360,25 @@ bool NavigationObstacle3D::get_carve_navigation_mesh() const { return carve_navigation_mesh; } +PackedStringArray NavigationObstacle3D::get_configuration_warnings() const { + PackedStringArray warnings = Node3D::get_configuration_warnings(); + + if (get_global_rotation().x != 0.0 || get_global_rotation().z != 0.0) { + warnings.push_back(RTR("NavigationObstacle3D only takes global rotation around the y-axis into account. Rotations around the x-axis or z-axis might lead to unexpected results.")); + } + + const Vector3 global_scale = get_global_basis().get_scale(); + if (global_scale.x < 0.001 || global_scale.y < 0.001 || global_scale.z < 0.001) { + warnings.push_back(RTR("NavigationObstacle3D does not support negative or zero scaling.")); + } + + if (radius > 0.0 && !get_global_basis().is_conformal()) { + warnings.push_back(RTR("The agent radius can only be scaled uniformly. The largest scale value along the three axes will be used.")); + } + + return warnings; +} + void NavigationObstacle3D::_update_map(RID p_map) { NavigationServer3D::get_singleton()->obstacle_set_map(obstacle, p_map); map_current = p_map; diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index 99288fc59e9..111abad8423 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -117,6 +117,8 @@ public: void set_carve_navigation_mesh(bool p_enabled); bool get_carve_navigation_mesh() const; + PackedStringArray get_configuration_warnings() const override; + private: void _update_map(RID p_map); void _update_position(const Vector3 p_position);