main.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <igl/scaf.h>
  2. #include <igl/arap.h>
  3. #include <igl/boundary_loop.h>
  4. #include <igl/harmonic.h>
  5. #include <igl/map_vertices_to_circle.h>
  6. #include <igl/readOBJ.h>
  7. #include <igl/Timer.h>
  8. #include <igl/opengl/glfw/Viewer.h>
  9. #include <igl/MappingEnergyType.h>
  10. #include <igl/doublearea.h>
  11. #include <igl/PI.h>
  12. #include <igl/flipped_triangles.h>
  13. #include <igl/topological_hole_fill.h>
  14. #include "tutorial_shared_path.h"
  15. Eigen::MatrixXd V;
  16. Eigen::MatrixXi F;
  17. Eigen::MatrixXd V_uv;
  18. igl::Timer timer;
  19. igl::SCAFData scaf_data;
  20. bool show_uv = false;
  21. float uv_scale = 0.2;
  22. bool key_down(igl::opengl::glfw::Viewer& viewer, unsigned char key, int modifier)
  23. {
  24. if (key == '1')
  25. show_uv = false;
  26. else if (key == '2')
  27. show_uv = true;
  28. if (key == ' ')
  29. {
  30. timer.start();
  31. igl::scaf_solve(scaf_data, 1);
  32. std::cout << "time = " << timer.getElapsedTime() << std::endl;
  33. }
  34. const auto& V_uv = uv_scale * scaf_data.w_uv.topRows(V.rows());
  35. if (show_uv)
  36. {
  37. viewer.data().clear();
  38. viewer.data().set_mesh(V_uv,F);
  39. viewer.data().set_uv(V_uv);
  40. viewer.core().align_camera_center(V_uv,F);
  41. }
  42. else
  43. {
  44. viewer.data().set_mesh(V,F);
  45. viewer.data().set_uv(V_uv);
  46. viewer.core().align_camera_center(V,F);
  47. }
  48. viewer.data().compute_normals();
  49. return false;
  50. }
  51. int main(int argc, char *argv[])
  52. {
  53. using namespace std;
  54. // Load a mesh in OFF format
  55. igl::readOBJ(TUTORIAL_SHARED_PATH "/camel_b.obj", V, F);
  56. Eigen::MatrixXd bnd_uv, uv_init;
  57. Eigen::VectorXd M;
  58. igl::doublearea(V, F, M);
  59. std::vector<std::vector<int>> all_bnds;
  60. igl::boundary_loop(F, all_bnds);
  61. // Heuristic primary boundary choice: longest
  62. auto primary_bnd = std::max_element(all_bnds.begin(), all_bnds.end(), [](const std::vector<int> &a, const std::vector<int> &b) { return a.size()<b.size(); });
  63. Eigen::VectorXi bnd = Eigen::Map<Eigen::VectorXi>(primary_bnd->data(), primary_bnd->size());
  64. igl::map_vertices_to_circle(V, bnd, bnd_uv);
  65. bnd_uv *= sqrt(M.sum() / (2 * igl::PI));
  66. if (all_bnds.size() == 1)
  67. {
  68. if (bnd.rows() == V.rows()) // case: all vertex on boundary
  69. {
  70. uv_init.resize(V.rows(), 2);
  71. for (int i = 0; i < bnd.rows(); i++)
  72. uv_init.row(bnd(i)) = bnd_uv.row(i);
  73. }
  74. else
  75. {
  76. igl::harmonic(V, F, bnd, bnd_uv, 1, uv_init);
  77. if (igl::flipped_triangles(uv_init, F).size() != 0)
  78. igl::harmonic(F, bnd, bnd_uv, 1, uv_init); // fallback uniform laplacian
  79. }
  80. }
  81. else
  82. {
  83. // if there is a hole, fill it and erase additional vertices.
  84. all_bnds.erase(primary_bnd);
  85. Eigen::MatrixXi F_filled;
  86. igl::topological_hole_fill(F, bnd, all_bnds, F_filled);
  87. igl::harmonic(F_filled, bnd, bnd_uv ,1, uv_init);
  88. uv_init = uv_init.topRows(V.rows());
  89. }
  90. Eigen::VectorXi b; Eigen::MatrixXd bc;
  91. igl::scaf_precompute(V, F, uv_init, scaf_data, igl::MappingEnergyType::SYMMETRIC_DIRICHLET, b, bc, 0);
  92. // Plot the mesh
  93. igl::opengl::glfw::Viewer viewer;
  94. viewer.data().set_mesh(V, F);
  95. const auto& V_uv = uv_scale * scaf_data.w_uv.topRows(V.rows());
  96. viewer.data().set_uv(V_uv);
  97. viewer.callback_key_down = &key_down;
  98. // Enable wireframe
  99. viewer.data().show_lines = true;
  100. // Draw checkerboard texture
  101. viewer.data().show_texture = true;
  102. std::cerr << "Press space for running an iteration." << std::endl;
  103. std::cerr << "Press 1 for Mesh 2 for UV" << std::endl;
  104. // Launch the viewer
  105. viewer.launch();
  106. }