diff --git a/extern/glow-extras b/extern/glow-extras index 9a73f0ea1a1272d861fd329d8f61f24cb74d536b..48afcb1fdbcaf874f7d58d86545525bca554696c 160000 --- a/extern/glow-extras +++ b/extern/glow-extras @@ -1 +1 @@ -Subproject commit 9a73f0ea1a1272d861fd329d8f61f24cb74d536b +Subproject commit 48afcb1fdbcaf874f7d58d86545525bca554696c diff --git a/extern/imgui b/extern/imgui index fcf73e7562f82dca7de2e66666e77cbbcc38be5b..8ca0ab36f8a5072b8dfaf569646233166f507c84 160000 --- a/extern/imgui +++ b/extern/imgui @@ -1 +1 @@ -Subproject commit fcf73e7562f82dca7de2e66666e77cbbcc38be5b +Subproject commit 8ca0ab36f8a5072b8dfaf569646233166f507c84 diff --git a/samples/basic/viewer/main.cc b/samples/basic/viewer/main.cc index 86fa731a5c47ffc79ec4e9de816179709422a5c5..9033679864195197ab597e3d2319084b791e6c6f 100644 --- a/samples/basic/viewer/main.cc +++ b/samples/basic/viewer/main.cc @@ -1,4 +1,5 @@ #include <imgui/imgui.h> +#include <imgui/imguizmo.h> #include <glow/common/str_utils.hh> #include <glow/data/TextureData.hh> @@ -15,6 +16,8 @@ #include <glow-extras/viewer/canvas.hh> #include <glow-extras/viewer/view.hh> +#include <GLFW/glfw3.h> + #include <typed-geometry/tg.hh> // path to sample files @@ -164,6 +167,117 @@ void advanced_objects(pm::vertex_attribute<tg::pos3> const& pos) // TODO: images } +void imguizmo(pm::vertex_attribute<tg::pos3> const& pos) +{ + // This sample shows how to use ImGuizmo, a very useful addon for ImGui for editing 4x4 affine transformation matrices using the viewer + // For additional information refer to https://github.com/CedricGuillemet/ImGuizmo/ + + // your own camera is required to access the camera's view and projection matrix + auto cam = gv::CameraController::create(); + + // cache the renderable + auto r = gv::make_renderable(pos); + + // local vs global coordinate system + auto currentGizmoMode = ImGuizmo::LOCAL; + + // the operation that we want to perform (rotate, scale, or translate) + auto currentGizmoOperation = ImGuizmo::ROTATE; + + // do we want to snap to specific values + bool useSnap = false; + + // the values that we want to snap to, i.e. 1 degree steps + float snap[3] = {1.f, 1.f, 1.f}; + + // the transformation that we want to edit + auto transform = tg::mat4::identity; + + // an interactive view is required + gv::interactive([&](float) { + // you can define keybindings to select an operation + if (ImGui::IsKeyPressed(GLFW_KEY_T)) + currentGizmoOperation = ImGuizmo::TRANSLATE; + if (ImGui::IsKeyPressed(GLFW_KEY_R)) + currentGizmoOperation = ImGuizmo::ROTATE; + if (ImGui::IsKeyPressed(GLFW_KEY_S)) + currentGizmoOperation = ImGuizmo::SCALE; + + // you can also choose the correct operation using gui elements + if (ImGui::RadioButton("Translate", currentGizmoOperation == ImGuizmo::TRANSLATE)) + currentGizmoOperation = ImGuizmo::TRANSLATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Rotate", currentGizmoOperation == ImGuizmo::ROTATE)) + currentGizmoOperation = ImGuizmo::ROTATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Scale", currentGizmoOperation == ImGuizmo::SCALE)) + currentGizmoOperation = ImGuizmo::SCALE; + + // ImGuizmo decomposes your input transform into translation, rotation, and scaling components + float matrixTranslation[3], matrixRotation[3], matrixScale[3]; + ImGuizmo::DecomposeMatrixToComponents(&transform[0][0], matrixTranslation, matrixRotation, matrixScale); + + // show the three components individually + ImGui::InputFloat3("Tr", matrixTranslation); + ImGui::InputFloat3("Rt", matrixRotation); + ImGui::InputFloat3("Sc", matrixScale); + + // rebuild your 4x4 transform matrix + ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, &transform[0][0]); + + // only show the radio button to choose local/global coordinate system when NOT scaling + // as scaling is always in local coordinates + if (currentGizmoOperation != ImGuizmo::SCALE) + { + if (ImGui::RadioButton("Local", currentGizmoMode == ImGuizmo::LOCAL)) + currentGizmoMode = ImGuizmo::LOCAL; + ImGui::SameLine(); + if (ImGui::RadioButton("World", currentGizmoMode == ImGuizmo::WORLD)) + currentGizmoMode = ImGuizmo::WORLD; + } + + // toggle snap on p key + if (ImGui::IsKeyPressed(GLFW_KEY_P)) + useSnap = !useSnap; + + // ... or use gui elements + ImGui::Checkbox("", &useSnap); + ImGui::SameLine(); + + // name the snap input accordingly + switch (currentGizmoOperation) + { + case ImGuizmo::TRANSLATE: + ImGui::InputFloat3("Snap", snap); + break; + case ImGuizmo::ROTATE: + ImGui::InputFloat("Angle Snap", snap); + break; + case ImGuizmo::SCALE: + ImGui::InputFloat("Scale Snap", snap); + break; + default: // silence warnings as there are quite a few more possible operations supported by ImGuizmo + break; // do nothing + } + + // ImGuizmo requires view and projection matrix for rendering. + // However, it does not work with a reversed z projection matrix, which is used by the viewer by default + // So we need to disable it temporarily, generate a projection matrix without it, and then reactivate it + auto view = cam->computeViewMatrix(); + auto const rev_z_enabled = cam->reverseZEnabled(); + cam->setReverseZEnabled(false); // + auto project = cam->computeProjMatrix(); + cam->setReverseZEnabled(rev_z_enabled); + + // This is where all the ImGuizmo magic comes together + ImGuizmo::Manipulate(&view[0][0], &project[0][0], currentGizmoOperation, currentGizmoMode, &transform[0][0], nullptr, useSnap ? &snap[0] : nullptr); + + // Because the view is resized when we change the object, it might be a good idea to pass the viewer a fixed bounding box + auto const aabb = tg::aabb3(tg::pos3(-2), tg::pos3(2)); + gv::view(r, cam, transform, aabb); + }); +} + void advanced_visualization(pm::vertex_attribute<tg::pos3> const& pos) { // the args in gv::view(obj, args) do not only configure the viewer but also change how the renderable is visualized @@ -1011,6 +1125,8 @@ int main() subtle_cases(pos); headless_screenshot(pos); + + imguizmo(pos); } // known issues