main.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include <igl/opengl/gl.h>
  2. #include <igl/arap.h>
  3. #include <igl/biharmonic_coordinates.h>
  4. #include <igl/cat.h>
  5. #include <igl/cotmatrix.h>
  6. #include <igl/massmatrix.h>
  7. #include <igl/matrix_to_list.h>
  8. #include <igl/parula.h>
  9. #include <igl/point_mesh_squared_distance.h>
  10. #include <igl/readDMAT.h>
  11. #include <igl/readMESH.h>
  12. #include <igl/remove_unreferenced.h>
  13. #include <igl/slice.h>
  14. #include <igl/writeDMAT.h>
  15. #include <igl/opengl/glfw/Viewer.h>
  16. #include <Eigen/Sparse>
  17. #include <iostream>
  18. #include <queue>
  19. #include "tutorial_shared_path.h"
  20. struct Mesh
  21. {
  22. Eigen::MatrixXd V,U;
  23. Eigen::MatrixXi T,F;
  24. } low,high,scene;
  25. Eigen::MatrixXd W;
  26. igl::ARAPData arap_data;
  27. int main(int argc, char * argv[])
  28. {
  29. using namespace Eigen;
  30. using namespace std;
  31. using namespace igl;
  32. // read the mesh, if the code is prepared outside of tutorial, the TUTORIAL_SHARED_PATH
  33. // should be the data folder
  34. if(!readMESH(TUTORIAL_SHARED_PATH "/octopus-low.mesh",low.V,low.T,low.F))
  35. {
  36. cout<<"failed to load mesh"<<endl;
  37. }
  38. if(!readMESH(TUTORIAL_SHARED_PATH "/octopus-high.mesh",high.V,high.T,high.F))
  39. {
  40. cout<<"failed to load mesh"<<endl;
  41. }
  42. // Precomputation
  43. {
  44. Eigen::VectorXi b;
  45. {
  46. // this will create a vector from 0 to V.rows()-1 where the gap is 1
  47. Eigen::VectorXi J = Eigen::VectorXi::LinSpaced(high.V.rows(),0,high.V.rows()-1);
  48. Eigen::VectorXd sqrD;
  49. Eigen::MatrixXd _2;
  50. cout<<"Finding closest points..."<<endl;
  51. // using J which is N by 1 instead of a matrix that represents faces of N by 3
  52. // so that we will find the closest vertices istead of closest point on the face
  53. // so far the two meshes are not seperated. So what we are really doing here
  54. // is computing handles from low resolution and use that for the high resolution one
  55. igl::point_mesh_squared_distance(low.V,high.V,J,sqrD,b,_2);
  56. assert(sqrD.minCoeff() < 1e-7 && "low.V should exist in high.V");
  57. }
  58. // force perfect positioning, rather have popping in low-res than high-res.
  59. // The correct/elaborate thing to do is express original low.V in terms of
  60. // linear interpolation (or extrapolation) via elements in (high.V,high.F)
  61. // this is to replace the vertices on low resolution
  62. // with the vertices in high resolution. b is the list of vertices
  63. // corresponding to the indices in high resolution which has closest
  64. // distance to the points in low resolution
  65. igl::slice(high.V,b,1,low.V);
  66. // list of points --> list of singleton lists
  67. std::vector<std::vector<int> > S;
  68. // S will hav size of low.V.rows() and each list inside will have 1 element
  69. igl::matrix_to_list(b,S);
  70. cout<<"Computing weights for "<<b.size()<<
  71. " handles at "<<high.V.rows()<<" vertices..."<<endl;
  72. // Technically k should equal 3 for smooth interpolation in 3d, but 2 is
  73. // faster and looks OK
  74. const int k = 2;
  75. // using all the points in low resolution as handles for the region
  76. // it will be too expansive to use all the points in high reolution as handles
  77. // but since low and high resembles the same thing, using points in low reesolution
  78. // will give you similar performance
  79. igl::biharmonic_coordinates(high.V,high.T,S,k,W);
  80. cout<<"Reindexing..."<<endl;
  81. // Throw away interior tet-vertices, keep weights and indices of boundary
  82. VectorXi I,J;
  83. igl::remove_unreferenced(high.V.rows(),high.F,I,J);
  84. for_each(high.F.data(),high.F.data()+high.F.size(),[&I](int & a){a=I(a);});
  85. for_each(b.data(),b.data()+b.size(),[&I](int & a){a=I(a);});
  86. igl::slice(MatrixXd(high.V),J,1,high.V);
  87. igl::slice(MatrixXd(W),J,1,W);
  88. }
  89. // Resize low res (high res will also be resized by affine precision of W)
  90. low.V.rowwise() -= low.V.colwise().mean();
  91. low.V /= (low.V.maxCoeff()-low.V.minCoeff());
  92. low.V.rowwise() += RowVector3d(0,1,0);
  93. low.U = low.V;
  94. high.U = high.V;
  95. arap_data.with_dynamics = true;
  96. arap_data.max_iter = 10;
  97. arap_data.energy = ARAP_ENERGY_TYPE_DEFAULT;
  98. arap_data.h = 0.01;
  99. arap_data.ym = 0.001;
  100. if(!arap_precomputation(low.V,low.T,3,VectorXi(),arap_data))
  101. {
  102. cerr<<"arap_precomputation failed."<<endl;
  103. return EXIT_FAILURE;
  104. }
  105. // Constant gravitational force
  106. Eigen::SparseMatrix<double> M;
  107. igl::massmatrix(low.V,low.T,igl::MASSMATRIX_TYPE_DEFAULT,M);
  108. const size_t n = low.V.rows();
  109. // f = ma
  110. arap_data.f_ext = M * RowVector3d(0,-9.8,0).replicate(n,1);
  111. // Random initial velocities to wiggle things
  112. arap_data.vel = MatrixXd::Random(n,3);
  113. igl::opengl::glfw::Viewer viewer;
  114. // Create one huge mesh containing both meshes
  115. igl::cat(1,low.U,high.U,scene.U);
  116. // need to remap the indices since we cat the V matrices
  117. igl::cat(1,low.F,MatrixXi(high.F.array()+low.V.rows()),scene.F);
  118. // Color each mesh
  119. viewer.data().set_mesh(scene.U,scene.F);
  120. MatrixXd C(scene.F.rows(),3);
  121. C<<
  122. RowVector3d(0.8,0.5,0.2).replicate(low.F.rows(),1),
  123. RowVector3d(0.3,0.4,1.0).replicate(high.F.rows(),1);
  124. viewer.data().set_colors(C);
  125. viewer.callback_key_pressed =
  126. [&](igl::opengl::glfw::Viewer & viewer,unsigned int key,int mods)->bool
  127. {
  128. switch(key)
  129. {
  130. default:
  131. return false;
  132. case ' ':
  133. viewer.core().is_animating = !viewer.core().is_animating;
  134. return true;
  135. case 'r':
  136. low.U = low.V;
  137. return true;
  138. }
  139. };
  140. viewer.callback_pre_draw = [&](igl::opengl::glfw::Viewer & viewer)->bool
  141. {
  142. glEnable(GL_CULL_FACE);
  143. if(viewer.core().is_animating)
  144. {
  145. arap_solve(MatrixXd(0,3),arap_data,low.U);
  146. for(int v = 0;v<low.U.rows();v++)
  147. {
  148. // collide with y=0 plane
  149. const int y = 1;
  150. if(low.U(v,y) < 0)
  151. {
  152. low.U(v,y) = -low.U(v,y);
  153. // ~ coefficient of restitution
  154. const double cr = 1.1;
  155. arap_data.vel(v,y) = - arap_data.vel(v,y) / cr;
  156. }
  157. }
  158. scene.U.block(0,0,low.U.rows(),low.U.cols()) = low.U;
  159. high.U = W * (low.U.rowwise() + RowVector3d(1,0,0));
  160. scene.U.block(low.U.rows(),0,high.U.rows(),high.U.cols()) = high.U;
  161. viewer.data().set_vertices(scene.U);
  162. viewer.data().compute_normals();
  163. }
  164. return false;
  165. };
  166. viewer.data().show_lines = false;
  167. viewer.core().is_animating = true;
  168. viewer.core().animation_max_fps = 30.;
  169. viewer.data().set_face_based(true);
  170. cout<<R"(
  171. [space] to toggle animation
  172. 'r' to reset positions
  173. )";
  174. viewer.core().rotation_type =
  175. igl::opengl::ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP;
  176. viewer.launch();
  177. }