You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.4 KiB

#include <igl/kelvinlets.h>
#include <igl/opengl/glfw/Viewer.h>
#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
#include <igl/readOFF.h>
#include <igl/unproject.h>
#include <igl/unproject_onto_mesh.h>
#include <imgui.h>
#include <iostream>
namespace {
void ShowHelpMarker(const char* desc)
{
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(450.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
}
int main()
{
Eigen::MatrixXd V1, OrigV;
Eigen::MatrixXi F1, OrigF;
igl::readOFF(TUTORIAL_SHARED_PATH "/bumpy.off", OrigV, OrigF);
std::cout << "1 View original mesh\n";
std::cout << "2 Switch to deformed mesh\n";
V1 = OrigV;
F1 = OrigF;
igl::opengl::glfw::Viewer viewer;
igl::opengl::glfw::imgui::ImGuiPlugin plugin;
viewer.plugins.push_back(&plugin);
igl::opengl::glfw::imgui::ImGuiMenu menu;
plugin.widgets.push_back(&menu);
auto brushRadius = 1.;
auto brushType = igl::BrushType::GRAB;
auto scale = 1;
menu.callback_draw_custom_window = [&]() {
ImGui::SetNextWindowPos(ImVec2(180.f * menu.menu_scaling(), 10),
ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiCond_FirstUseEver);
ImGui::Begin(
"Kelvinlet Brushes", nullptr, ImGuiWindowFlags_NoSavedSettings);
ImGui::InputDouble("Brush Radius", &brushRadius, 0, 0, "%.4f");
ImGui::Combo("Brush type",
reinterpret_cast<int*>(&brushType),
"Grab\0Scale\0Twist\0Pinch\0\0");
ImGui::InputInt("Falloff", &scale);
ShowHelpMarker("Defines how localized the stroke is {1,2,3}");
ImGui::End();
};
Eigen::Vector3d posStart(0, 0, 0);
Eigen::Vector3d posEnd;
decltype(OrigV) result;
auto min_point = V1.colwise().minCoeff();
auto max_point = V1.colwise().maxCoeff();
// to multiply brush force proportional to size of mesh
auto brush_strength = (max_point - min_point).norm();
Eigen::Matrix3d twist, pinch;
twist << 0, 1, -1, -1, 0, 1, 1, -1, 0; // skew-symmetric
pinch << 0, 1, 1, 1, 0, 1, 1, 1, 0; // symmetric
viewer.callback_key_down =
[&](igl::opengl::glfw::Viewer& viewer, unsigned char key, int) {
if (key == '1') {
viewer.data().clear();
viewer.data().set_mesh(OrigV, OrigF);
viewer.core().align_camera_center(OrigV, OrigF);
} else if (key == '2') {
viewer.data().clear();
viewer.data().set_mesh(V1, F1);
viewer.core().align_camera_center(V1, F1);
}
return false;
};
viewer.callback_mouse_down =
[&](igl::opengl::glfw::Viewer& viewer, int, int) -> bool {
Eigen::Vector3f bc;
int fid;
auto x = viewer.current_mouse_x;
auto y =
viewer.core().viewport(3) - static_cast<float>(viewer.current_mouse_y);
if (igl::unproject_onto_mesh(Eigen::Vector2f(x, y),
viewer.core().view,
viewer.core().proj,
viewer.core().viewport,
V1,
F1,
fid,
bc)) {
posStart = igl::unproject(Eigen::Vector3f(x, y, viewer.down_mouse_z),
viewer.core().view,
viewer.core().proj,
viewer.core().viewport)
.template cast<double>();
return true;
}
return false;
};
viewer.callback_mouse_move =
[&](igl::opengl::glfw::Viewer& viewer, int, int) -> bool {
if (!posStart.isZero() && !posStart.hasNaN()) {
posEnd = igl::unproject(
Eigen::Vector3f(viewer.current_mouse_x,
viewer.core().viewport[3] -
static_cast<float>(viewer.current_mouse_y),
viewer.down_mouse_z),
viewer.core().view,
viewer.core().proj,
viewer.core().viewport)
.template cast<double>();
// exaggerate the force by a little bit
Eigen::Vector3d forceVec = (posEnd - posStart) * brush_strength;
int scaleFactor = forceVec.norm();
if (posEnd.x() < posStart.x()) {
// probably not the best way to determine direction.
scaleFactor = -scaleFactor;
}
Eigen::Matrix3d mat;
switch (brushType) {
case igl::BrushType::GRAB:
mat.setZero();
break;
case igl::BrushType::SCALE:
mat = Eigen::Matrix3d::Identity() * scaleFactor;
break;
case igl::BrushType::TWIST:
mat = twist * scaleFactor;
break;
case igl::BrushType::PINCH:
mat = pinch * scaleFactor;
break;
}
igl::kelvinlets(
V1,
posStart,
forceVec,
mat,
igl::KelvinletParams<double>(brushRadius, scale, brushType),
result);
viewer.data().set_vertices(result);
viewer.data().compute_normals();
return true;
}
return false;
};
viewer.callback_mouse_up =
[&](igl::opengl::glfw::Viewer& viewer, int, int) -> bool {
if (!posStart.isZero()) {
V1 = result;
posStart.setZero();
return true;
}
return false;
};
viewer.data().set_mesh(V1, F1);
viewer.core().align_camera_center(V1, F1);
viewer.launch();
}