move ImGuizmo tutorial into plugin; simplify and isolate
This commit is contained in:
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}}}}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
class SlicingPlugin : public igl::opengl::glfw::imgui::ImGuiMenu
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
view(2,3) -= 50; // Adjust depth for view transform
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
};
|
||||
#include <imgui/imgui_internal.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imguizmo/ImGuizmo.h>
|
||||
|
||||
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");
|
||||
|
||||
// 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
|
||||
SlicingPlugin menu;
|
||||
viewer.plugins.push_back(&menu);
|
||||
|
||||
viewer.launch();
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user