From 58e4bbff49451cb1d6943bb674d9c2532b4cf92e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 9 Nov 2026 07:56:51 +0100 Subject: [PATCH] fix(editor): a model turned with the gizmo about the vertical axis no longer jumps back and forth The angles of the whole gizmo matrix were decomposed every frame and the model was turned by their difference from its own. The decomposition gives the angle about the vertical axis only within -90..90 degrees: past 90 it comes out as 180 - angle with the other two axes turned by 180, so a drag one way turned the model back and flipped it. The turn is now taken from the delta matrix of this frame (small, so its angles decompose with no ambiguity) and wrapped to -180..180. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DDcMn1Q7wdYkbxDUWscNHZ --- application/editormode.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/application/editormode.cpp b/application/editormode.cpp index 32f991c5..1ad3ef6e 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -4804,8 +4804,12 @@ void editor_mode::render_gizmo() snapvalue = glm::vec3(0.1f); float const *snap = Global.ctrlState && snapvalue.x > 0.0f ? glm::value_ptr(snapvalue) : nullptr; + // the change of this frame alone: a turn is taken from it, not from the angles the whole matrix decomposes into, + // which can't tell a turn of more than 90 degrees about the vertical axis (it comes out as 180 - angle with the + // other two axes flipped, and the model turned back and forth while dragged one way) + glm::mat4 delta(1.0f); ImGuizmo::Manipulate(glm::value_ptr(view), glm::value_ptr(projection), - operation, mode, glm::value_ptr(matrix), nullptr, snap); + operation, mode, glm::value_ptr(matrix), glm::value_ptr(delta), snap); if (ImGuizmo::IsUsing()) { @@ -4822,9 +4826,11 @@ void editor_mode::render_gizmo() if (operation == ImGuizmo::ROTATE && model) { - // apply the rotation delta relative to the model's current orientation - glm::vec3 const newangles(newrotation[0], newrotation[1], newrotation[2]); - auto const turned{newangles - model->Angles()}; + // the turn of this frame, small, so its angles decompose with no ambiguity + float deltatranslation[3], deltarotation[3], deltascale[3]; + ImGuizmo::DecomposeMatrixToComponents(glm::value_ptr(delta), deltatranslation, deltarotation, deltascale); + auto const wrapped = [](float Angle) { return Angle - 360.0f * std::floor((Angle + 180.0f) / 360.0f); }; + glm::vec3 const turned{wrapped(deltarotation[0]), wrapped(deltarotation[1]), wrapped(deltarotation[2])}; m_editor.rotate(model, turned, 0.0f); selection_follow(glm::dvec3(0.0), turned, model->location()); }