main.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #include <iostream>
  2. #include <igl/slim.h>
  3. #include <igl/vertex_components.h>
  4. #include <igl/readOBJ.h>
  5. #include <igl/writeOBJ.h>
  6. #include <igl/Timer.h>
  7. #include <igl/boundary_loop.h>
  8. #include <igl/map_vertices_to_circle.h>
  9. #include <igl/harmonic.h>
  10. #include <igl/MappingEnergyType.h>
  11. #include <igl/serialize.h>
  12. #include <igl/read_triangle_mesh.h>
  13. #include <igl/opengl/glfw/Viewer.h>
  14. #include <igl/flipped_triangles.h>
  15. #include <igl/euler_characteristic.h>
  16. #include <igl/barycenter.h>
  17. #include <igl/adjacency_matrix.h>
  18. #include <igl/is_edge_manifold.h>
  19. #include <igl/doublearea.h>
  20. #include <igl/cat.h>
  21. #include <igl/PI.h>
  22. #include <stdlib.h>
  23. #include <string>
  24. #include <vector>
  25. using namespace std;
  26. using namespace Eigen;
  27. void check_mesh_for_issues(Eigen::MatrixXd& V, Eigen::MatrixXi& F);
  28. void param_2d_demo_iter(igl::opengl::glfw::Viewer& viewer);
  29. void get_soft_constraint_for_circle(Eigen::MatrixXd& V_o, Eigen::MatrixXi& F, Eigen::VectorXi& b, Eigen::MatrixXd& bc);
  30. void soft_const_demo_iter(igl::opengl::glfw::Viewer& viewer);
  31. void deform_3d_demo_iter(igl::opengl::glfw::Viewer& viewer);
  32. void get_cube_corner_constraints(Eigen::MatrixXd& V_o, Eigen::MatrixXi& F, Eigen::VectorXi& b, Eigen::MatrixXd& bc);
  33. void display_3d_mesh(igl::opengl::glfw::Viewer& viewer);
  34. void int_set_to_eigen_vector(const std::set<int>& int_set, Eigen::VectorXi& vec);
  35. Eigen::MatrixXd V;
  36. Eigen::MatrixXi F;
  37. bool first_iter = true;
  38. igl::SLIMData sData;
  39. igl::Timer timer;
  40. double uv_scale_param;
  41. enum DEMO_TYPE {
  42. PARAM_2D,
  43. SOFT_CONST,
  44. DEFORM_3D
  45. };
  46. DEMO_TYPE demo_type;
  47. bool key_down(igl::opengl::glfw::Viewer& viewer, unsigned char key, int modifier){
  48. if (key == ' ') {
  49. switch (demo_type) {
  50. case PARAM_2D: {
  51. param_2d_demo_iter(viewer);
  52. break;
  53. }
  54. case SOFT_CONST: {
  55. soft_const_demo_iter(viewer);
  56. break;
  57. }
  58. case DEFORM_3D: {
  59. deform_3d_demo_iter(viewer);
  60. break;
  61. }
  62. default:
  63. break;
  64. }
  65. }
  66. return false;
  67. }
  68. void param_2d_demo_iter(igl::opengl::glfw::Viewer& viewer) {
  69. if (first_iter) {
  70. timer.start();
  71. igl::read_triangle_mesh(TUTORIAL_SHARED_PATH "/face.obj", V, F);
  72. check_mesh_for_issues(V,F);
  73. cout << "\tMesh is valid!" << endl;
  74. Eigen::MatrixXd uv_init;
  75. Eigen::VectorXi bnd; Eigen::MatrixXd bnd_uv;
  76. igl::boundary_loop(F,bnd);
  77. igl::map_vertices_to_circle(V,bnd,bnd_uv);
  78. igl::harmonic(V,F,bnd,bnd_uv,1,uv_init);
  79. if (igl::flipped_triangles(uv_init,F).size() != 0) {
  80. igl::harmonic(F,bnd,bnd_uv,1,uv_init); // use uniform laplacian
  81. }
  82. cout << "initialized parametrization" << endl;
  83. sData.slim_energy = igl::MappingEnergyType::SYMMETRIC_DIRICHLET;
  84. Eigen::VectorXi b; Eigen::MatrixXd bc;
  85. slim_precompute(V,F,uv_init,sData, igl::MappingEnergyType::SYMMETRIC_DIRICHLET, b,bc,0);
  86. uv_scale_param = 15 * (1./sqrt(sData.mesh_area));
  87. viewer.data().set_mesh(V, F);
  88. viewer.core().align_camera_center(V,F);
  89. viewer.data().set_uv(sData.V_o*uv_scale_param);
  90. viewer.data().compute_normals();
  91. viewer.data().show_texture = true;
  92. first_iter = false;
  93. } else {
  94. timer.start();
  95. slim_solve(sData,1); // 1 iter
  96. viewer.data().set_uv(sData.V_o*uv_scale_param);
  97. }
  98. cout << "time = " << timer.getElapsedTime() << endl;
  99. cout << "energy = " << sData.energy << endl;
  100. }
  101. void soft_const_demo_iter(igl::opengl::glfw::Viewer& viewer) {
  102. if (first_iter) {
  103. igl::read_triangle_mesh(TUTORIAL_SHARED_PATH "/circle.obj", V, F);
  104. check_mesh_for_issues(V,F);
  105. cout << "\tMesh is valid!" << endl;
  106. Eigen::MatrixXd V_0 = V.block(0,0,V.rows(),2);
  107. Eigen::VectorXi b; Eigen::MatrixXd bc;
  108. get_soft_constraint_for_circle(V_0,F,b,bc);
  109. double soft_const_p = 1e5;
  110. slim_precompute(V,F,V_0,sData,igl::MappingEnergyType::SYMMETRIC_DIRICHLET,b,bc,soft_const_p);
  111. viewer.data().set_mesh(V, F);
  112. viewer.core().align_camera_center(V,F);
  113. viewer.data().compute_normals();
  114. viewer.data().show_lines = true;
  115. first_iter = false;
  116. } else {
  117. slim_solve(sData,1); // 1 iter
  118. viewer.data().set_mesh(sData.V_o, F);
  119. }
  120. }
  121. void deform_3d_demo_iter(igl::opengl::glfw::Viewer& viewer) {
  122. if (first_iter) {
  123. timer.start();
  124. igl::readOBJ(TUTORIAL_SHARED_PATH "/cube_40k.obj", V, F);
  125. Eigen::MatrixXd V_0 = V;
  126. Eigen::VectorXi b; Eigen::MatrixXd bc;
  127. get_cube_corner_constraints(V_0,F,b,bc);
  128. double soft_const_p = 1e5;
  129. sData.exp_factor = 5.0;
  130. slim_precompute(V,F,V_0,sData,igl::MappingEnergyType::EXP_CONFORMAL,b,bc,soft_const_p);
  131. //cout << "precomputed" << endl;
  132. first_iter = false;
  133. display_3d_mesh(viewer);
  134. } else {
  135. timer.start();
  136. slim_solve(sData,1); // 1 iter
  137. display_3d_mesh(viewer);
  138. }
  139. cout << "time = " << timer.getElapsedTime() << endl;
  140. cout << "energy = " << sData.energy << endl;
  141. }
  142. void display_3d_mesh(igl::opengl::glfw::Viewer& viewer) {
  143. MatrixXd V_temp; MatrixXi F_temp;
  144. Eigen::MatrixXd Barycenters;
  145. igl::barycenter(sData.V,sData.F,Barycenters);
  146. //cout << "Barycenters.rows() = " << Barycenters.rows() << endl;
  147. //double t = double((key - '1')+1) / 9.0;
  148. double view_depth = 10.;
  149. double t = view_depth/9.;
  150. VectorXd v = Barycenters.col(2).array() - Barycenters.col(2).minCoeff();
  151. v /= v.col(0).maxCoeff();
  152. vector<int> s;
  153. for (unsigned i=0; i<v.size();++i)
  154. if (v(i) < t)
  155. s.push_back(i);
  156. V_temp.resize(s.size()*4,3);
  157. F_temp.resize(s.size()*4,3);
  158. for (unsigned i=0; i<s.size();++i){
  159. V_temp.row(i*4+0) = sData.V_o.row(sData.F(s[i],0));
  160. V_temp.row(i*4+1) = sData.V_o.row(sData.F(s[i],1));
  161. V_temp.row(i*4+2) = sData.V_o.row(sData.F(s[i],2));
  162. V_temp.row(i*4+3) = sData.V_o.row(sData.F(s[i],3));
  163. F_temp.row(i*4+0) << (i*4)+0, (i*4)+1, (i*4)+3;
  164. F_temp.row(i*4+1) << (i*4)+0, (i*4)+2, (i*4)+1;
  165. F_temp.row(i*4+2) << (i*4)+3, (i*4)+2, (i*4)+0;
  166. F_temp.row(i*4+3) << (i*4)+1, (i*4)+2, (i*4)+3;
  167. }
  168. viewer.data().set_mesh(V_temp,F_temp);
  169. viewer.core().align_camera_center(V_temp,F_temp);
  170. viewer.data().set_face_based(true);
  171. viewer.data().show_lines = true;
  172. }
  173. int main(int argc, char *argv[]) {
  174. cerr << "Press space for running an iteration." << std::endl;
  175. cerr << "Syntax: " << argv[0] << " demo_number (1 to 3)" << std::endl;
  176. cerr << "1. 2D unconstrained parametrization" << std::endl;
  177. cerr << "2. 2D deformation with positional constraints" << std::endl;
  178. cerr << "3. 3D mesh deformation with positional constraints" << std::endl;
  179. demo_type = PARAM_2D;
  180. if (argc == 2) {
  181. switch (std::atoi(argv[1])) {
  182. case 1: {
  183. demo_type = PARAM_2D;
  184. break;
  185. } case 2: {
  186. demo_type = SOFT_CONST;
  187. break;
  188. } case 3: {
  189. demo_type = DEFORM_3D;
  190. break;
  191. }
  192. default: {
  193. cerr << "Wrong demo number - Please choose one between 1-3" << std:: endl;
  194. exit(1);
  195. }
  196. }
  197. }
  198. // Launch the viewer
  199. igl::opengl::glfw::Viewer viewer;
  200. viewer.callback_key_down = &key_down;
  201. // Disable wireframe
  202. viewer.data().show_lines = false;
  203. // Draw checkerboard texture
  204. viewer.data().show_texture = false;
  205. // First iteration
  206. key_down(viewer, ' ', 0);
  207. viewer.launch();
  208. return 0;
  209. }
  210. void check_mesh_for_issues(Eigen::MatrixXd& V, Eigen::MatrixXi& F) {
  211. Eigen::SparseMatrix<double> A;
  212. igl::adjacency_matrix(F,A);
  213. Eigen::MatrixXi C, Ci;
  214. igl::vertex_components(A, C, Ci);
  215. int connected_components = Ci.rows();
  216. if (connected_components!=1) {
  217. cout << "Error! Input has multiple connected components" << endl; exit(1);
  218. }
  219. int euler_char = igl::euler_characteristic(V, F);
  220. if (euler_char!=1)
  221. {
  222. cout <<
  223. "Error! Input does not have a disk topology, it's euler char is " <<
  224. euler_char << endl;
  225. exit(1);
  226. }
  227. bool is_edge_manifold = igl::is_edge_manifold(F);
  228. if (!is_edge_manifold) {
  229. cout << "Error! Input is not an edge manifold" << endl; exit(1);
  230. }
  231. Eigen::VectorXd areas; igl::doublearea(V,F,areas);
  232. const double eps = 1e-14;
  233. for (int i = 0; i < areas.rows(); i++) {
  234. if (areas(i) < eps) {
  235. cout << "Error! Input has zero area faces" << endl; exit(1);
  236. }
  237. }
  238. }
  239. void get_soft_constraint_for_circle(Eigen::MatrixXd& V_o, Eigen::MatrixXi& F, Eigen::VectorXi& b, Eigen::MatrixXd& bc) {
  240. Eigen::VectorXi bnd;
  241. igl::boundary_loop(F,bnd);
  242. const int B_STEPS = 22; // constraint every B_STEPS vertices of the boundary
  243. b.resize(bnd.rows()/B_STEPS);
  244. bc.resize(b.rows(),2);
  245. int c_idx = 0;
  246. for (int i = B_STEPS; i < bnd.rows(); i+=B_STEPS) {
  247. b(c_idx) = bnd(i);
  248. c_idx++;
  249. }
  250. bc.row(0) = V_o.row(b(0)); // keep it there for now
  251. bc.row(1) = V_o.row(b(2));
  252. bc.row(2) = V_o.row(b(3));
  253. bc.row(3) = V_o.row(b(4));
  254. bc.row(4) = V_o.row(b(5));
  255. bc.row(0) << V_o(b(0),0), 0;
  256. bc.row(4) << V_o(b(4),0), 0;
  257. bc.row(2) << V_o(b(2),0), 0.1;
  258. bc.row(3) << V_o(b(3),0), 0.05;
  259. bc.row(1) << V_o(b(1),0), -0.15;
  260. bc.row(5) << V_o(b(5),0), +0.15;
  261. }
  262. void get_cube_corner_constraints(Eigen::MatrixXd& V, Eigen::MatrixXi& F, Eigen::VectorXi& b, Eigen::MatrixXd& bc) {
  263. double min_x,max_x,min_y,max_y,min_z,max_z;
  264. min_x = V.col(0).minCoeff(); max_x = V.col(0).maxCoeff();
  265. min_y = V.col(1).minCoeff(); max_y = V.col(1).maxCoeff();
  266. min_z = V.col(2).minCoeff(); max_z = V.col(2).maxCoeff();
  267. // get all cube corners
  268. b.resize(8,1); bc.resize(8,3);
  269. int x;
  270. for (int i = 0; i < V.rows(); i++) {
  271. if (V.row(i) == Eigen::RowVector3d(min_x,min_y,min_z)) b(0) = i;
  272. if (V.row(i) == Eigen::RowVector3d(min_x,min_y,max_z)) b(1) = i;
  273. if (V.row(i) == Eigen::RowVector3d(min_x,max_y,min_z)) b(2) = i;
  274. if (V.row(i) == Eigen::RowVector3d(min_x,max_y,max_z)) b(3) = i;
  275. if (V.row(i) == Eigen::RowVector3d(max_x,min_y,min_z)) b(4) = i;
  276. if (V.row(i) == Eigen::RowVector3d(max_x,max_y,min_z)) b(5) = i;
  277. if (V.row(i) == Eigen::RowVector3d(max_x,min_y,max_z)) b(6) = i;
  278. if (V.row(i) == Eigen::RowVector3d(max_x,max_y,max_z)) b(7) = i;
  279. }
  280. // get all cube edges
  281. std::set<int> cube_edge1; Eigen::VectorXi cube_edge1_vec;
  282. for (int i = 0; i < V.rows(); i++) {
  283. if ((V(i,0) == min_x && V(i,1) == min_y)) {
  284. cube_edge1.insert(i);
  285. }
  286. }
  287. Eigen::VectorXi edge1;
  288. int_set_to_eigen_vector(cube_edge1, edge1);
  289. std::set<int> cube_edge2; Eigen::VectorXi edge2;
  290. for (int i = 0; i < V.rows(); i++) {
  291. if ((V(i,0) == max_x && V(i,1) == max_y)) {
  292. cube_edge2.insert(i);
  293. }
  294. }
  295. int_set_to_eigen_vector(cube_edge2, edge2);
  296. b = igl::cat(1,edge1,edge2);
  297. std::set<int> cube_edge3; Eigen::VectorXi edge3;
  298. for (int i = 0; i < V.rows(); i++) {
  299. if ((V(i,0) == max_x && V(i,1) == min_y)) {
  300. cube_edge3.insert(i);
  301. }
  302. }
  303. int_set_to_eigen_vector(cube_edge3, edge3);
  304. b = igl::cat(1,b,edge3);
  305. std::set<int> cube_edge4; Eigen::VectorXi edge4;
  306. for (int i = 0; i < V.rows(); i++) {
  307. if ((V(i,0) == min_x && V(i,1) == max_y)) {
  308. cube_edge4.insert(i);
  309. }
  310. }
  311. int_set_to_eigen_vector(cube_edge4, edge4);
  312. b = igl::cat(1,b,edge4);
  313. bc.resize(b.rows(),3);
  314. Eigen::Matrix3d m; m = Eigen::AngleAxisd(0.3 * igl::PI, Eigen::Vector3d(1./sqrt(2.),1./sqrt(2.),0.)/*Eigen::Vector3d::UnitX()*/);
  315. int i = 0;
  316. for (; i < cube_edge1.size(); i++) {
  317. Eigen::RowVector3d edge_rot_center(min_x,min_y,(min_z+max_z)/2.);
  318. bc.row(i) = (V.row(b(i)) - edge_rot_center) * m + edge_rot_center;
  319. }
  320. for (; i < cube_edge1.size() + cube_edge2.size(); i++) {
  321. Eigen::RowVector3d edge_rot_center(max_x,max_y,(min_z+max_z)/2.);
  322. bc.row(i) = (V.row(b(i)) - edge_rot_center) * m.transpose() + edge_rot_center;
  323. }
  324. for (; i < cube_edge1.size() + cube_edge2.size() + cube_edge3.size(); i++) {
  325. bc.row(i) = 0.75*V.row(b(i));
  326. }
  327. for (; i < b.rows(); i++) {
  328. bc.row(i) = 0.75*V.row(b(i));
  329. }
  330. }
  331. void int_set_to_eigen_vector(const std::set<int>& int_set, Eigen::VectorXi& vec) {
  332. vec.resize(int_set.size()); int idx = 0;
  333. for(auto f : int_set) {
  334. vec(idx) = f; idx++;
  335. }
  336. }