From 14a7c0f1e5daa1890de393bc2d2ecbff9d5530ae Mon Sep 17 00:00:00 2001 From: mxtherfxcker Date: Thu, 8 Jan 2026 20:07:21 +0300 Subject: [PATCH] Fix Skeleton3D edit mode usability issues --- editor/scene/3d/skeleton_3d_editor_plugin.cpp | 98 ++++++++++++------- editor/scene/3d/skeleton_3d_editor_plugin.h | 9 +- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/editor/scene/3d/skeleton_3d_editor_plugin.cpp b/editor/scene/3d/skeleton_3d_editor_plugin.cpp index e5977aad79..db910f041a 100644 --- a/editor/scene/3d/skeleton_3d_editor_plugin.cpp +++ b/editor/scene/3d/skeleton_3d_editor_plugin.cpp @@ -1518,15 +1518,32 @@ EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_3d_gui_input(Camera3 Node3DEditor *ne = Node3DEditor::get_singleton(); if (se && se->is_edit_mode()) { const Ref mb = p_event; + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { + Skeleton3D *skeleton = se->get_skeleton(); + if (skeleton) { + int closest_idx = Skeleton3DGizmoPlugin::skeleton_intersect_ray(skeleton, p_camera, mb->get_position()); + if (closest_idx >= 0) { + se->select_bone(closest_idx); + se->update_bone_original(); + + Vector> gizmos = skeleton->get_gizmos(); + for (Ref seg : gizmos) { + if (seg.is_valid()) { + Transform3D bone_xform = seg->get_subgizmo_transform(closest_idx); + ne->call("_set_subgizmo_selection", skeleton, seg, closest_idx, bone_xform); + break; + } + } + return EditorPlugin::AFTER_GUI_INPUT_STOP; + } + } + } if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) { if (!ne->is_gizmo_visible()) { return EditorPlugin::AFTER_GUI_INPUT_STOP; } } - if (mb->is_pressed()) { - se->update_bone_original(); - } } return EditorPlugin::AFTER_GUI_INPUT_CUSTOM; } @@ -1629,19 +1646,27 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi return -1; } - if (Node3DEditor::get_singleton()->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) { - return -1; + int closest_idx = skeleton_intersect_ray(skeleton, p_camera, p_point); + + if (closest_idx >= 0) { + se->select_bone(closest_idx); + se->update_bone_original(); + return closest_idx; } - // Select bone. - real_t grab_threshold = 4 * EDSCALE; + se->select_bone(-1); + return -1; +} + +int Skeleton3DGizmoPlugin::skeleton_intersect_ray(const Skeleton3D *p_skeleton, Camera3D *p_camera, const Vector2 &p_point) { + real_t grab_threshold = 8 * EDSCALE; Vector3 ray_from = p_camera->get_global_transform().origin; - Transform3D gt = skeleton->get_global_transform(); + Transform3D gt = p_skeleton->get_global_transform(); int closest_idx = -1; real_t closest_dist = 1e10; - const int bone_count = skeleton->get_bone_count(); + const int bone_count = p_skeleton->get_bone_count(); for (int i = 0; i < bone_count; i++) { - Vector3 joint_pos_3d = gt.xform(skeleton->get_bone_global_pose(i).origin); + Vector3 joint_pos_3d = gt.xform(p_skeleton->get_bone_global_pose(i).origin); Vector2 joint_pos_2d = p_camera->unproject_position(joint_pos_3d); real_t dist_3d = ray_from.distance_to(joint_pos_3d); real_t dist_2d = p_point.distance_to(joint_pos_2d); @@ -1650,14 +1675,7 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi closest_idx = i; } } - - if (closest_idx >= 0) { - se->select_bone(closest_idx); - return closest_idx; - } - - se->select_bone(-1); - return -1; + return closest_idx; } Transform3D Skeleton3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const { @@ -1705,25 +1723,35 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Set Bone Transform")); - if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { - for (int i = 0; i < p_ids.size(); i++) { - ur->add_do_method(skeleton, "set_bone_pose_position", p_ids[i], skeleton->get_bone_pose_position(p_ids[i])); - ur->add_undo_method(skeleton, "set_bone_pose_position", p_ids[i], se->get_bone_original_position()); + + if (p_cancel) { + for (int id : p_ids) { + ur->add_do_method(skeleton, "set_bone_pose_position", id, se->get_bone_original_position()); + ur->add_do_method(skeleton, "set_bone_pose_rotation", id, se->get_bone_original_rotation()); + ur->add_do_method(skeleton, "set_bone_pose_scale", id, se->get_bone_original_scale()); + ur->add_undo_method(skeleton, "set_bone_pose_position", id, skeleton->get_bone_pose_position(id)); + ur->add_undo_method(skeleton, "set_bone_pose_rotation", id, skeleton->get_bone_pose_rotation(id)); + ur->add_undo_method(skeleton, "set_bone_pose_scale", id, skeleton->get_bone_pose_scale(id)); } - } - if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) { - for (int i = 0; i < p_ids.size(); i++) { - ur->add_do_method(skeleton, "set_bone_pose_rotation", p_ids[i], skeleton->get_bone_pose_rotation(p_ids[i])); - ur->add_undo_method(skeleton, "set_bone_pose_rotation", p_ids[i], se->get_bone_original_rotation()); + } else { + Node3DEditor::ToolMode tool_mode = ne->get_tool_mode(); + if (tool_mode == Node3DEditor::TOOL_MODE_SELECT || tool_mode == Node3DEditor::TOOL_MODE_MOVE || tool_mode == Node3DEditor::TOOL_MODE_TRANSFORM) { + for (int id : p_ids) { + ur->add_do_method(skeleton, "set_bone_pose_position", id, skeleton->get_bone_pose_position(id)); + ur->add_undo_method(skeleton, "set_bone_pose_position", id, se->get_bone_original_position()); + } } - } - if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { - for (int i = 0; i < p_ids.size(); i++) { - // If the axis is swapped by scaling, the rotation can be changed. - ur->add_do_method(skeleton, "set_bone_pose_rotation", p_ids[i], skeleton->get_bone_pose_rotation(p_ids[i])); - ur->add_undo_method(skeleton, "set_bone_pose_rotation", p_ids[i], se->get_bone_original_rotation()); - ur->add_do_method(skeleton, "set_bone_pose_scale", p_ids[i], skeleton->get_bone_pose_scale(p_ids[i])); - ur->add_undo_method(skeleton, "set_bone_pose_scale", p_ids[i], se->get_bone_original_scale()); + if (tool_mode == Node3DEditor::TOOL_MODE_SELECT || tool_mode == Node3DEditor::TOOL_MODE_ROTATE || tool_mode == Node3DEditor::TOOL_MODE_TRANSFORM) { + for (int id : p_ids) { + ur->add_do_method(skeleton, "set_bone_pose_rotation", id, skeleton->get_bone_pose_rotation(id)); + ur->add_undo_method(skeleton, "set_bone_pose_rotation", id, se->get_bone_original_rotation()); + } + } + if (tool_mode == Node3DEditor::TOOL_MODE_SCALE || tool_mode == Node3DEditor::TOOL_MODE_TRANSFORM) { + for (int id : p_ids) { + ur->add_do_method(skeleton, "set_bone_pose_scale", id, skeleton->get_bone_pose_scale(id)); + ur->add_undo_method(skeleton, "set_bone_pose_scale", id, se->get_bone_original_scale()); + } } } diff --git a/editor/scene/3d/skeleton_3d_editor_plugin.h b/editor/scene/3d/skeleton_3d_editor_plugin.h index 1121c27701..ac5fc19ce3 100644 --- a/editor/scene/3d/skeleton_3d_editor_plugin.h +++ b/editor/scene/3d/skeleton_3d_editor_plugin.h @@ -292,15 +292,16 @@ class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: static Ref get_bones_mesh(Skeleton3D *p_skeleton, int p_selected, bool p_is_selected); + static int skeleton_intersect_ray(const Skeleton3D *p_skeleton, Camera3D *p_camera, const Vector2 &p_point); bool has_gizmo(Node3D *p_spatial) override; String get_gizmo_name() const override; int get_priority() const override; - int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override; - Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override; - void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector &p_ids, const Vector &p_restore, bool p_cancel) override; + virtual int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override; + virtual Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override; + virtual void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override; + virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector &p_ids, const Vector &p_restore, bool p_cancel) override; void redraw(EditorNode3DGizmo *p_gizmo) override;