1 // This file is part of libigl, a simple c++ geometry processing library.
2 //
3 // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public License
6 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
7 // obtain one at http://mozilla.org/MPL/2.0/.
8 #include "ambient_occlusion.h"
9 #include "random_dir.h"
10 #include "ray_mesh_intersect.h"
11 #include "EPS.h"
12 #include "Hit.h"
13 #include "parallel_for.h"
14 #include <functional>
15 #include <vector>
16 #include <algorithm>
17 
18 template <
19   typename DerivedP,
20   typename DerivedN,
21   typename DerivedS >
ambient_occlusion(const std::function<bool (const Eigen::Vector3f &,const Eigen::Vector3f &)> & shoot_ray,const Eigen::PlainObjectBase<DerivedP> & P,const Eigen::PlainObjectBase<DerivedN> & N,const int num_samples,Eigen::PlainObjectBase<DerivedS> & S)22 IGL_INLINE void igl::ambient_occlusion(
23   const std::function<
24     bool(
25       const Eigen::Vector3f&,
26       const Eigen::Vector3f&)
27       > & shoot_ray,
28   const Eigen::PlainObjectBase<DerivedP> & P,
29   const Eigen::PlainObjectBase<DerivedN> & N,
30   const int num_samples,
31   Eigen::PlainObjectBase<DerivedS> & S)
32 {
33   using namespace Eigen;
34   const int n = P.rows();
35   // Resize output
36   S.resize(n,1);
37   // Embree seems to be parallel when constructing but not when tracing rays
38   const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
39 
40   const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
41   {
42     const Vector3f origin = P.row(p).template cast<float>();
43     const Vector3f normal = N.row(p).template cast<float>();
44     int num_hits = 0;
45     for(int s = 0;s<num_samples;s++)
46     {
47       Vector3f d = D.row(s);
48       if(d.dot(normal) < 0)
49       {
50         // reverse ray
51         d *= -1;
52       }
53       if(shoot_ray(origin,d))
54       {
55         num_hits++;
56       }
57     }
58     S(p) = (double)num_hits/(double)num_samples;
59   };
60   parallel_for(n,inner,1000);
61 }
62 
63 template <
64   typename DerivedV,
65   int DIM,
66   typename DerivedF,
67   typename DerivedP,
68   typename DerivedN,
69   typename DerivedS >
ambient_occlusion(const igl::AABB<DerivedV,DIM> & aabb,const Eigen::PlainObjectBase<DerivedV> & V,const Eigen::PlainObjectBase<DerivedF> & F,const Eigen::PlainObjectBase<DerivedP> & P,const Eigen::PlainObjectBase<DerivedN> & N,const int num_samples,Eigen::PlainObjectBase<DerivedS> & S)70 IGL_INLINE void igl::ambient_occlusion(
71   const igl::AABB<DerivedV,DIM> & aabb,
72   const Eigen::PlainObjectBase<DerivedV> & V,
73   const Eigen::PlainObjectBase<DerivedF> & F,
74   const Eigen::PlainObjectBase<DerivedP> & P,
75   const Eigen::PlainObjectBase<DerivedN> & N,
76   const int num_samples,
77   Eigen::PlainObjectBase<DerivedS> & S)
78 {
79   const auto & shoot_ray = [&aabb,&V,&F](
80     const Eigen::Vector3f& _s,
81     const Eigen::Vector3f& dir)->bool
82   {
83     Eigen::Vector3f s = _s+1e-4*dir;
84     igl::Hit hit;
85     return aabb.intersect_ray(
86       V,
87       F,
88       s  .cast<typename DerivedV::Scalar>().eval(),
89       dir.cast<typename DerivedV::Scalar>().eval(),
90       hit);
91   };
92   return ambient_occlusion(shoot_ray,P,N,num_samples,S);
93 
94 }
95 
96 template <
97   typename DerivedV,
98   typename DerivedF,
99   typename DerivedP,
100   typename DerivedN,
101   typename DerivedS >
ambient_occlusion(const Eigen::PlainObjectBase<DerivedV> & V,const Eigen::PlainObjectBase<DerivedF> & F,const Eigen::PlainObjectBase<DerivedP> & P,const Eigen::PlainObjectBase<DerivedN> & N,const int num_samples,Eigen::PlainObjectBase<DerivedS> & S)102 IGL_INLINE void igl::ambient_occlusion(
103   const Eigen::PlainObjectBase<DerivedV> & V,
104   const Eigen::PlainObjectBase<DerivedF> & F,
105   const Eigen::PlainObjectBase<DerivedP> & P,
106   const Eigen::PlainObjectBase<DerivedN> & N,
107   const int num_samples,
108   Eigen::PlainObjectBase<DerivedS> & S)
109 {
110   if(F.rows() < 100)
111   {
112     // Super naive
113     const auto & shoot_ray = [&V,&F](
114       const Eigen::Vector3f& _s,
115       const Eigen::Vector3f& dir)->bool
116     {
117       Eigen::Vector3f s = _s+1e-4*dir;
118       igl::Hit hit;
119       return ray_mesh_intersect(s,dir,V,F,hit);
120     };
121     return ambient_occlusion(shoot_ray,P,N,num_samples,S);
122   }
123   AABB<DerivedV,3> aabb;
124   aabb.init(V,F);
125   return ambient_occlusion(aabb,V,F,P,N,num_samples,S);
126 }
127 
128 #ifdef IGL_STATIC_LIBRARY
129 // Explicit template instantiation
130 // generated by autoexplicit.sh
131 template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
132 // generated by autoexplicit.sh
133 template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
134 // generated by autoexplicit.sh
135 template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
136 template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
137 #endif
138