From 45f6110e2634235e4828877a366c029470265ff8 Mon Sep 17 00:00:00 2001 From: Juan Pablo Arce Date: Fri, 19 Jul 2024 20:30:33 -0300 Subject: [PATCH] Fix gizmos without visible geometry not being selectable The issue was that Node3DEditorViewport was using the render server's BVH to filter out nodes, which is not correct for gizmos that have no renderable components, or have collision triangles that exceed the bounds of their renderable components. --- editor/plugins/node_3d_editor_gizmos.cpp | 37 +++++++++++++++ editor/plugins/node_3d_editor_gizmos.h | 5 ++ editor/plugins/node_3d_editor_plugin.cpp | 60 ++++++++++++++++++++---- editor/plugins/node_3d_editor_plugin.h | 9 ++++ 4 files changed, 101 insertions(+), 10 deletions(-) diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index de56767929a..67d5e44ce57 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -81,6 +81,8 @@ void EditorNode3DGizmo::redraw() { gizmo_plugin->redraw(this); } + _update_bvh(); + if (Node3DEditor::get_singleton()->is_current_selected_gizmo(this)) { Node3DEditor::get_singleton()->update_transform_gizmo(); } @@ -244,6 +246,32 @@ void EditorNode3DGizmo::add_mesh(const Ref &p_mesh, const Ref &p instances.push_back(ins); } +void EditorNode3DGizmo::_update_bvh() { + ERR_FAIL_NULL(spatial_node); + + Transform3D transform = spatial_node->get_global_transform(); + + float effective_icon_size = selectable_icon_size > 0.0f ? selectable_icon_size : 0.0f; + Vector3 icon_size_vector3 = Vector3(effective_icon_size, effective_icon_size, effective_icon_size); + AABB aabb(spatial_node->get_position() - icon_size_vector3 * 100.0f, icon_size_vector3 * 200.0f); + + for (const Vector3 &segment_end : collision_segments) { + aabb.expand_to(transform.xform(segment_end)); + } + + if (collision_mesh.is_valid()) { + for (const Face3 &face : collision_mesh->get_faces()) { + aabb.expand_to(transform.xform(face.vertex[0])); + aabb.expand_to(transform.xform(face.vertex[1])); + aabb.expand_to(transform.xform(face.vertex[2])); + } + } + + Node3DEditor::get_singleton()->update_gizmo_bvh_node( + bvh_node_id, + aabb); +} + void EditorNode3DGizmo::add_lines(const Vector &p_lines, const Ref &p_material, bool p_billboard, const Color &p_modulate) { add_vertices(p_lines, p_material, Mesh::PRIMITIVE_LINES, p_billboard, p_modulate); } @@ -765,6 +793,10 @@ void EditorNode3DGizmo::create() { instances.write[i].create_instance(spatial_node, hidden); } + bvh_node_id = Node3DEditor::get_singleton()->insert_gizmo_bvh_node( + spatial_node, + AABB(spatial_node->get_position(), Vector3(0, 0, 0))); + transform(); } @@ -774,6 +806,8 @@ void EditorNode3DGizmo::transform() { for (int i = 0; i < instances.size(); i++) { RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform() * instances[i].xform); } + + _update_bvh(); } void EditorNode3DGizmo::free() { @@ -790,6 +824,9 @@ void EditorNode3DGizmo::free() { clear(); + Node3DEditor::get_singleton()->remove_gizmo_bvh_node(bvh_node_id); + bvh_node_id = DynamicBVH::ID(); + valid = false; } diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index d7c368d5d01..c4b275032ab 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -31,6 +31,7 @@ #ifndef NODE_3D_EDITOR_GIZMOS_H #define NODE_3D_EDITOR_GIZMOS_H +#include "core/math/dynamic_bvh.h" #include "core/templates/hash_map.h" #include "core/templates/local_vector.h" #include "scene/3d/camera_3d.h" @@ -72,8 +73,12 @@ class EditorNode3DGizmo : public Node3DGizmo { Vector instances; Node3D *spatial_node = nullptr; + DynamicBVH::ID bvh_node_id; + void _set_node_3d(Node *p_node) { set_node_3d(Object::cast_to(p_node)); } + void _update_bvh(); + protected: static void _bind_methods(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 72eea8a27ed..d8a8c8ab05c 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -800,7 +800,6 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray); } - Vector instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario()); HashSet> found_gizmos; Node *edited_scene = get_tree()->get_edited_scene_root(); @@ -808,9 +807,9 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { Node *item = nullptr; float closest_dist = 1e20; - for (int i = 0; i < instances.size(); i++) { - Node3D *spat = Object::cast_to(ObjectDB::get_instance(instances[i])); + Vector nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_ray_query(pos, pos + ray * camera->get_far()); + for (Node3D *spat : nodes_with_gizmos) { if (!spat) { continue; } @@ -863,12 +862,11 @@ void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, Vector<_RayRe Vector3 ray = get_ray(p_pos); Vector3 pos = get_ray_pos(p_pos); - Vector instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario()); + Vector nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_ray_query(pos, pos + ray * camera->get_far()); + HashSet found_nodes; - for (int i = 0; i < instances.size(); i++) { - Node3D *spat = Object::cast_to(ObjectDB::get_instance(instances[i])); - + for (Node3D *spat : nodes_with_gizmos) { if (!spat) { continue; } @@ -1046,14 +1044,13 @@ void Node3DEditorViewport::_select_region() { _clear_selected(); } - Vector instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world_3d()->get_scenario()); + Vector nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_frustum_query(frustum); HashSet found_nodes; Vector selected; Node *edited_scene = get_tree()->get_edited_scene_root(); - for (int i = 0; i < instances.size(); i++) { - Node3D *sp = Object::cast_to(ObjectDB::get_instance(instances[i])); + for (Node3D *sp : nodes_with_gizmos) { if (!sp || _is_node_locked(sp)) { continue; } @@ -9205,6 +9202,49 @@ void Node3DEditor::remove_gizmo_plugin(Ref p_plugin) { _update_gizmos_menu(); } +DynamicBVH::ID Node3DEditor::insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb) { + return gizmo_bvh.insert(p_aabb, p_node); +} + +void Node3DEditor::update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb) { + gizmo_bvh.update(p_id, p_aabb); + gizmo_bvh.optimize_incremental(1); +} + +void Node3DEditor::remove_gizmo_bvh_node(DynamicBVH::ID p_id) { + gizmo_bvh.remove(p_id); +} + +Vector Node3DEditor::gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end) { + struct Result { + Vector nodes; + bool operator()(void *p_data) { + nodes.append((Node3D *)p_data); + return false; + } + } result; + + gizmo_bvh.ray_query(p_ray_start, p_ray_end, result); + + return result.nodes; +} + +Vector Node3DEditor::gizmo_bvh_frustum_query(const Vector &p_frustum) { + Vector points = Geometry3D::compute_convex_mesh_points(&p_frustum[0], p_frustum.size()); + + struct Result { + Vector nodes; + bool operator()(void *p_data) { + nodes.append((Node3D *)p_data); + return false; + } + } result; + + gizmo_bvh.convex_query(p_frustum.ptr(), p_frustum.size(), points.ptr(), points.size(), result); + + return result.nodes; +} + Node3DEditorPlugin::Node3DEditorPlugin() { spatial_editor = memnew(Node3DEditor); spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 5bd14748c08..9e7d46c5e85 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -31,6 +31,7 @@ #ifndef NODE_3D_EDITOR_PLUGIN_H #define NODE_3D_EDITOR_PLUGIN_H +#include "core/math/dynamic_bvh.h" #include "editor/plugins/editor_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" #include "editor/themes/editor_scale.h" @@ -629,6 +630,8 @@ private: int current_hover_gizmo_handle; bool current_hover_gizmo_handle_secondary; + DynamicBVH gizmo_bvh; + real_t snap_translate_value; real_t snap_rotate_value; real_t snap_scale_value; @@ -933,6 +936,12 @@ public: void add_gizmo_plugin(Ref p_plugin); void remove_gizmo_plugin(Ref p_plugin); + DynamicBVH::ID insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb); + void update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb); + void remove_gizmo_bvh_node(DynamicBVH::ID p_id); + Vector gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end); + Vector gizmo_bvh_frustum_query(const Vector &p_frustum); + void edit(Node3D *p_spatial); void clear();