main.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #include <igl/kelvinlets.h>
  2. #include <igl/opengl/glfw/Viewer.h>
  3. #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
  4. #include <igl/readOFF.h>
  5. #include <igl/unproject.h>
  6. #include <igl/unproject_onto_mesh.h>
  7. #include <imgui/imgui.h>
  8. #include <iostream>
  9. namespace {
  10. void ShowHelpMarker(const char* desc)
  11. {
  12. ImGui::SameLine();
  13. ImGui::TextDisabled("(?)");
  14. if (ImGui::IsItemHovered()) {
  15. ImGui::BeginTooltip();
  16. ImGui::PushTextWrapPos(450.0f);
  17. ImGui::TextUnformatted(desc);
  18. ImGui::PopTextWrapPos();
  19. ImGui::EndTooltip();
  20. }
  21. }
  22. }
  23. int main()
  24. {
  25. Eigen::MatrixXd V1, OrigV;
  26. Eigen::MatrixXi F1, OrigF;
  27. igl::readOFF(TUTORIAL_SHARED_PATH "/bumpy.off", OrigV, OrigF);
  28. std::cout << "1 View original mesh\n";
  29. std::cout << "2 Switch to deformed mesh\n";
  30. V1 = OrigV;
  31. F1 = OrigF;
  32. igl::opengl::glfw::Viewer viewer;
  33. igl::opengl::glfw::imgui::ImGuiMenu menu;
  34. viewer.plugins.push_back(&menu);
  35. auto brushRadius = 1.;
  36. auto brushType = igl::BrushType::GRAB;
  37. auto scale = 1;
  38. menu.callback_draw_custom_window = [&]() {
  39. ImGui::SetNextWindowPos(ImVec2(180.f * menu.menu_scaling(), 10),
  40. ImGuiCond_FirstUseEver);
  41. ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiCond_FirstUseEver);
  42. ImGui::Begin(
  43. "Kelvinlet Brushes", nullptr, ImGuiWindowFlags_NoSavedSettings);
  44. ImGui::InputDouble("Brush Radius", &brushRadius, 0, 0, "%.4f");
  45. ImGui::Combo("Brush type",
  46. reinterpret_cast<int*>(&brushType),
  47. "Grab\0Scale\0Twist\0Pinch\0\0");
  48. ImGui::InputInt("Falloff", &scale);
  49. ShowHelpMarker("Defines how localized the stroke is {1,2,3}");
  50. ImGui::End();
  51. };
  52. Eigen::Vector3d posStart(0, 0, 0);
  53. Eigen::Vector3d posEnd;
  54. decltype(OrigV) result;
  55. auto min_point = V1.colwise().minCoeff();
  56. auto max_point = V1.colwise().maxCoeff();
  57. // to multiply brush force proportional to size of mesh
  58. auto brush_strength = (max_point - min_point).norm();
  59. Eigen::Matrix3d twist, pinch;
  60. twist << 0, 1, -1, -1, 0, 1, 1, -1, 0; // skew-symmetric
  61. pinch << 0, 1, 1, 1, 0, 1, 1, 1, 0; // symmetric
  62. viewer.callback_key_down =
  63. [&](igl::opengl::glfw::Viewer& viewer, unsigned char key, int) {
  64. std::cout << "Key: " << key << " " << (unsigned int)key << std::endl;
  65. if (key == '1') {
  66. viewer.data().clear();
  67. viewer.data().set_mesh(OrigV, OrigF);
  68. viewer.core().align_camera_center(OrigV, OrigF);
  69. } else if (key == '2') {
  70. viewer.data().clear();
  71. viewer.data().set_mesh(V1, F1);
  72. viewer.core().align_camera_center(V1, F1);
  73. }
  74. return false;
  75. };
  76. viewer.callback_mouse_down =
  77. [&](igl::opengl::glfw::Viewer& viewer, int, int) -> bool {
  78. Eigen::Vector3f bc;
  79. int fid;
  80. auto x = viewer.current_mouse_x;
  81. auto y =
  82. viewer.core().viewport(3) - static_cast<float>(viewer.current_mouse_y);
  83. if (igl::unproject_onto_mesh(Eigen::Vector2f(x, y),
  84. viewer.core().view,
  85. viewer.core().proj,
  86. viewer.core().viewport,
  87. V1,
  88. F1,
  89. fid,
  90. bc)) {
  91. posStart = igl::unproject(Eigen::Vector3f(x, y, viewer.down_mouse_z),
  92. viewer.core().view,
  93. viewer.core().proj,
  94. viewer.core().viewport)
  95. .template cast<double>();
  96. return true;
  97. }
  98. return false;
  99. };
  100. viewer.callback_mouse_move =
  101. [&](igl::opengl::glfw::Viewer& viewer, int, int) -> bool {
  102. if (!posStart.isZero() && !posStart.hasNaN()) {
  103. posEnd = igl::unproject(
  104. Eigen::Vector3f(viewer.current_mouse_x,
  105. viewer.core().viewport[3] -
  106. static_cast<float>(viewer.current_mouse_y),
  107. viewer.down_mouse_z),
  108. viewer.core().view,
  109. viewer.core().proj,
  110. viewer.core().viewport)
  111. .template cast<double>();
  112. // exaggerate the force by a little bit
  113. Eigen::Vector3d forceVec = (posEnd - posStart) * brush_strength;
  114. int scaleFactor = forceVec.norm();
  115. if (posEnd.x() < posStart.x()) {
  116. // probably not the best way to determine direction.
  117. scaleFactor = -scaleFactor;
  118. }
  119. Eigen::Matrix3d mat;
  120. switch (brushType) {
  121. case igl::BrushType::GRAB:
  122. mat.setZero();
  123. break;
  124. case igl::BrushType::SCALE:
  125. mat = Eigen::Matrix3d::Identity() * scaleFactor;
  126. break;
  127. case igl::BrushType::TWIST:
  128. mat = twist * scaleFactor;
  129. break;
  130. case igl::BrushType::PINCH:
  131. mat = pinch * scaleFactor;
  132. break;
  133. }
  134. igl::kelvinlets(
  135. V1,
  136. posStart,
  137. forceVec,
  138. mat,
  139. igl::KelvinletParams<double>(brushRadius, scale, brushType),
  140. result);
  141. viewer.data().set_mesh(result, F1);
  142. viewer.core().align_camera_center(result, F1);
  143. return true;
  144. }
  145. return false;
  146. };
  147. viewer.callback_mouse_up =
  148. [&](igl::opengl::glfw::Viewer& viewer, int, int) -> bool {
  149. if (!posStart.isZero()) {
  150. V1 = result;
  151. posStart.setZero();
  152. return true;
  153. }
  154. return false;
  155. };
  156. viewer.data().set_mesh(V1, F1);
  157. viewer.core().align_camera_center(V1, F1);
  158. viewer.launch();
  159. }