main.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #include <igl/read_triangle_mesh.h>
  2. #include <igl/lipschitz_octree.h>
  3. #include <igl/opengl/glfw/Viewer.h>
  4. #include <igl/AABB.h>
  5. #include <igl/fast_winding_number.h>
  6. #include <igl/signed_distance.h>
  7. #include <igl/grid.h>
  8. #include <igl/colormap.h>
  9. #include <igl/matlab_format.h>
  10. #include <igl/marching_cubes.h>
  11. #include <igl/unique_sparse_voxel_corners.h>
  12. #include <igl/get_seconds.h>
  13. // Edges of a cube box with minimum corner at origin and side length h.
  14. void box_edges(
  15. const Eigen::RowVector3d & origin,
  16. const double h,
  17. Eigen::MatrixXd & V,
  18. Eigen::MatrixXi & E)
  19. {
  20. V.resize(8,3);
  21. V<< 0,0,0, 0,0,1, 0,1,0, 0,1,1, 1,0,0, 1,0,1, 1,1,0, 1,1,1;
  22. V *= h;
  23. V.rowwise() += origin;
  24. E.resize(12,2);
  25. E<< 0,1, 0,2, 0,4, 1,3, 1,5, 2,3, 2,6, 3,7, 4,5, 4,6, 5,7, 6,7;
  26. }
  27. // Edges of cubes placed at all corners of octree with origin and cell side length h.
  28. void all_box_edges(
  29. const Eigen::RowVector3d & origin,
  30. const double h,
  31. const Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> & ijk,
  32. Eigen::MatrixXd & V,
  33. Eigen::MatrixXi & E)
  34. {
  35. V.resize(ijk.rows()*8,3);
  36. E.resize(ijk.rows()*12,2);
  37. for(int c = 0;c<ijk.rows();c++)
  38. {
  39. Eigen::MatrixXd Vc;
  40. Eigen::MatrixXi Ec;
  41. box_edges(
  42. origin + h * Eigen::RowVector3d(ijk(c,1),ijk(c,0),ijk(c,2)), h, Vc,Ec);
  43. V.middleRows(c*8,8) = Vc;
  44. E.middleRows(c*12,12) = Ec.array() + c*8;
  45. }
  46. }
  47. int main(int argc, char * argv[])
  48. {
  49. IGL_TICTOC_LAMBDA;
  50. // Read mesh
  51. Eigen::MatrixXd V;
  52. Eigen::MatrixXi F;
  53. if(!igl::read_triangle_mesh
  54. (argc>1?argv[1]: TUTORIAL_SHARED_PATH "/decimated-knight.off",V,F)) {
  55. std::cout << "Failed to load mesh." << std::endl;
  56. }
  57. // Prepare unsigned and signed distance function handles
  58. igl::AABB<Eigen::MatrixXd,3> aabb;
  59. aabb.init(V,F);
  60. const double bbd = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
  61. double offset_factor = 0.05;
  62. igl::FastWindingNumberBVH fwn_bvh;
  63. igl::fast_winding_number(V.cast<float>().eval(), F, 2, fwn_bvh);
  64. const std::function<double(const Eigen::RowVector3d &)>
  65. sdf = [&]( const Eigen::RowVector3d & p) -> double
  66. {
  67. double w = fast_winding_number(fwn_bvh, 2, p.template cast<float>().eval());
  68. double s = 1.-2.*std::abs(w);
  69. int i;
  70. Eigen::RowVector3d c;
  71. return s*std::sqrt(aabb.squared_distance(V,F,p,i,c)) - offset_factor*bbd;
  72. };
  73. // This can't be auto when using static library or compiler gets confused.
  74. const std::function<double(const Eigen::RowVector3d &)>
  75. udf = [&]( const Eigen::RowVector3d & p) -> double
  76. {
  77. return std::abs(sdf(p));
  78. };
  79. // Centered bounding cube (root of octree) with padding.
  80. double h0 = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
  81. int max_depth = 5;
  82. // Pad bounding box by max_depth
  83. //{
  84. // double leaf_h = h0 / (1 << max_depth);
  85. // h0 += leaf_h*2;
  86. //}
  87. // Pad to root
  88. h0 *= 2;
  89. Eigen::RowVector3d origin = 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff()).array() - 0.5*h0;
  90. igl::opengl::glfw::Viewer viewer;
  91. viewer.data().set_mesh(V,F);
  92. const int main_index = viewer.selected_data_index;
  93. Eigen::MatrixXd rV;
  94. Eigen::MatrixXi rE;
  95. box_edges(origin,h0,rV,rE);
  96. viewer.data().set_edges(rV,rE,Eigen::RowVector3d(1,1,0));
  97. viewer.data().set_face_based(true);
  98. viewer.data().show_lines = false;
  99. viewer.append_mesh();
  100. const int aux_index = viewer.selected_data_index;
  101. const auto update = [&]()
  102. {
  103. if(max_depth<=8)
  104. {
  105. // For comparison, how long would it take to compute on the dense grid
  106. tictoc();
  107. Eigen::Matrix<double,Eigen::Dynamic,3,Eigen::RowMajor> GV;
  108. Eigen::RowVector3i res(1<<max_depth,1<<max_depth,1<<max_depth);
  109. igl::grid(res,GV);
  110. GV *= h0;
  111. GV.rowwise() += origin;
  112. Eigen::VectorXd GS(GV.rows());
  113. igl::parallel_for( GV.rows(), [&](const int u)
  114. {
  115. // evaluate the function at the corner
  116. GS(u) = sdf(GV.row(u));
  117. },1000);
  118. printf(" n³ grid: %0.7f seconds\n",tictoc());
  119. }else
  120. {
  121. printf(" n³ grid: [omitted]\n");
  122. }
  123. tictoc();
  124. // Identify the octree cells that could contain the surface
  125. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> ijk;
  126. igl::lipschitz_octree(origin,h0,max_depth,udf,ijk);
  127. printf(" lipschitz_octree: %0.7f seconds\n",tictoc());
  128. // Gather the corners of those leaf cells
  129. const double h = h0 / (1 << max_depth);
  130. Eigen::Matrix<int,Eigen::Dynamic,8,Eigen::RowMajor> J;
  131. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> unique_ijk;
  132. Eigen::Matrix<double,Eigen::Dynamic,3,Eigen::RowMajor> unique_corner_positions;
  133. igl::unique_sparse_voxel_corners(origin,h0,max_depth,ijk,unique_ijk,J,unique_corner_positions);
  134. printf("unique_sparse_voxel_corners: %0.7f seconds\n",tictoc());
  135. /// Evaluate the signed distance function at the corners
  136. Eigen::VectorXd S(unique_corner_positions.rows());
  137. //for(int u = 0;u<unique_corner_positions.rows();u++)
  138. igl::parallel_for(
  139. unique_corner_positions.rows(),
  140. [&](const int u)
  141. {
  142. // evaluate the function at the corner
  143. S(u) = sdf(unique_corner_positions.row(u));
  144. },1000);
  145. printf(" sdf: %0.7f seconds\n",tictoc());
  146. // Run marching cubes on the sparse set of leaf cells
  147. Eigen::Matrix<double,Eigen::Dynamic,3> mV;
  148. Eigen::Matrix<int,Eigen::Dynamic,3> mF;
  149. igl::marching_cubes( S,unique_corner_positions,J, 0, mV,mF);
  150. printf(" marching_cubes: %0.7f seconds\n",tictoc());
  151. // Visualize
  152. viewer.data(aux_index).clear();
  153. viewer.data(aux_index).set_mesh(mV,mF);
  154. viewer.data(aux_index).set_face_based(true);
  155. viewer.data().show_lines = max_depth <= 7;
  156. viewer.data(aux_index).set_colors(Eigen::RowVector3d(0.941176,0.305882,0.282353));
  157. if(max_depth <= 7)
  158. {
  159. // If tree is shallow enough, visualize the edges of the octree cells
  160. Eigen::MatrixXd gV;
  161. Eigen::MatrixXi gE;
  162. all_box_edges(origin,h,ijk,gV,gE);
  163. viewer.data(aux_index).set_edges(gV,gE,Eigen::RowVector3d(1,1,1));
  164. Eigen::MatrixXd point_colors;
  165. igl::colormap(
  166. igl::ColorMapType::COLOR_MAP_TYPE_TURBO,
  167. S,-S.array().abs().maxCoeff(),S.array().abs().maxCoeff(),
  168. point_colors);
  169. viewer.data(aux_index).add_points(unique_corner_positions,point_colors);
  170. viewer.data(aux_index).point_size = 8;
  171. }
  172. printf(" |ijk| : %ld\n",ijk.rows());
  173. };
  174. viewer.callback_key_pressed =
  175. [&](igl::opengl::glfw::Viewer & viewer, unsigned int key, int mod)->bool
  176. {
  177. switch(key) {
  178. default:
  179. return false;
  180. case '=':
  181. case '+':
  182. case '-':
  183. case '_':
  184. max_depth = std::max(0,max_depth + ((key == '-'||key=='_') ? -1 : 1));
  185. printf("max_depth = %d\n",max_depth);
  186. update();
  187. break;
  188. case '}':
  189. case '{':
  190. offset_factor =
  191. std::min(std::max(-1.0,offset_factor+(key=='{'?-0.01:0.01)),1.0);
  192. printf("offset_factor = %f\n",offset_factor);
  193. update();
  194. break;
  195. }
  196. return true;
  197. };
  198. update();
  199. // Trivial batched function
  200. const std::function<Eigen::VectorXd(const Eigen::Matrix<double,Eigen::Dynamic,3,Eigen::RowMajor> &)>
  201. udf_batch = [&](const Eigen::Matrix<double,Eigen::Dynamic,3,Eigen::RowMajor> & P) -> Eigen::VectorXd
  202. {
  203. Eigen::VectorXd U(P.rows());
  204. for(int i = 0;i<P.rows();i++)
  205. {
  206. U(i) = udf(P.row(i));
  207. }
  208. return U;
  209. };
  210. {
  211. // The batched version should produce the same size output
  212. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> ijk_batch;
  213. igl::lipschitz_octree<true>(origin,h0,max_depth,udf_batch,ijk_batch);
  214. printf(" |ijk_batch| : %ld\n",ijk_batch.rows());
  215. }
  216. std::cout << R"(Usage:
  217. -,+ Decrease,Increase the depth of the octree and recompute
  218. {,} Decrease,Increase the offset factor for the signed distance function
  219. )";
  220. viewer.launch();
  221. return 0;
  222. }