Browse Source

move ImGuizmo tutorial into plugin; simplify and isolate

Alec Jacobson 5 years ago
parent
commit
d9864be29e

+ 0 - 59
include/igl/opengl/glfw/imgui/ImGuizmo.h

@@ -1,59 +0,0 @@
-#pragma once
-////////////////////////////////////////////////////////////////////////////////
-#include <imgui/imgui.h>
-#include <imgui/imgui_internal.h>
-#include <imguizmo/ImGuizmo.h>
-#include <Eigen/Dense>
-#include <vector>
-////////////////////////////////////////////////////////////////////////////////
-
-namespace igl
-{
-namespace opengl
-{
-namespace glfw
-{
-namespace imgui
-{
-
-void EditTransform(const float *cameraView, const float *cameraProjection, float* matrix, bool isOrthographic)
-{
-	static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
-        // Alec: This could be a parameter ImGuizmo::WORLD will make senze in some
-        // circumstances. For now, 109_ImGuizmo and my other use cases make more
-        // sense in LOCAL mode.
-	static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL);
-
-        // Maya-style key bindings
-	if (ImGui::IsKeyPressed('W'))
-		mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
-	if (ImGui::IsKeyPressed('E'))
-		mCurrentGizmoOperation = ImGuizmo::ROTATE;
-	if (ImGui::IsKeyPressed('R'))
-		mCurrentGizmoOperation = ImGuizmo::SCALE;
-
-	if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
-		mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
-	ImGui::SameLine();
-	if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
-		mCurrentGizmoOperation = ImGuizmo::ROTATE;
-	ImGui::SameLine();
-	if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
-		mCurrentGizmoOperation = ImGuizmo::SCALE;
-
-	float matrixTranslation[3], matrixRotation[3], matrixScale[3];
-	ImGuizmo::DecomposeMatrixToComponents(matrix, matrixTranslation, matrixRotation, matrixScale);
-	ImGui::InputFloat3("Tr", matrixTranslation, 3);
-	ImGui::InputFloat3("Rt", matrixRotation, 3);
-	ImGui::InputFloat3("Sc", matrixScale, 3);
-	ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix);
-
-	ImGuiIO& io = ImGui::GetIO();
-	ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
-	ImGuizmo::Manipulate(cameraView, cameraProjection, mCurrentGizmoOperation, mCurrentGizmoMode, matrix, NULL, NULL);
-}
-
-} // end namespace
-} // end namespace
-} // end namespace
-} // end namespace

+ 49 - 0
include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp

@@ -0,0 +1,49 @@
+#include "ImGuizmoPlugin.h"
+#include <imgui/imgui.h>
+#include <imgui_impl_glfw.h>
+#include <imgui_impl_opengl3.h>
+#include <imgui_fonts_droid_sans.h>
+#include <GLFW/glfw3.h>
+
+namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
+
+IGL_INLINE void ImGuizmoPlugin::init(igl::opengl::glfw::Viewer *_viewer)
+{
+  ImGuiMenu::init(_viewer);
+}
+IGL_INLINE bool ImGuizmoPlugin::pre_draw() 
+{
+  ImGuiMenu::pre_draw();
+  ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
+  ImGuizmo::BeginFrame();
+  ImGui::PopStyleVar();
+  return false;
+}
+IGL_INLINE bool ImGuizmoPlugin::post_draw() 
+{
+  // Don't draw the Viewer's default menu: draw just the ImGuizmo
+  Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom);
+  Eigen::Matrix4f proj = viewer->core().proj;
+  if(viewer->core().orthographic){ view(2,3) -= 1000;/* Hack depth */ }
+  // ImGuizmo doesn't like a lot of scaling in view, shift it to T
+  const float z = viewer->core().camera_base_zoom;
+  const Eigen::Matrix4f S = 
+    (Eigen::Matrix4f()<< z,0,0,0, 0,z,0,0, 0,0,z,0, 0,0,0,1).finished();
+  view = (view * S.inverse()).eval();
+  const Eigen::Matrix4f T0 = T;
+  T = (S * T).eval();
+  ImGuiIO& io = ImGui::GetIO();
+  ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
+  ImGuizmo::Manipulate(
+    view.data(),proj.data(),operation,ImGuizmo::LOCAL,T.data(),NULL,NULL);
+  // invert scaling that was shifted onto T
+  T = (S.inverse() * T).eval();
+  const float diff = (T-T0).array().abs().maxCoeff();
+  // Only call if actually changed; otherwise, triggers on all mouse events
+  if( diff > 1e-7) { callback(T); }
+  ImGui::Render();
+  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
+  return false;
+}
+
+}}}}

+ 37 - 0
include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h

@@ -0,0 +1,37 @@
+#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H
+#define IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H
+#include "../../../igl_inline.h"
+#include "ImGuiMenu.h"
+#include <imgui/imgui.h>
+#include <imgui/imgui_internal.h>
+#include <imguizmo/ImGuizmo.h>
+#include <Eigen/Dense>
+
+namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
+
+class ImGuizmoPlugin : public igl::opengl::glfw::imgui::ImGuiMenu
+{
+public:
+  // callback(T) called when the stored transform T changes
+  std::function<void(const Eigen::Matrix4f &)> callback;
+  // whether rotating, translating or scaling
+  ImGuizmo::OPERATION operation;
+  // stored transformation
+  Eigen::Matrix4f T;
+  // Initilize with rotate operation on an identity transform (at origin)
+  ImGuizmoPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){};
+  /////////////////////////////////////////////////////////////////////////////
+  // Boilerplate
+  virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
+  virtual bool pre_draw() override;
+  /////////////////////////////////////////////////////////////////////////////
+  virtual bool post_draw() override;
+};
+
+}}}}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "ImGuizmoPlugin.cpp"
+#endif
+
+#endif

+ 44 - 92
tutorial/109_ImGuizmo/main.cpp

@@ -1,101 +1,53 @@
+#include <igl/read_triangle_mesh.h>
 #include <igl/opengl/glfw/Viewer.h>
-#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
-#include <igl/opengl/glfw/imgui/ImGuizmo.h>
-#include <imgui_impl_glfw.h>
-#include <imgui_impl_opengl3.h>
+#include <igl/opengl/glfw/imgui/ImGuizmoPlugin.h>
 #include <GLFW/glfw3.h>
 #include <imgui/imgui.h>
-#include "tutorial_shared_path.h"
+#include <imgui/imgui_internal.h>
+#include <imgui_impl_glfw.h>
+#include <imgui_impl_opengl3.h>
+#include <imguizmo/ImGuizmo.h>
 
-class SlicingPlugin : public igl::opengl::glfw::imgui::ImGuiMenu
+int main(int argc, char *argv[])
 {
-  igl::opengl::ViewerData data;
-  // Hard Coded Plane Mesh
-  const Eigen::MatrixXd OV = (Eigen::MatrixXd(4, 3) <<
-    -0.5, -0.5, 0.0,
-    -0.5,  0.5, 0.0,
-    0.5,  0.5, 0.0,
-    0.5, -0.5, 0.0).finished();
-  const Eigen::MatrixXi OF = (Eigen::MatrixXi(2, 3) <<
-    0, 2, 1,
-    0, 3, 2).finished();
-
-  virtual void init(igl::opengl::glfw::Viewer *_viewer) override
+  // Load a mesh from file
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
+  igl::read_triangle_mesh(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/cow.off",V,F);
+  // Set up viewer
+  igl::opengl::glfw::Viewer vr;
+  vr.data().set_mesh(V,F);
+  // Custom menu
+  igl::opengl::glfw::imgui::ImGuizmoPlugin plugin;
+  vr.plugins.push_back(&plugin);
+  // Initialize ImGuizmo at mesh centroid
+  plugin.T.block(0,3,3,1) = 
+    0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff()).transpose().cast<float>();
+  // Update can be applied relative to this remembered initial transform
+  const Eigen::Matrix4f T0 = plugin.T;
+  // Attach callback to apply imguizmo's transform to mesh
+  plugin.callback = [&](const Eigen::Matrix4f & T)
   {
-    ImGuiMenu::init(_viewer);
-    // Load slicing plane into viewer (a square mesh)
-    data.set_mesh(SlicingPlugin::OV, SlicingPlugin::OF);
-    data.set_face_based(true);
-    data.set_colors(Eigen::RowVector4d(224, 86, 253, 128)/255.0);
-    data.show_lines = false;
-  }
-
-  virtual bool pre_draw() override {
-    ImGuiMenu::pre_draw();
-    ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
-    ImGuizmo::BeginFrame();
-    ImGui::PopStyleVar();
-    return false;
-  }
-
-  virtual bool post_draw() override {
-    viewer->core().draw(data);
-    ImGuiMenu::post_draw();
-    return false;
-  }
-
-  virtual void draw_custom_window() override {
-    float menu_width = 180.f * menu_scaling();
-    ImGui::SetNextWindowPos(ImVec2(menu_width, 0.0f), ImGuiCond_FirstUseEver);
-    ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver);
-    ImGui::SetNextWindowSizeConstraints(ImVec2(1.5f * menu_width, -1.0f), ImVec2(1.5f * menu_width, -1.0f));
-    bool _guizmo_menu_visible = true;
-    ImGui::Begin(
-      "ImGuizmo Tools", &_guizmo_menu_visible,
-      ImGuiWindowFlags_NoSavedSettings
-      | ImGuiWindowFlags_AlwaysAutoResize
-    );
-
-    draw_imguizmo_menu();
-
-    ImGui::End();
-  }
-
-  virtual void draw_imguizmo_menu() {
-    static Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();
-    const float z = viewer->core().camera_base_zoom;
-    Eigen::Affine3f rescale = Eigen::Scaling(0.5f * z)
-      * Eigen::Translation3f(viewer->core().camera_base_translation);
-    Eigen::Affine3f view = Eigen::Affine3f( viewer->core().view * 1./viewer->core().camera_zoom ) * rescale.inverse();
-    Eigen::Matrix4f proj = viewer->core().proj;
-    if(viewer->core().orthographic)
+    const Eigen::Matrix4d TT = (T*T0.inverse()).cast<double>().transpose();
+    vr.data().set_vertices(
+      (V.rowwise().homogeneous()*TT).rowwise().hnormalized());
+    vr.data().compute_normals();
+  };
+  // Maya-style keyboard shortcuts for operation
+  vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
+  {
+    switch(key)
     {
-      view(2,3) -= 50; // Adjust depth for view transform
+      case 'W': case 'w': plugin.operation = ImGuizmo::TRANSLATE; return true;
+      case 'E': case 'e': plugin.operation = ImGuizmo::ROTATE;    return true;
+      case 'R': case 'r': plugin.operation = ImGuizmo::SCALE;     return true;
     }
-
-    igl::opengl::glfw::imgui::EditTransform(view.matrix().data(), proj.data(), matrix.data(), viewer->core().orthographic);
-
-    // Transform the slicing plane according to
-    // ImGuizmo tool manipulations in the viewer
-    Eigen::Affine3f model = Eigen::Affine3f(rescale.inverse()*matrix);
-    Eigen::MatrixXd V = (SlicingPlugin::OV.rowwise().homogeneous()
-      * model.matrix().cast<double>().transpose()).rowwise().hnormalized();
-
-    if (data.V.rows() == V.rows())
-      data.set_vertices(V);
-  }
-
-};
-
-int main(int argc, char *argv[])
-{
-  // Plot the mesh
-  igl::opengl::glfw::Viewer viewer;
-  viewer.load_mesh_from_file(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/cow.off");
-
-  // Custom menu
-  SlicingPlugin menu;
-  viewer.plugins.push_back(&menu);
-
-  viewer.launch();
+    return false;
+  };
+  std::cout<<R"(
+W,w  Switch to translate operation
+E,e  Switch to rotate operation
+R,r  Switch to scale operation
+)";
+  vr.launch();
 }