aabb-evaluation.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include <iostream>
  2. #include <fstream>
  3. #include <string>
  4. #include <libslic3r/TriangleMesh.hpp>
  5. #include <libslic3r/AABBTreeIndirect.hpp>
  6. #include <libslic3r/SLA/EigenMesh3D.hpp>
  7. #ifdef _MSC_VER
  8. #pragma warning(push)
  9. #pragma warning(disable: 4244)
  10. #pragma warning(disable: 4267)
  11. #endif
  12. #include <igl/ray_mesh_intersect.h>
  13. #include <igl/point_mesh_squared_distance.h>
  14. #include <igl/remove_duplicate_vertices.h>
  15. #include <igl/signed_distance.h>
  16. #include <igl/random_dir.h>
  17. #ifdef _MSC_VER
  18. #pragma warning(pop)
  19. #endif
  20. const std::string USAGE_STR = {
  21. "Usage: aabb-evaluation stlfilename.stl"
  22. };
  23. using namespace Slic3r;
  24. void profile(const TriangleMesh &mesh)
  25. {
  26. Eigen::MatrixXd V;
  27. Eigen::MatrixXi F;
  28. Eigen::MatrixXd vertex_normals;
  29. sla::to_eigen_mesh(mesh, V, F);
  30. igl::per_vertex_normals(V, F, vertex_normals);
  31. static constexpr int num_samples = 100;
  32. const int num_vertices = std::min(10000, int(mesh.its.vertices.size()));
  33. const Eigen::MatrixXd dirs = igl::random_dir_stratified(num_samples).cast<double>();
  34. Eigen::MatrixXd occlusion_output0;
  35. {
  36. AABBTreeIndirect::Tree3f tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(mesh.its.vertices, mesh.its.indices);
  37. occlusion_output0.resize(num_vertices, 1);
  38. for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
  39. const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
  40. const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
  41. int num_hits = 0;
  42. for (int s = 0; s < num_samples; s++) {
  43. Eigen::Vector3d d = dirs.row(s);
  44. if(d.dot(normal) < 0) {
  45. // reverse ray
  46. d *= -1;
  47. }
  48. igl::Hit hit;
  49. if (AABBTreeIndirect::intersect_ray_first_hit(mesh.its.vertices, mesh.its.indices, tree, (origin + 1e-4 * d).eval(), d, hit))
  50. ++ num_hits;
  51. }
  52. occlusion_output0(ivertex) = (double)num_hits/(double)num_samples;
  53. }
  54. occlusion_output0.resize(num_vertices, 1);
  55. for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
  56. const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
  57. const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
  58. int num_hits = 0;
  59. for (int s = 0; s < num_samples; s++) {
  60. Eigen::Vector3d d = dirs.row(s);
  61. if(d.dot(normal) < 0) {
  62. // reverse ray
  63. d *= -1;
  64. }
  65. igl::Hit hit;
  66. if (AABBTreeIndirect::intersect_ray_first_hit(mesh.its.vertices, mesh.its.indices, tree,
  67. Eigen::Vector3f((origin + 1e-4 * d).template cast<float>()),
  68. Eigen::Vector3f(d.template cast<float>()), hit))
  69. ++ num_hits;
  70. }
  71. occlusion_output0(ivertex) = (double)num_hits/(double)num_samples;
  72. }
  73. }
  74. Eigen::MatrixXd occlusion_output1;
  75. {
  76. std::vector<Vec3d> vertices;
  77. std::vector<Vec3i> triangles;
  78. for (int i = 0; i < V.rows(); ++ i)
  79. vertices.emplace_back(V.row(i).transpose());
  80. for (int i = 0; i < F.rows(); ++ i)
  81. triangles.emplace_back(F.row(i).transpose());
  82. AABBTreeIndirect::Tree3d tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(vertices, triangles);
  83. occlusion_output1.resize(num_vertices, 1);
  84. for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
  85. const Eigen::Vector3d origin = V.row(ivertex).template cast<double>();
  86. const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
  87. int num_hits = 0;
  88. for (int s = 0; s < num_samples; s++) {
  89. Eigen::Vector3d d = dirs.row(s);
  90. if(d.dot(normal) < 0) {
  91. // reverse ray
  92. d *= -1;
  93. }
  94. igl::Hit hit;
  95. if (AABBTreeIndirect::intersect_ray_first_hit(vertices, triangles, tree, Eigen::Vector3d(origin + 1e-4 * d), d, hit))
  96. ++ num_hits;
  97. }
  98. occlusion_output1(ivertex) = (double)num_hits/(double)num_samples;
  99. }
  100. }
  101. // Build the AABB accelaration tree
  102. Eigen::MatrixXd occlusion_output2;
  103. {
  104. igl::AABB<Eigen::MatrixXd, 3> AABB;
  105. AABB.init(V, F);
  106. occlusion_output2.resize(num_vertices, 1);
  107. for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
  108. const Eigen::Vector3d origin = V.row(ivertex).template cast<double>();
  109. const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
  110. int num_hits = 0;
  111. for (int s = 0; s < num_samples; s++) {
  112. Eigen::Vector3d d = dirs.row(s);
  113. if(d.dot(normal) < 0) {
  114. // reverse ray
  115. d *= -1;
  116. }
  117. igl::Hit hit;
  118. if (AABB.intersect_ray(V, F, origin + 1e-4 * d, d, hit))
  119. ++ num_hits;
  120. }
  121. occlusion_output2(ivertex) = (double)num_hits/(double)num_samples;
  122. }
  123. }
  124. Eigen::MatrixXd occlusion_output3;
  125. {
  126. typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
  127. typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
  128. igl::AABB<MapMatrixXfUnaligned, 3> AABB;
  129. auto vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), mesh.its.vertices.size(), 3);
  130. auto faces = MapMatrixXiUnaligned(mesh.its.indices.front().data(), mesh.its.indices.size(), 3);
  131. AABB.init(
  132. vertices,
  133. faces);
  134. occlusion_output3.resize(num_vertices, 1);
  135. for (int ivertex = 0; ivertex < num_vertices; ++ ivertex) {
  136. const Eigen::Vector3d origin = mesh.its.vertices[ivertex].template cast<double>();
  137. const Eigen::Vector3d normal = vertex_normals.row(ivertex).template cast<double>();
  138. int num_hits = 0;
  139. for (int s = 0; s < num_samples; s++) {
  140. Eigen::Vector3d d = dirs.row(s);
  141. if(d.dot(normal) < 0) {
  142. // reverse ray
  143. d *= -1;
  144. }
  145. igl::Hit hit;
  146. if (AABB.intersect_ray(vertices, faces, (origin + 1e-4 * d).eval().template cast<float>(), d.template cast<float>(), hit))
  147. ++ num_hits;
  148. }
  149. occlusion_output3(ivertex) = (double)num_hits/(double)num_samples;
  150. }
  151. }
  152. }
  153. int main(const int argc, const char *argv[])
  154. {
  155. if(argc < 2) {
  156. std::cout << USAGE_STR << std::endl;
  157. return EXIT_SUCCESS;
  158. }
  159. TriangleMesh mesh;
  160. if (! mesh.ReadSTLFile(argv[1])) {
  161. std::cerr << "Error loading " << argv[1] << std::endl;
  162. return -1;
  163. }
  164. if (mesh.empty()) {
  165. std::cerr << "Error loading " << argv[1] << " . It is empty." << std::endl;
  166. return -1;
  167. }
  168. profile(mesh);
  169. return EXIT_SUCCESS;
  170. }