orient_outward_ao.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "orient_outward_ao.h"
  2. #include "../per_face_normals.h"
  3. #include "../doublearea.h"
  4. #include "../random_dir.h"
  5. #include "EmbreeIntersector.h"
  6. #include <iostream>
  7. #include <random>
  8. #include <limits>
  9. template <
  10. typename DerivedV,
  11. typename DerivedF,
  12. typename DerivedC,
  13. typename DerivedFF,
  14. typename DerivedI>
  15. IGL_INLINE void igl::orient_outward_ao(
  16. const Eigen::PlainObjectBase<DerivedV> & V,
  17. const Eigen::PlainObjectBase<DerivedF> & F,
  18. const Eigen::PlainObjectBase<DerivedC> & C,
  19. const int min_num_rays_per_component,
  20. const int total_num_rays,
  21. Eigen::PlainObjectBase<DerivedFF> & FF,
  22. Eigen::PlainObjectBase<DerivedI> & I)
  23. {
  24. using namespace Eigen;
  25. using namespace std;
  26. assert(C.rows() == F.rows());
  27. assert(F.cols() == 3);
  28. assert(V.cols() == 3);
  29. // pass both sides of faces to Embree
  30. MatrixXi F2;
  31. F2.resize(F.rows()*2,F.cols());
  32. F2 << F, F.rowwise().reverse().eval();
  33. EmbreeIntersector<typename DerivedV::Scalar, typename DerivedF::Scalar> ei(V,F2);
  34. // number of faces
  35. const int m = F.rows();
  36. // number of patches
  37. const int num_cc = C.maxCoeff()+1;
  38. I.resize(num_cc);
  39. if(&FF != &F)
  40. {
  41. FF = F;
  42. }
  43. // face normal
  44. PlainObjectBase<DerivedV> N;
  45. per_face_normals(V,F,N);
  46. // face area
  47. Matrix<typename DerivedV::Scalar,Dynamic,1> A;
  48. doublearea(V,F,A);
  49. double area_min = A.minCoeff();
  50. double area_total = A.sum();
  51. // determine number of rays per component according to its area
  52. VectorXd area_per_component;
  53. area_per_component.setZero(num_cc);
  54. for (int f = 0; f < m; ++f)
  55. {
  56. area_per_component(C(f)) += A(f);
  57. }
  58. VectorXi num_rays_per_component;
  59. num_rays_per_component.setZero(num_cc);
  60. for (int c = 0; c < num_cc; ++c)
  61. {
  62. num_rays_per_component(c) = max<int>(min_num_rays_per_component, static_cast<int>(total_num_rays * area_per_component(c) / area_total));
  63. }
  64. // generate all the rays
  65. uniform_real_distribution<double> rdist;
  66. mt19937 prng;
  67. prng.seed(time(0));
  68. vector<int > ray_face;
  69. vector<Vector3d> ray_ori;
  70. vector<Vector3d> ray_dir;
  71. ray_face.reserve(total_num_rays);
  72. ray_ori .reserve(total_num_rays);
  73. ray_dir .reserve(total_num_rays);
  74. for (int c = 0; c < num_cc; ++c)
  75. {
  76. vector<int> CF; // set of faces per component
  77. vector<int> CF_area;
  78. for (int f = 0; f < m; ++f)
  79. {
  80. if (C(f)==c)
  81. {
  82. CF.push_back(f);
  83. CF_area.push_back(static_cast<int>(100 * A(f) / area_min));
  84. }
  85. }
  86. // discrete distribution for random selection of faces with probability proportional to their areas
  87. auto ddist_func = [&] (double i) { return CF_area[static_cast<int>(i)]; };
  88. discrete_distribution<int> ddist(CF.size(), 0, CF.size(), ddist_func); // simple ctor of (Iter, Iter) not provided by the stupid VC11 impl...
  89. for (int i = 0; i < num_rays_per_component[c]; ++i)
  90. {
  91. int f = CF[ddist(prng)]; // select face with probability proportional to face area
  92. double t0 = rdist(prng); // random barycentric coordinate
  93. double t1 = rdist(prng);
  94. double t2 = rdist(prng);
  95. double t_sum = t0 + t1 + t2;
  96. t0 /= t_sum;
  97. t1 /= t_sum;
  98. t2 /= t_sum;
  99. Vector3d p = t0 * V.row(F(f,0)) // be careful with the index!!!
  100. + t1 * V.row(F(f,1))
  101. + t2 * V.row(F(f,2));
  102. Vector3d n = N.row(f);
  103. Vector3d d = random_dir();
  104. if (n.dot(d) < 0)
  105. {
  106. d *= -1;
  107. }
  108. ray_face.push_back(f);
  109. ray_ori .push_back(p);
  110. ray_dir .push_back(d);
  111. }
  112. }
  113. // occlusion count per component
  114. vector<int> C_occlude_count_front(num_cc, 0);
  115. vector<int> C_occlude_count_back (num_cc, 0);
  116. //auto dbg_get_hit_point = [&] (embree::Hit hit) {
  117. // RowVector3d p0 = V.row(F2(hit.id0, 0));
  118. // RowVector3d p1 = V.row(F2(hit.id0, 1));
  119. // RowVector3d p2 = V.row(F2(hit.id0, 2));
  120. // RowVector3d p = (1 - hit.u - hit.v) * p0 + hit.u * p1 + hit.v * p2;
  121. // return p;
  122. //};
  123. #pragma omp parallel for
  124. for (int i = 0; i < ray_face.size(); ++i)
  125. {
  126. int f = ray_face[i];
  127. Vector3d o = ray_ori [i];
  128. Vector3d d = ray_dir [i];
  129. int c = C(f);
  130. Hit hit_front;
  131. if (ei.intersectRay(o, d, hit_front))
  132. {
  133. #pragma omp atomic
  134. //RowVector3d hit_point = dbg_get_hit_point(hit_front);
  135. C_occlude_count_front[c]++;
  136. }
  137. Hit hit_back;
  138. if (ei.intersectRay(o, -d, hit_back))
  139. {
  140. #pragma omp atomic
  141. //RowVector3d hit_point = dbg_get_hit_point(hit_back);
  142. C_occlude_count_back[c]++;
  143. }
  144. }
  145. for(int c = 0;c<num_cc;c++)
  146. {
  147. I(c) = C_occlude_count_front[c] > C_occlude_count_back[c];
  148. }
  149. // flip according to I
  150. for(int f = 0;f<m;f++)
  151. {
  152. if(I(C(f)))
  153. {
  154. FF.row(f) = FF.row(f).reverse().eval();
  155. }
  156. }
  157. }
  158. // Call with default parameters
  159. template <
  160. typename DerivedV,
  161. typename DerivedF,
  162. typename DerivedC,
  163. typename DerivedFF,
  164. typename DerivedI>
  165. IGL_INLINE void igl::orient_outward_ao(
  166. const Eigen::PlainObjectBase<DerivedV> & V,
  167. const Eigen::PlainObjectBase<DerivedF> & F,
  168. const Eigen::PlainObjectBase<DerivedC> & C,
  169. Eigen::PlainObjectBase<DerivedFF> & FF,
  170. Eigen::PlainObjectBase<DerivedI> & I)
  171. {
  172. return orient_outward_ao(V, F, C, 100, F.rows() * 100, FF, I);
  173. }
  174. #ifndef IGL_HEADER_ONLY
  175. // Explicit template specialization
  176. template void igl::orient_outward_ao<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  177. #endif