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