Browse Source

Fix nightly build + move EmbreeIntersector impl to .cpp (#1674)

Jérémie Dumas 5 years ago
parent
commit
858c843971

+ 396 - 0
include/igl/embree/EmbreeIntersector.cpp

@@ -0,0 +1,396 @@
+
+#include "EmbreeIntersector.h"
+
+// Implementation
+#include <igl/EPS.h>
+
+IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector()
+  :
+  //scene(NULL),
+  geomID(0),
+  vertices(NULL),
+  triangles(NULL),
+  initialized(false),
+  device(igl::embree::EmbreeDevice::get_device())
+{
+}
+
+IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector(
+  const EmbreeIntersector &)
+  :// To make -Weffc++ happy
+  //scene(NULL),
+  geomID(0),
+  vertices(NULL),
+  triangles(NULL),
+  initialized(false)
+{
+  assert(false && "Embree: Copying EmbreeIntersector is not allowed");
+}
+
+IGL_INLINE igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
+  const EmbreeIntersector &)
+{
+  assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
+  return *this;
+}
+
+
+IGL_INLINE void igl::embree::EmbreeIntersector::init(
+  const PointMatrixType& V,
+  const FaceMatrixType& F,
+  bool isStatic)
+{
+  std::vector<const PointMatrixType*> Vtemp;
+  std::vector<const FaceMatrixType*> Ftemp;
+  std::vector<int> masks;
+  Vtemp.push_back(&V);
+  Ftemp.push_back(&F);
+  masks.push_back(0xFFFFFFFF);
+  init(Vtemp,Ftemp,masks,isStatic);
+}
+
+IGL_INLINE void igl::embree::EmbreeIntersector::init(
+  const std::vector<const PointMatrixType*>& V,
+  const std::vector<const FaceMatrixType*>& F,
+  const std::vector<int>& masks,
+  bool isStatic)
+{
+
+  if(initialized)
+    deinit();
+
+  using namespace std;
+
+  if(V.size() == 0 || F.size() == 0)
+  {
+    std::cerr << "Embree: No geometry specified!";
+    return;
+  }
+
+  RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
+
+  // create a scene
+  scene = rtcNewScene(device);
+  rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
+  rtcSetSceneBuildQuality(scene, buildQuality);
+
+  for(int g=0;g<(int)V.size();g++)
+  {
+    // create triangle mesh geometry in that scene
+    RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
+    rtcSetGeometryBuildQuality(geom_0,buildQuality);
+    rtcSetGeometryTimeStepCount(geom_0,1);
+    geomID = rtcAttachGeometry(scene,geom_0);
+    rtcReleaseGeometry(geom_0);
+
+    // fill vertex buffer
+    vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
+    for(int i=0;i<(int)V[g]->rows();i++)
+    {
+      vertices[i].x = (float)V[g]->coeff(i,0);
+      vertices[i].y = (float)V[g]->coeff(i,1);
+      vertices[i].z = (float)V[g]->coeff(i,2);
+    }
+
+
+    // fill triangle buffer
+    triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
+    for(int i=0;i<(int)F[g]->rows();i++)
+    {
+      triangles[i].v0 = (int)F[g]->coeff(i,0);
+      triangles[i].v1 = (int)F[g]->coeff(i,1);
+      triangles[i].v2 = (int)F[g]->coeff(i,2);
+    }
+
+
+    rtcSetGeometryMask(geom_0,masks[g]);
+    rtcCommitGeometry(geom_0);
+  }
+
+  rtcCommitScene(scene);
+
+  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+      std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
+#ifdef IGL_VERBOSE
+  else
+    std::cerr << "Embree: geometry added." << endl;
+#endif
+
+  initialized = true;
+}
+
+igl::embree::EmbreeIntersector
+::~EmbreeIntersector()
+{
+  if(initialized)
+    deinit();
+  igl::embree::EmbreeDevice::release_device();
+}
+
+void igl::embree::EmbreeIntersector::deinit()
+{
+  if(device && scene)
+  {
+    rtcReleaseScene(scene);
+
+    if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+    {
+        std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+    }
+#ifdef IGL_VERBOSE
+    else
+    {
+      std::cerr << "Embree: geometry removed." << std::endl;
+    }
+#endif
+  }
+}
+
+IGL_INLINE bool igl::embree::EmbreeIntersector::intersectRay(
+  const Eigen::RowVector3f& origin,
+  const Eigen::RowVector3f& direction,
+  Hit& hit,
+  float tnear,
+  float tfar,
+  int mask) const
+{
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
+  createRay(ray, origin,direction,tnear,tfar,mask);
+
+  // shot ray
+  {
+    RTCIntersectContext context;
+    rtcInitIntersectContext(&context);
+    rtcIntersect1(scene,&context,&ray);
+    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+    ray.hit.Ng_y = -ray.hit.Ng_y;
+    ray.hit.Ng_z = -ray.hit.Ng_z;
+  }
+#ifdef IGL_VERBOSE
+  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
+      std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+#endif
+
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+  {
+    hit.id = ray.hit.primID;
+    hit.gid = ray.hit.geomID;
+    hit.u = ray.hit.u;
+    hit.v = ray.hit.v;
+    hit.t = ray.ray.tfar;
+    return true;
+  }
+
+  return false;
+}
+
+IGL_INLINE bool igl::embree::EmbreeIntersector::intersectBeam(
+      const Eigen::RowVector3f& origin,
+      const Eigen::RowVector3f& direction,
+      Hit& hit,
+      float tnear,
+      float tfar,
+      int mask,
+      int geoId,
+      bool closestHit,
+	  unsigned int samples) const
+{
+  bool hasHit = false;
+  Hit bestHit;
+
+  if(closestHit)
+    bestHit.t = std::numeric_limits<float>::max();
+  else
+    bestHit.t = 0;
+
+  if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
+  {
+    bestHit = hit;
+    hasHit = true;
+  }
+
+  // sample points around actual ray (conservative hitcheck)
+  const float eps= 1e-5;
+
+  Eigen::RowVector3f up(0,1,0);
+  if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
+  Eigen::RowVector3f offset = direction.cross(up).normalized();
+
+  Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
+
+  for(int r=0;r<(int)samples;r++)
+  {
+    if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
+        ((closestHit && (hit.t < bestHit.t)) ||
+           (!closestHit && (hit.t > bestHit.t)))  &&
+        (hit.gid == geoId || geoId == -1))
+    {
+      bestHit = hit;
+      hasHit = true;
+    }
+    offset = rot*offset.transpose();
+  }
+
+  hit = bestHit;
+  return hasHit;
+}
+
+IGL_INLINE bool
+igl::embree::EmbreeIntersector
+::intersectRay(
+  const Eigen::RowVector3f& origin,
+  const Eigen::RowVector3f& direction,
+  std::vector<Hit > &hits,
+  int& num_rays,
+  float tnear,
+  float tfar,
+  int mask) const
+{
+  using namespace std;
+  num_rays = 0;
+  hits.clear();
+  int last_id0 = -1;
+  double self_hits = 0;
+  // This epsilon is directly correleated to the number of missed hits, smaller
+  // means more accurate and slower
+  //const double eps = DOUBLE_EPS;
+  const double eps = FLOAT_EPS;
+  double min_t = tnear;
+  bool large_hits_warned = false;
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
+  createRay(ray,origin,direction,tnear,tfar,mask);
+
+  while(true)
+  {
+    ray.ray.tnear = min_t;
+    ray.ray.tfar = tfar;
+    ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+    ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
+    ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
+    num_rays++;
+    {
+      RTCIntersectContext context;
+      rtcInitIntersectContext(&context);
+      rtcIntersect1(scene,&context,&ray);
+      ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+      ray.hit.Ng_y = -ray.hit.Ng_y;
+      ray.hit.Ng_z = -ray.hit.Ng_z;
+    }
+    if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+    {
+      // Hit self again, progressively advance
+      if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
+      {
+        // push min_t a bit more
+        //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
+        double t_push = pow(2.0,self_hits)*eps;
+        #ifdef IGL_VERBOSE
+        std::cerr<<"  t_push: "<<t_push<<endl;
+        #endif
+        //o = o+t_push*d;
+        min_t += t_push;
+        self_hits++;
+      }
+      else
+      {
+        Hit hit;
+        hit.id = ray.hit.primID;
+        hit.gid = ray.hit.geomID;
+        hit.u = ray.hit.u;
+        hit.v = ray.hit.v;
+        hit.t = ray.ray.tfar;
+        hits.push_back(hit);
+#ifdef IGL_VERBOSE
+        std::cerr<<"  t: "<<hit.t<<endl;
+#endif
+        // Instead of moving origin, just change min_t. That way calculations
+        // all use exactly same origin values
+        min_t = ray.ray.tfar;
+
+        // reset t_scale
+        self_hits = 0;
+      }
+      last_id0 = ray.hit.primID;
+    }
+    else
+      break; // no more hits
+
+    if(hits.size()>1000 && !large_hits_warned)
+    {
+      std::cout<<"Warning: Large number of hits..."<<endl;
+      std::cout<<"[ ";
+      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
+      {
+        std::cout<<(hit->id+1)<<" ";
+      }
+
+      std::cout.precision(std::numeric_limits< double >::digits10);
+      std::cout<<"[ ";
+
+      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
+      {
+        std::cout<<(hit->t)<<endl;;
+      }
+
+      std::cout<<"]"<<endl;
+      large_hits_warned = true;
+
+      return hits.empty();
+    }
+  }
+
+  return hits.empty();
+}
+
+IGL_INLINE bool
+igl::embree::EmbreeIntersector
+::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
+{
+  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
+  ray.ray.flags = 0;
+  createRay(ray,a,ab,0,1.0,mask);
+
+  {
+    RTCIntersectContext context;
+    rtcInitIntersectContext(&context);
+    rtcIntersect1(scene,&context,&ray);
+    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
+    ray.hit.Ng_y = -ray.hit.Ng_y;
+    ray.hit.Ng_z = -ray.hit.Ng_z;
+  }
+
+  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
+  {
+    hit.id = ray.hit.primID;
+    hit.gid = ray.hit.geomID;
+    hit.u = ray.hit.u;
+    hit.v = ray.hit.v;
+    hit.t = ray.ray.tfar;
+    return true;
+  }
+
+  return false;
+}
+
+IGL_INLINE void
+igl::embree::EmbreeIntersector
+::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
+{
+  ray.ray.org_x = origin[0];
+  ray.ray.org_y = origin[1];
+  ray.ray.org_z = origin[2];
+  ray.ray.dir_x = direction[0];
+  ray.ray.dir_y = direction[1];
+  ray.ray.dir_z = direction[2];
+  ray.ray.tnear = tnear;
+  ray.ray.tfar = tfar;
+  ray.ray.id = RTC_INVALID_GEOMETRY_ID;
+  ray.ray.mask = mask;
+  ray.ray.time = 0.0f;
+
+  ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+  ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
+  ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
+}

+ 14 - 405
include/igl/embree/EmbreeIntersector.h

@@ -37,13 +37,13 @@ namespace igl
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
       typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
       typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
     public:
     public:
-      inline EmbreeIntersector();
+      EmbreeIntersector();
     private:
     private:
       // Copying and assignment are not allowed.
       // Copying and assignment are not allowed.
-      inline EmbreeIntersector(const EmbreeIntersector & that);
-      inline EmbreeIntersector & operator=(const EmbreeIntersector &);
+      EmbreeIntersector(const EmbreeIntersector & that);
+      EmbreeIntersector & operator=(const EmbreeIntersector &);
     public:
     public:
-      virtual inline ~EmbreeIntersector();
+      virtual ~EmbreeIntersector();
 
 
       // Initialize with a given mesh.
       // Initialize with a given mesh.
       //
       //
@@ -53,7 +53,7 @@ namespace igl
       //   isStatic  scene is optimized for static geometry
       //   isStatic  scene is optimized for static geometry
       // Side effects:
       // Side effects:
       //   The first time this is ever called the embree engine is initialized.
       //   The first time this is ever called the embree engine is initialized.
-      inline void init(
+      void init(
         const PointMatrixType& V,
         const PointMatrixType& V,
         const FaceMatrixType& F,
         const FaceMatrixType& F,
         bool isStatic = false);
         bool isStatic = false);
@@ -67,7 +67,7 @@ namespace igl
       //   isStatic  scene is optimized for static geometry
       //   isStatic  scene is optimized for static geometry
       // Side effects:
       // Side effects:
       //   The first time this is ever called the embree engine is initialized.
       //   The first time this is ever called the embree engine is initialized.
-      inline void init(
+      void init(
         const std::vector<const PointMatrixType*>& V,
         const std::vector<const PointMatrixType*>& V,
         const std::vector<const FaceMatrixType*>& F,
         const std::vector<const FaceMatrixType*>& F,
         const std::vector<int>& masks,
         const std::vector<int>& masks,
@@ -76,7 +76,7 @@ namespace igl
       // Deinitialize embree datasctructures for current mesh.  Also called on
       // Deinitialize embree datasctructures for current mesh.  Also called on
       // destruction: no need to call if you just want to init() once and
       // destruction: no need to call if you just want to init() once and
       // destroy.
       // destroy.
-      inline void deinit();
+      void deinit();
 
 
       // Given a ray find the first hit
       // Given a ray find the first hit
       //
       //
@@ -89,7 +89,7 @@ namespace igl
       // Output:
       // Output:
       //   hit        information about hit
       //   hit        information about hit
       // Returns true if and only if there was a hit
       // Returns true if and only if there was a hit
-      inline bool intersectRay(
+      bool intersectRay(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         const Eigen::RowVector3f& direction,
         Hit& hit,
         Hit& hit,
@@ -112,7 +112,7 @@ namespace igl
       // Output:
       // Output:
       //   hit        information about hit
       //   hit        information about hit
       // Returns true if and only if there was a hit
       // Returns true if and only if there was a hit
-      inline bool intersectBeam(
+      bool intersectBeam(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         const Eigen::RowVector3f& direction,
         Hit& hit,
         Hit& hit,
@@ -135,7 +135,7 @@ namespace igl
       //   hit        information about hit
       //   hit        information about hit
       //   num_rays   number of rays shot (at least one)
       //   num_rays   number of rays shot (at least one)
       // Returns true if and only if there was a hit
       // Returns true if and only if there was a hit
-      inline bool intersectRay(
+      bool intersectRay(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         const Eigen::RowVector3f& direction,
         std::vector<Hit > &hits,
         std::vector<Hit > &hits,
@@ -152,7 +152,7 @@ namespace igl
       // Output:
       // Output:
       //   hit  information about hit
       //   hit  information about hit
       // Returns true if and only if there was a hit
       // Returns true if and only if there was a hit
-      inline bool intersectSegment(
+      bool intersectSegment(
         const Eigen::RowVector3f& a,
         const Eigen::RowVector3f& a,
         const Eigen::RowVector3f& ab,
         const Eigen::RowVector3f& ab,
         Hit &hit,
         Hit &hit,
@@ -171,7 +171,7 @@ namespace igl
 
 
       RTCDevice device;
       RTCDevice device;
 
 
-      inline void createRay(
+      void createRay(
         RTCRayHit& ray,
         RTCRayHit& ray,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         const Eigen::RowVector3f& direction,
@@ -182,399 +182,8 @@ namespace igl
   }
   }
 }
 }
 
 
-// Implementation
-#include <igl/EPS.h>
-
-
-inline igl::embree::EmbreeIntersector::EmbreeIntersector()
-  :
-  //scene(NULL),
-  geomID(0),
-  vertices(NULL),
-  triangles(NULL),
-  initialized(false),
-  device(igl::embree::EmbreeDevice::get_device())
-{
-}
-
-inline igl::embree::EmbreeIntersector::EmbreeIntersector(
-  const EmbreeIntersector &)
-  :// To make -Weffc++ happy
-  //scene(NULL),
-  geomID(0),
-  vertices(NULL),
-  triangles(NULL),
-  initialized(false)
-{
-  assert(false && "Embree: Copying EmbreeIntersector is not allowed");
-}
-
-inline igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
-  const EmbreeIntersector &)
-{
-  assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
-  return *this;
-}
-
-
-inline void igl::embree::EmbreeIntersector::init(
-  const PointMatrixType& V,
-  const FaceMatrixType& F,
-  bool isStatic)
-{
-  std::vector<const PointMatrixType*> Vtemp;
-  std::vector<const FaceMatrixType*> Ftemp;
-  std::vector<int> masks;
-  Vtemp.push_back(&V);
-  Ftemp.push_back(&F);
-  masks.push_back(0xFFFFFFFF);
-  init(Vtemp,Ftemp,masks,isStatic);
-}
-
-inline void igl::embree::EmbreeIntersector::init(
-  const std::vector<const PointMatrixType*>& V,
-  const std::vector<const FaceMatrixType*>& F,
-  const std::vector<int>& masks,
-  bool isStatic)
-{
-
-  if(initialized)
-    deinit();
-
-  using namespace std;
-  
-  if(V.size() == 0 || F.size() == 0)
-  {
-    std::cerr << "Embree: No geometry specified!";
-    return;
-  }
-
-  RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
-
-  // create a scene
-  scene = rtcNewScene(device);
-  rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
-  rtcSetSceneBuildQuality(scene, buildQuality);
-
-  for(int g=0;g<(int)V.size();g++)
-  {
-    // create triangle mesh geometry in that scene
-    RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
-    rtcSetGeometryBuildQuality(geom_0,buildQuality);
-    rtcSetGeometryTimeStepCount(geom_0,1);
-    geomID = rtcAttachGeometry(scene,geom_0);
-    rtcReleaseGeometry(geom_0);
-
-    // fill vertex buffer
-    vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
-    for(int i=0;i<(int)V[g]->rows();i++)
-    {
-      vertices[i].x = (float)V[g]->coeff(i,0);
-      vertices[i].y = (float)V[g]->coeff(i,1);
-      vertices[i].z = (float)V[g]->coeff(i,2);
-    }
-    
-
-    // fill triangle buffer
-    triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
-    for(int i=0;i<(int)F[g]->rows();i++)
-    {
-      triangles[i].v0 = (int)F[g]->coeff(i,0);
-      triangles[i].v1 = (int)F[g]->coeff(i,1);
-      triangles[i].v2 = (int)F[g]->coeff(i,2);
-    }
-    
-
-    rtcSetGeometryMask(geom_0,masks[g]);
-    rtcCommitGeometry(geom_0);
-  }
-
-  rtcCommitScene(scene);
-
-  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
-      std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
-#ifdef IGL_VERBOSE
-  else
-    std::cerr << "Embree: geometry added." << endl;
-#endif
-
-  initialized = true;
-}
-
-igl::embree::EmbreeIntersector
-::~EmbreeIntersector()
-{
-  if(initialized)
-    deinit();
-  igl::embree::EmbreeDevice::release_device();
-}
-
-void igl::embree::EmbreeIntersector::deinit()
-{
-  if(device && scene)
-  {
-    rtcReleaseScene(scene);
-
-    if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
-    {
-        std::cerr << "Embree: An error occurred while resetting!" << std::endl;
-    }
-#ifdef IGL_VERBOSE
-    else
-    {
-      std::cerr << "Embree: geometry removed." << std::endl;
-    }
-#endif
-  }
-}
-
-inline bool igl::embree::EmbreeIntersector::intersectRay(
-  const Eigen::RowVector3f& origin,
-  const Eigen::RowVector3f& direction,
-  Hit& hit,
-  float tnear,
-  float tfar,
-  int mask) const
-{
-  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
-  ray.ray.flags = 0;
-  createRay(ray, origin,direction,tnear,tfar,mask);
-
-  // shot ray
-  {
-    RTCIntersectContext context;
-    rtcInitIntersectContext(&context);
-    rtcIntersect1(scene,&context,&ray);
-    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-    ray.hit.Ng_y = -ray.hit.Ng_y;
-    ray.hit.Ng_z = -ray.hit.Ng_z;
-  }
-#ifdef IGL_VERBOSE
-  if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
-      std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+#ifndef IGL_STATIC_LIBRARY
+#  include "EmbreeIntersector.cpp"
 #endif
 #endif
 
 
-  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
-  {
-    hit.id = ray.hit.primID;
-    hit.gid = ray.hit.geomID;
-    hit.u = ray.hit.u;
-    hit.v = ray.hit.v;
-    hit.t = ray.ray.tfar;
-    return true;
-  }
-
-  return false;
-}
-
-inline bool igl::embree::EmbreeIntersector::intersectBeam(
-      const Eigen::RowVector3f& origin,
-      const Eigen::RowVector3f& direction,
-      Hit& hit,
-      float tnear,
-      float tfar,
-      int mask,
-      int geoId,
-      bool closestHit,
-	  unsigned int samples) const
-{
-  bool hasHit = false;
-  Hit bestHit;
-
-  if(closestHit)
-    bestHit.t = std::numeric_limits<float>::max();
-  else
-    bestHit.t = 0;
-
-  if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
-  {
-    bestHit = hit;
-    hasHit = true;
-  }
-
-  // sample points around actual ray (conservative hitcheck)
-  const float eps= 1e-5;
-
-  Eigen::RowVector3f up(0,1,0);
-  if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
-  Eigen::RowVector3f offset = direction.cross(up).normalized();
-
-  Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
-
-  for(int r=0;r<(int)samples;r++)
-  {
-    if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) && 
-        ((closestHit && (hit.t < bestHit.t)) || 
-           (!closestHit && (hit.t > bestHit.t)))  &&
-        (hit.gid == geoId || geoId == -1))
-    {
-      bestHit = hit;
-      hasHit = true;
-    }
-    offset = rot*offset.transpose();
-  }
-
-  hit = bestHit;
-  return hasHit;
-}
-
-inline bool
-igl::embree::EmbreeIntersector
-::intersectRay(
-  const Eigen::RowVector3f& origin,
-  const Eigen::RowVector3f& direction,
-  std::vector<Hit > &hits,
-  int& num_rays,
-  float tnear,
-  float tfar,
-  int mask) const
-{
-  using namespace std;
-  num_rays = 0;
-  hits.clear();
-  int last_id0 = -1;
-  double self_hits = 0;
-  // This epsilon is directly correleated to the number of missed hits, smaller
-  // means more accurate and slower
-  //const double eps = DOUBLE_EPS;
-  const double eps = FLOAT_EPS;
-  double min_t = tnear;
-  bool large_hits_warned = false;
-  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
-  ray.ray.flags = 0;
-  createRay(ray,origin,direction,tnear,tfar,mask);
-
-  while(true)
-  {
-    ray.ray.tnear = min_t;
-    ray.ray.tfar = tfar;
-    ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
-    ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
-    ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
-    num_rays++;
-    {
-      RTCIntersectContext context;
-      rtcInitIntersectContext(&context);
-      rtcIntersect1(scene,&context,&ray);
-      ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-      ray.hit.Ng_y = -ray.hit.Ng_y;
-      ray.hit.Ng_z = -ray.hit.Ng_z;
-    }
-    if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
-    {
-      // Hit self again, progressively advance
-      if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
-      {
-        // push min_t a bit more
-        //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
-        double t_push = pow(2.0,self_hits)*eps;
-        #ifdef IGL_VERBOSE
-        std::cerr<<"  t_push: "<<t_push<<endl;
-        #endif
-        //o = o+t_push*d;
-        min_t += t_push;
-        self_hits++;
-      }
-      else
-      {
-        Hit hit;
-        hit.id = ray.hit.primID;
-        hit.gid = ray.hit.geomID;
-        hit.u = ray.hit.u;
-        hit.v = ray.hit.v;
-        hit.t = ray.ray.tfar;
-        hits.push_back(hit);
-#ifdef IGL_VERBOSE
-        std::cerr<<"  t: "<<hit.t<<endl;
-#endif
-        // Instead of moving origin, just change min_t. That way calculations
-        // all use exactly same origin values
-        min_t = ray.ray.tfar;
-
-        // reset t_scale
-        self_hits = 0;
-      }
-      last_id0 = ray.hit.primID;
-    }
-    else
-      break; // no more hits
-
-    if(hits.size()>1000 && !large_hits_warned)
-    {
-      std::cout<<"Warning: Large number of hits..."<<endl;
-      std::cout<<"[ ";
-      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
-      {
-        std::cout<<(hit->id+1)<<" ";
-      }
-
-      std::cout.precision(std::numeric_limits< double >::digits10);
-      std::cout<<"[ ";
-
-      for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
-      {
-        std::cout<<(hit->t)<<endl;;
-      }
-
-      std::cout<<"]"<<endl;
-      large_hits_warned = true;
-
-      return hits.empty();
-    }
-  }
-
-  return hits.empty();
-}
-
-inline bool
-igl::embree::EmbreeIntersector
-::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
-{
-  RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
-  ray.ray.flags = 0;
-  createRay(ray,a,ab,0,1.0,mask);
-
-  {
-    RTCIntersectContext context;
-    rtcInitIntersectContext(&context);
-    rtcIntersect1(scene,&context,&ray);
-    ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-    ray.hit.Ng_y = -ray.hit.Ng_y;
-    ray.hit.Ng_z = -ray.hit.Ng_z;
-  }
-
-  if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
-  {
-    hit.id = ray.hit.primID;
-    hit.gid = ray.hit.geomID;
-    hit.u = ray.hit.u;
-    hit.v = ray.hit.v;
-    hit.t = ray.ray.tfar;
-    return true;
-  }
-
-  return false;
-}
-
-inline void
-igl::embree::EmbreeIntersector
-::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
-{
-  ray.ray.org_x = origin[0];
-  ray.ray.org_y = origin[1];
-  ray.ray.org_z = origin[2];
-  ray.ray.dir_x = direction[0];
-  ray.ray.dir_y = direction[1];
-  ray.ray.dir_z = direction[2];
-  ray.ray.tnear = tnear;
-  ray.ray.tfar = tfar;
-  ray.ray.id = RTC_INVALID_GEOMETRY_ID;
-  ray.ray.mask = mask;
-  ray.ray.time = 0.0f;
-
-  ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
-  ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
-  ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
-}
-
 #endif //EMBREE_INTERSECTOR_H
 #endif //EMBREE_INTERSECTOR_H

+ 28 - 35
include/igl/embree/EmbreeRenderer.h

@@ -1,6 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 //
-// 
+//
 // Copyright (C) 2020 Vladimir Fonov <[email protected]>
 // Copyright (C) 2020 Vladimir Fonov <[email protected]>
 //               2013 Alec Jacobson <[email protected]>
 //               2013 Alec Jacobson <[email protected]>
 //               2014 Christian Schüller <[email protected]>
 //               2014 Christian Schüller <[email protected]>
@@ -46,35 +46,28 @@ namespace igl
         Vec3f N;    // element normal
         Vec3f N;    // element normal
       };
       };
 
 
-      // Initialize embree engine. This will be called on instance `init()`
-      // calls. If already inited then this function does nothing: it is harmless
-      // to call more than once.
-      static IGL_INLINE void global_init();
-    private:
-      // Deinitialize the embree engine.
-      static IGL_INLINE void global_deinit();
     public:
     public:
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> ColorMatrixType;
       typedef Eigen::Matrix<float,Eigen::Dynamic,3> ColorMatrixType;
       typedef Eigen::Matrix<int,  Eigen::Dynamic,3> FaceMatrixType;
       typedef Eigen::Matrix<int,  Eigen::Dynamic,3> FaceMatrixType;
-      
+
       typedef Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> PixelMatrixType;
       typedef Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> PixelMatrixType;
 
 
     public:
     public:
-      IGL_INLINE EmbreeRenderer();
+      EmbreeRenderer();
     private:
     private:
       // Copying and assignment are not allowed.
       // Copying and assignment are not allowed.
-      IGL_INLINE EmbreeRenderer(const EmbreeRenderer & that);
-      IGL_INLINE EmbreeRenderer & operator=(const EmbreeRenderer &);
+      EmbreeRenderer(const EmbreeRenderer & that);
+      EmbreeRenderer & operator=(const EmbreeRenderer &);
     public:
     public:
-      virtual inline ~EmbreeRenderer();
-      
+      virtual ~EmbreeRenderer();
+
       // Specify mesh, this call reinitializes embree structures
       // Specify mesh, this call reinitializes embree structures
       // Inputs:
       // Inputs:
       //   V  #V x dim matrix of vertex coordinates
       //   V  #V x dim matrix of vertex coordinates
       //   F  #F x simplex_size  matrix of indices of simplex corners into V
       //   F  #F x simplex_size  matrix of indices of simplex corners into V
       //   is_static - optimize for static thene (HQ rendering)
       //   is_static - optimize for static thene (HQ rendering)
-      IGL_INLINE void set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & V,
+      void set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & V,
                     const Eigen::Matrix<int,  Eigen::Dynamic,3>  & F,
                     const Eigen::Matrix<int,  Eigen::Dynamic,3>  & F,
                     bool is_static=true);
                     bool is_static=true);
       // Specify per-vertex or per-face color
       // Specify per-vertex or per-face color
@@ -82,13 +75,13 @@ namespace igl
       //   C  #V x 3 matrix of vertex colors
       //   C  #V x 3 matrix of vertex colors
       //    or #F x 3 matrix of face colors
       //    or #F x 3 matrix of face colors
       //    or 1 x 3 matrix of uniform color
       //    or 1 x 3 matrix of uniform color
-      IGL_INLINE void set_colors(const Eigen::MatrixXd & C);
+      void set_colors(const Eigen::MatrixXd & C);
 
 
 
 
       // Use min(D) and max(D) to set caxis.
       // Use min(D) and max(D) to set caxis.
-      IGL_INLINE void set_data(const Eigen::VectorXd & D,
+      void set_data(const Eigen::VectorXd & D,
                     igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
                     igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS);
-  
+
       // Specify per-vertex or per-face scalar field
       // Specify per-vertex or per-face scalar field
       //   that will be converted to color using jet color map
       //   that will be converted to color using jet color map
       // Inputs:
       // Inputs:
@@ -97,7 +90,7 @@ namespace igl
       //   D  #V by 1 list of scalar values
       //   D  #V by 1 list of scalar values
       //   cmap colormap type
       //   cmap colormap type
       //   num_steps number of intervals to discretize the colormap
       //   num_steps number of intervals to discretize the colormap
-      IGL_INLINE void set_data(
+      void set_data(
         const Eigen::VectorXd & D,
         const Eigen::VectorXd & D,
         double caxis_min,
         double caxis_min,
         double caxis_max,
         double caxis_max,
@@ -106,27 +99,27 @@ namespace igl
       // Specify mesh rotation
       // Specify mesh rotation
       // Inputs:
       // Inputs:
       //   r  3 x 3 rotaton matrix
       //   r  3 x 3 rotaton matrix
-      IGL_INLINE void set_rot(const Eigen::Matrix3d &r);
+      void set_rot(const Eigen::Matrix3d &r);
 
 
       // Specify mesh magnification
       // Specify mesh magnification
       // Inputs:
       // Inputs:
       //   z  magnification ratio
       //   z  magnification ratio
-      IGL_INLINE void set_zoom(double z);
+      void set_zoom(double z);
 
 
       // Specify mesh translation
       // Specify mesh translation
       // Inputs:
       // Inputs:
-      //   tr  translation vector 
-      IGL_INLINE void set_translation(const Eigen::Vector3d &tr);
+      //   tr  translation vector
+      void set_translation(const Eigen::Vector3d &tr);
 
 
       // Specify that color is face based
       // Specify that color is face based
       // Inputs:
       // Inputs:
       //    f - face or vertex colours
       //    f - face or vertex colours
-      IGL_INLINE void set_face_based(bool f);
+      void set_face_based(bool f);
 
 
       // Use orthographic projection
       // Use orthographic projection
       // Inputs:
       // Inputs:
       //    f - orthographic or perspective projection
       //    f - orthographic or perspective projection
-      IGL_INLINE void set_orthographic(bool f );
+      void set_orthographic(bool f );
 
 
       // render full buffer
       // render full buffer
       // Outputs:
       // Outputs:
@@ -136,8 +129,8 @@ namespace igl
       //   G - green channel
       //   G - green channel
       //   B - blue channel
       //   B - blue channel
       //   A - alpha channel
       //   A - alpha channel
-      IGL_INLINE void render_buffer(PixelMatrixType &R,
-                         PixelMatrixType &G, 
+      void render_buffer(PixelMatrixType &R,
+                         PixelMatrixType &G,
                          PixelMatrixType &B,
                          PixelMatrixType &B,
                          PixelMatrixType &A);
                          PixelMatrixType &A);
 
 
@@ -152,7 +145,7 @@ namespace igl
       // Output:
       // Output:
       //   hit        information about hit
       //   hit        information about hit
       // Returns true if and only if there was a hit
       // Returns true if and only if there was a hit
-      IGL_INLINE bool intersect_ray(
+      bool intersect_ray(
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         const Eigen::RowVector3f& direction,
         Hit& hit,
         Hit& hit,
@@ -170,7 +163,7 @@ namespace igl
       //   isStatic  scene is optimized for static geometry
       //   isStatic  scene is optimized for static geometry
       // Side effects:
       // Side effects:
       //   The first time this is ever called the embree engine is initialized.
       //   The first time this is ever called the embree engine is initialized.
-      IGL_INLINE void init(
+      void init(
         const PointMatrixType& V,
         const PointMatrixType& V,
         const FaceMatrixType& F,
         const FaceMatrixType& F,
         bool isStatic = false);
         bool isStatic = false);
@@ -184,7 +177,7 @@ namespace igl
       //   isStatic  scene is optimized for static geometry
       //   isStatic  scene is optimized for static geometry
       // Side effects:
       // Side effects:
       //   The first time this is ever called the embree engine is initialized.
       //   The first time this is ever called the embree engine is initialized.
-      IGL_INLINE void init(
+      void init(
         const std::vector<const PointMatrixType*>& V,
         const std::vector<const PointMatrixType*>& V,
         const std::vector<const FaceMatrixType*>& F,
         const std::vector<const FaceMatrixType*>& F,
         const std::vector<int>& masks,
         const std::vector<int>& masks,
@@ -194,9 +187,9 @@ namespace igl
       // Deinitialize embree datasctructures for current mesh.  Also called on
       // Deinitialize embree datasctructures for current mesh.  Also called on
       // destruction: no need to call if you just want to init() once and
       // destruction: no need to call if you just want to init() once and
       // destroy.
       // destroy.
-      IGL_INLINE void deinit();
+      void deinit();
       // initialize view parameters
       // initialize view parameters
-      IGL_INLINE void init_view();
+      void init_view();
 
 
       // scene data
       // scene data
       PointMatrixType V; // vertices
       PointMatrixType V; // vertices
@@ -211,7 +204,7 @@ namespace igl
       // Camera parameters
       // Camera parameters
       float camera_base_zoom;
       float camera_base_zoom;
       float camera_zoom;
       float camera_zoom;
-      
+
       Eigen::Vector3f camera_base_translation;
       Eigen::Vector3f camera_base_translation;
       Eigen::Vector3f camera_translation;
       Eigen::Vector3f camera_translation;
       Eigen::Vector3f camera_eye;
       Eigen::Vector3f camera_eye;
@@ -221,7 +214,7 @@ namespace igl
       float camera_dnear;
       float camera_dnear;
       float camera_dfar;
       float camera_dfar;
 
 
-      // projection matrixes      
+      // projection matrixes
       Eigen::Matrix4f view;
       Eigen::Matrix4f view;
       Eigen::Matrix4f proj;
       Eigen::Matrix4f proj;
       Eigen::Matrix4f norm;
       Eigen::Matrix4f norm;
@@ -237,7 +230,7 @@ namespace igl
 
 
       RTCDevice device;
       RTCDevice device;
 
 
-      IGL_INLINE void create_ray(
+      void create_ray(
         RTCRayHit& ray,
         RTCRayHit& ray,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& origin,
         const Eigen::RowVector3f& direction,
         const Eigen::RowVector3f& direction,