orient_outward_ao.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include "orient_outward_ao.h"
  2. #include "../per_face_normals.h"
  3. #include "../barycenter.h"
  4. #include "../doublearea.h"
  5. #include "../matlab_format.h"
  6. #include "ambient_occlusion.h"
  7. #include <iostream>
  8. #include <random>
  9. template <
  10. typename DerivedV,
  11. typename DerivedF,
  12. typename DerivedC,
  13. typename PointMatrixType,
  14. typename FaceMatrixType,
  15. typename RowVector3,
  16. typename DerivedFF,
  17. typename DerivedI>
  18. IGL_INLINE void igl::orient_outward_ao(
  19. const Eigen::PlainObjectBase<DerivedV> & V,
  20. const Eigen::PlainObjectBase<DerivedF> & F,
  21. const Eigen::PlainObjectBase<DerivedC> & C,
  22. const igl::EmbreeIntersector<PointMatrixType,FaceMatrixType,RowVector3> & ei,
  23. const int num_samples,
  24. Eigen::PlainObjectBase<DerivedFF> & FF,
  25. Eigen::PlainObjectBase<DerivedI> & I)
  26. {
  27. using namespace Eigen;
  28. using namespace std;
  29. assert(C.rows() == F.rows());
  30. assert(F.cols() == 3);
  31. assert(V.cols() == 3);
  32. // number of faces
  33. const int m = F.rows();
  34. // number of patches
  35. const int num_cc = C.maxCoeff()+1;
  36. I.resize(num_cc);
  37. if(&FF != &F)
  38. {
  39. FF = F;
  40. }
  41. PlainObjectBase<DerivedV> N;
  42. Matrix<typename DerivedV::Scalar,Dynamic,1> A;
  43. per_face_normals(V,F,N);
  44. doublearea(V,F,A);
  45. double minarea = A.minCoeff();
  46. mt19937 engine;
  47. engine.seed(time(0));
  48. Matrix<int, Dynamic, 1> A_int = (A * 100.0 / minarea).cast<int>();
  49. auto ddist_func = [&] (double i) { return A_int(static_cast<int>(i)); };
  50. discrete_distribution<int> ddist(m, 0, m, ddist_func); // simple ctor of (Iter, Iter) not provided by the stupid VC11 impl...
  51. uniform_real_distribution<double> rdist;
  52. Matrix<int, Dynamic, 1> C_occlude_count; // +1 when front ray is occluded, -1 when back ray is occluded
  53. C_occlude_count.setZero(m, 1);
  54. //#pragma omp parallel for
  55. for (int i = 0; i < num_samples; ++i)
  56. {
  57. int f = ddist(engine); // select face with probability proportional to face area
  58. double t0 = rdist(engine);
  59. double t1 = rdist(engine);
  60. double t2 = rdist(engine);
  61. double t_sum = t0 + t1 + t2;
  62. t0 /= t_sum;
  63. t1 /= t_sum;
  64. t2 /= t_sum;
  65. RowVector3d p = t0 * V.row(F(f,0)) + t1 * V.row(F(f,1)) + t1 * V.row(F(f,2));
  66. RowVector3d n = N.row(f);
  67. bool is_backside = rdist(engine) < 0.5;
  68. if (is_backside)
  69. {
  70. n *= -1;
  71. }
  72. Matrix<typename DerivedV::Scalar,Dynamic,1> S;
  73. ambient_occlusion(ei, p, n, 1, S);
  74. if (S(0) > 0)
  75. {
  76. C_occlude_count(C(f)) += is_backside ? -1 : 1;
  77. }
  78. }
  79. for(int c = 0;c<num_cc;c++)
  80. {
  81. I(c) = C_occlude_count(c) > 0;
  82. }
  83. // flip according to I
  84. for(int f = 0;f<m;f++)
  85. {
  86. if(I(C(f)))
  87. {
  88. FF.row(f) = FF.row(f).reverse().eval();
  89. }
  90. }
  91. }
  92. // EmbreeIntersector generated on the fly
  93. template <
  94. typename DerivedV,
  95. typename DerivedF,
  96. typename DerivedC,
  97. typename DerivedFF,
  98. typename DerivedI>
  99. IGL_INLINE void igl::orient_outward_ao(
  100. const Eigen::PlainObjectBase<DerivedV> & V,
  101. const Eigen::PlainObjectBase<DerivedF> & F,
  102. const Eigen::PlainObjectBase<DerivedC> & C,
  103. const int num_samples,
  104. Eigen::PlainObjectBase<DerivedFF> & FF,
  105. Eigen::PlainObjectBase<DerivedI> & I)
  106. {
  107. using namespace igl;
  108. using namespace Eigen;
  109. EmbreeIntersector<
  110. PlainObjectBase<DerivedV>,
  111. PlainObjectBase<DerivedF>,
  112. Matrix<typename DerivedV::Scalar,3,1> > ei(V,F);
  113. return orient_outward_ao(V, F, C, ei, num_samples, FF, I);
  114. }