Browse Source

removed templates from EmbreeINtersector

Former-commit-id: 69ac25018005ba82d820bc8ef6b6aed2b62869fe
Alec Jacobson (jalec 11 years ago
parent
commit
bc940b6418

+ 2 - 2
examples/ambient-occlusion/example.cpp

@@ -48,7 +48,7 @@ Eigen::MatrixXd V,N,C,mid;
 Eigen::MatrixXi F;
 // Bounding box diagonal length
 double bbd;
-igl::EmbreeIntersector<Eigen::MatrixXd::Scalar,Eigen::MatrixXi::Scalar> ei;
+igl::EmbreeIntersector ei;
 // Running ambient occlusion
 Eigen::VectorXd S;
 int tot_num_samples = 0;
@@ -373,7 +373,7 @@ int main(int argc, char * argv[])
   bbd = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
 
   // Init embree
-  ei.init(V,F);
+  ei.init(V.cast<float>(),F.cast<int>());
 
   // Init glut
   glutInit(&argc,argv);

+ 18 - 18
examples/embree/example.cpp

@@ -37,11 +37,11 @@ double bbd;
 // Faces
 Eigen::MatrixXi F;
 // Embree intersection structure
-igl::EmbreeIntersector<double,int> ei;
+igl::EmbreeIntersector ei;
 // Hits collected
 std::vector<igl::Hit > hits;
 // Ray information, "projection screen" corners
-Eigen::Vector3d win_s,s,d,dir,NW,NE,SE,SW;
+Eigen::Vector3f win_s,s,d,dir,NW,NE,SE,SW;
 // Textures and framebuffers for "projection screen"
 GLuint tex_id = 0, fbo_id = 0, dfbo_id = 0;
 
@@ -191,18 +191,18 @@ void display()
     glEnable(GL_DEPTH_TEST);
     glBegin(GL_LINES);
     glColor3f(1,0,0);
-    glVertex3dv(s.data());
+    glVertex3fv(s.data());
     glColor3f(1,0,0);
-    glVertex3dv(d.data());
+    glVertex3fv(d.data());
     glEnd();
 
     // Draw the start and end points used for ray
     glPointSize(10.0);
     glBegin(GL_POINTS);
     glColor3f(1,0,0);
-    glVertex3dv(s.data());
+    glVertex3fv(s.data());
     glColor3f(0,0,1);
-    glVertex3dv(d.data());
+    glVertex3fv(d.data());
     glEnd();
   }
 
@@ -245,10 +245,10 @@ void display()
     glColor4f(0,0,0,1.0);
     glPointSize(10.0);
     glBegin(GL_POINTS);
-    glVertex3dv(SW.data());
-    glVertex3dv(SE.data());
-    glVertex3dv(NE.data());
-    glVertex3dv(NW.data());
+    glVertex3fv(SW.data());
+    glVertex3fv(SE.data());
+    glVertex3fv(NE.data());
+    glVertex3fv(NW.data());
     glEnd();
 
     glDisable(GL_LIGHTING);
@@ -257,13 +257,13 @@ void display()
     glColor4f(1,1,1,0.7);
     glBegin(GL_QUADS);
     glTexCoord2d(0,0);
-    glVertex3dv(SW.data());
+    glVertex3fv(SW.data());
     glTexCoord2d(1,0);
-    glVertex3dv(SE.data());
+    glVertex3fv(SE.data());
     glTexCoord2d(1,1);
-    glVertex3dv(NE.data());
+    glVertex3fv(NE.data());
     glTexCoord2d(0,1);
-    glVertex3dv(NW.data());
+    glVertex3fv(NW.data());
     glEnd();
     glBindTexture(GL_TEXTURE_2D, 0);
     glDisable(GL_TEXTURE_2D);
@@ -287,7 +287,7 @@ void display()
     glLoadIdentity();
     glPointSize(20.0);
     glBegin(GL_POINTS);
-    glVertex2dv(win_s.data());
+    glVertex2fv(win_s.data());
     glEnd();
   }
   report_gl_error();
@@ -316,8 +316,8 @@ void mouse_move(int mouse_x, int mouse_y)
   push_scene();
   push_object();
   // Unproject mouse at 0 depth and some positive depth
-  win_s = Vector3d(mouse_x,height-mouse_y,0);
-  Vector3d win_d(mouse_x,height-mouse_y,1);
+  win_s = Vector3f(mouse_x,height-mouse_y,0);
+  Vector3f win_d(mouse_x,height-mouse_y,1);
   unproject(win_s,s);
   unproject(win_d,d);
   pop_object();
@@ -463,7 +463,7 @@ int main(int argc, char * argv[])
     V.colwise().minCoeff()).maxCoeff();
 
   // Init embree
-  ei.init(V,F);
+  ei.init(V.cast<float>(),F.cast<int>());
 
   // Init glut
   glutInit(&argc,argv);

+ 28 - 67
include/igl/embree/EmbreeIntersector.h

@@ -14,32 +14,29 @@
 
 namespace igl
 {
-  template <
-  typename Scalar,
-  typename Index>
   class EmbreeIntersector
   {
   public:
     // 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 void global_init();
+    static inline void global_init();
   private:
     // Deinitialize the embree engine. This should probably never be called by
     // the user. Hence it's private. Do you really want to do this?
-    static void global_deinit();
+    static inline void global_deinit();
   public:
-    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> PointMatrixType;
-    typedef Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>  FaceMatrixType;
-    typedef Eigen::Matrix<Scalar,1,3> RowVector3;
+    typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic> PointMatrixType;
+    typedef Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>  FaceMatrixType;
+    typedef Eigen::Matrix<float,1,3> RowVector3;
   public:
-    EmbreeIntersector();
+    inline EmbreeIntersector();
   private:
     // Copying and assignment are not allowed.
-    EmbreeIntersector(const EmbreeIntersector & that);
-    EmbreeIntersector operator=(const EmbreeIntersector &);
+    inline EmbreeIntersector(const EmbreeIntersector & that);
+    inline EmbreeIntersector operator=(const EmbreeIntersector &);
   public:
-    virtual ~EmbreeIntersector();
+    virtual inline ~EmbreeIntersector();
       
     // Initialize with a given mesh.
     //
@@ -48,7 +45,7 @@ namespace igl
     //   F  #F by 3 list of Oriented triangles
     // Side effects:
     //   The first time this is ever called the embree engine is initialized.
-    void init(
+    inline void init(
       const PointMatrixType & V,
       const FaceMatrixType & F,
       const char* structure = "default",
@@ -57,7 +54,7 @@ namespace igl
     // Deinitialize embree datasctructures for current mesh.  Also called on
     // destruction: no need to call if you just want to init() once and
     // destroy.
-    void deinit();
+    inline void deinit();
   
     // Given a ray find the first hit
     // 
@@ -67,7 +64,7 @@ namespace igl
     // Output:
     //   hit        information about hit
     // Returns true if and only if there was a hit
-    bool intersectRay(
+    inline bool intersectRay(
       const RowVector3& origin, 
       const RowVector3& direction,
       Hit& hit,
@@ -83,7 +80,7 @@ namespace igl
     //   hit        information about hit
     //   num_rays   number of rays shot (at least one)
     // Returns true if and only if there was a hit
-    bool intersectRay(
+    inline bool intersectRay(
       const RowVector3& origin,
       const RowVector3& direction,
       std::vector<Hit > &hits,
@@ -99,7 +96,7 @@ namespace igl
     // Output:
     //   hit  information about hit
     // Returns true if and only if there was a hit
-    bool intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const;
+    inline bool intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const;
     
   private:
     embree::RTCGeometry* mesh;
@@ -125,10 +122,7 @@ namespace igl
 template <typename RowVector3>
 inline embree::Vector3f toVector3f(const RowVector3 &p) { return embree::Vector3f((float)p[0], (float)p[1], (float)p[2]); }
 
-template <
-typename Scalar,
-typename Index>
-void igl::EmbreeIntersector < Scalar, Index>::global_init()
+inline void igl::EmbreeIntersector::global_init()
 {
   if(!EmbreeIntersector_inited)
   {
@@ -141,10 +135,7 @@ void igl::EmbreeIntersector < Scalar, Index>::global_init()
   }
 }
 
-template <
-typename Scalar,
-typename Index>
-void igl::EmbreeIntersector < Scalar, Index>::global_deinit()
+inline void igl::EmbreeIntersector::global_deinit()
 {
   EmbreeIntersector_inited = false;
   embree::rtcStopThreads();
@@ -152,10 +143,7 @@ void igl::EmbreeIntersector < Scalar, Index>::global_deinit()
   embree::rtcFreeMemory();
 }
 
-template <
-typename Scalar,
-typename Index>
-igl::EmbreeIntersector < Scalar, Index>::EmbreeIntersector()
+inline igl::EmbreeIntersector::EmbreeIntersector()
   :
   mesh(NULL),
   triangles(NULL),
@@ -164,31 +152,21 @@ igl::EmbreeIntersector < Scalar, Index>::EmbreeIntersector()
 {
 }
 
-template <
-typename Scalar,
-typename Index>
-igl::EmbreeIntersector < Scalar, Index>::EmbreeIntersector(
+inline igl::EmbreeIntersector::EmbreeIntersector(
   const EmbreeIntersector & that)
 {
   assert(false && "Copying EmbreeIntersector is not allowed");
 }
 
-template <
-typename Scalar,
-typename Index>
-igl::EmbreeIntersector <Scalar,Index> 
-igl::EmbreeIntersector < Scalar, Index>::operator=(
-  const EmbreeIntersector<Scalar, Index> & that)
+inline igl::EmbreeIntersector igl::EmbreeIntersector::operator=(
+  const EmbreeIntersector & that)
 {
   assert(false && "Assigning an EmbreeIntersector is not allowed");
   return *this;
 }
 
 
-template <
-typename Scalar,
-typename Index>
-void igl::EmbreeIntersector < Scalar, Index>::init(
+inline void igl::EmbreeIntersector::init(
   const PointMatrixType & V,
   const FaceMatrixType & F,
   const char* structure,
@@ -227,30 +205,19 @@ void igl::EmbreeIntersector < Scalar, Index>::init(
   intersector = embree::rtcQueryIntersector1(mesh,traverser);
 }
 
-template <
-typename Scalar,
-typename Index>
-igl::EmbreeIntersector < Scalar, Index>
+igl::EmbreeIntersector
 ::~EmbreeIntersector()
 {
   deinit();
 }
 
-template <
-typename Scalar,
-typename Index>
-void igl::EmbreeIntersector < Scalar, Index>::deinit()
+void igl::EmbreeIntersector::deinit()
 {
   embree::rtcDeleteIntersector1(intersector);
   embree::rtcDeleteGeometry(mesh);
 }
 
-template <
-typename Scalar,
-typename Index>
-bool 
-igl::EmbreeIntersector< Scalar, Index>
-::intersectRay(
+inline bool igl::EmbreeIntersector::intersectRay(
   const RowVector3& origin,
   const RowVector3& direction,
   Hit& hit,
@@ -272,11 +239,8 @@ igl::EmbreeIntersector< Scalar, Index>
   return false;
 }
 
-template <
-typename Scalar,
-typename Index>
-bool 
-igl::EmbreeIntersector < Scalar, Index>
+inline bool 
+igl::EmbreeIntersector
 ::intersectRay(
   const RowVector3& origin, 
   const RowVector3& direction,
@@ -370,11 +334,8 @@ igl::EmbreeIntersector < Scalar, Index>
   return hits.empty();
 }
 
-template <
-typename Scalar,
-typename Index>
-bool 
-igl::EmbreeIntersector < Scalar, Index>
+inline bool 
+igl::EmbreeIntersector
 ::intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const
 {
   embree::Ray ray(toVector3f(a), toVector3f(ab), embree::zero, embree::one);

+ 9 - 13
include/igl/embree/ambient_occlusion.cpp

@@ -4,13 +4,11 @@
 #include <igl/EPS.h>
 
 template <
-  typename Scalar,
-  typename Index,
   typename DerivedP,
   typename DerivedN,
   typename DerivedS >
 void igl::ambient_occlusion(
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
+  const igl::EmbreeIntersector & ei,
   const Eigen::PlainObjectBase<DerivedP> & P,
   const Eigen::PlainObjectBase<DerivedN> & N,
   const int num_samples,
@@ -26,14 +24,14 @@ void igl::ambient_occlusion(
   // loop over mesh vertices
   for(int p = 0;p<n;p++)
   {
-    const Vector3d origin = P.row(p);
-    const Vector3d normal = N.row(p);
+    const Vector3f origin = P.row(p).template cast<float>();
+    const Vector3f normal = N.row(p).template cast<float>();
     int num_hits = 0;
-    MatrixXd D = random_dir_stratified(num_samples);
+    MatrixXf D = random_dir_stratified(num_samples).cast<float>();
     for(int s = 0;s<num_samples;s++)
     {
       //Vector3d d = random_dir();
-      Vector3d d = D.row(s);
+      Vector3f d = D.row(s);
       if(d.dot(normal) < 0)
       {
         // reverse ray
@@ -66,16 +64,14 @@ void igl::ambient_occlusion(
 {
   using namespace igl;
   using namespace Eigen;
-  EmbreeIntersector<
-    typename DerivedV::Scalar,
-    typename DerivedF::Scalar > ei;
-  ei.init(V,F);
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),F.template cast<int>());
   ambient_occlusion(ei,P,N,num_samples,S);
 }
 
 #ifndef IGL_HEADER_ONLY
 // Explicit template instanciation
-template void igl::ambient_occlusion<double, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::EmbreeIntersector<double, int> 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> >&);
-template void igl::ambient_occlusion<double, int, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::EmbreeIntersector<double, int> 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> >&);
+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> >(igl::EmbreeIntersector 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> >&);
+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> >(igl::EmbreeIntersector 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> >&);
 template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -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<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> >&);
 #endif

+ 1 - 6
include/igl/embree/ambient_occlusion.h

@@ -5,9 +5,6 @@
 namespace igl
 {
   // Forward define
-  template <
-    typename Scalar,
-    typename Index>
   class EmbreeIntersector;
   // Compute ambient occlusion per given point
   //
@@ -20,13 +17,11 @@ namespace igl
   //      (not occluded)
   //
   template <
-    typename Scalar,
-    typename Index,
     typename DerivedP,
     typename DerivedN,
     typename DerivedS >
   void ambient_occlusion(
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
+    const igl::EmbreeIntersector & ei,
     const Eigen::PlainObjectBase<DerivedP> & P,
     const Eigen::PlainObjectBase<DerivedN> & N,
     const int num_samples,

+ 6 - 3
include/igl/embree/bone_visible.cpp

@@ -26,8 +26,8 @@ IGL_INLINE void igl::bone_visible(
   FF.resize(F.rows()*2,F.cols());
   FF << F, F.rowwise().reverse();
   // Initialize intersector
-  EmbreeIntersector<double,int> ei;
-  ei.init(V,FF);
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),FF.template cast<int>());
   const double sd_norm = (s-d).norm();
   // Embree seems to be parallel when constructing but not when tracing rays
 #pragma omp parallel for
@@ -68,7 +68,10 @@ IGL_INLINE void igl::bone_visible(
     // perhaps 1.0 should be 1.0-epsilon, or actually since we checking the
     // incident face, perhaps 1.0 should be 1.0+eps
     const Vector3d dir = (Vv-projv)*1.0;
-    if(ei.intersectSegment(projv,dir, hit))
+    if(ei.intersectSegment(
+       projv.template cast<float>(),
+       dir.template cast<float>(), 
+       hit))
     {
       // mod for double sided lighting
       const int fi = hit.id % F.rows();

+ 4 - 4
include/igl/embree/orient_outward_ao.cpp

@@ -32,8 +32,8 @@ IGL_INLINE void igl::orient_outward_ao(
   MatrixXi F2;
   F2.resize(F.rows()*2,F.cols());
   F2 << F, F.rowwise().reverse().eval();
-  EmbreeIntersector<typename DerivedV::Scalar, typename DerivedF::Scalar> ei;
-  ei.init(V,F2);
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),F2.template cast<int>());
   
   // number of faces
   const int m = F.rows();
@@ -143,8 +143,8 @@ IGL_INLINE void igl::orient_outward_ao(
     int c = C(f);
     Hit hit_front;
     Hit hit_back;
-    double dist_front = ei.intersectRay(o,  d, hit_front) ? get_dist(hit_front, o) : dist_large;
-    double dist_back  = ei.intersectRay(o, -d, hit_back ) ? get_dist(hit_back , o) : dist_large;
+    double dist_front = ei.intersectRay(o.template cast<float>(),  d.template cast<float>(), hit_front) ? get_dist(hit_front, o) : dist_large;
+    double dist_back  = ei.intersectRay(o.template cast<float>(), -d.template cast<float>(), hit_back ) ? get_dist(hit_back , o) : dist_large;
 #pragma omp atomic
     C_occlude_dist_front[c] += dist_front;
 #pragma omp atomic

+ 8 - 11
include/igl/embree/unproject_in_mesh.cpp

@@ -4,13 +4,11 @@
 #include <vector>
 
 template <
-  typename Scalar,
-  typename Index,
   typename Derivedobj>
 int igl::unproject_in_mesh(
   const int x,
   const int y,
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
+  const igl::EmbreeIntersector & ei,
   Eigen::PlainObjectBase<Derivedobj> & obj)
 {
   std::vector<igl::Hit> hits;
@@ -18,13 +16,11 @@ int igl::unproject_in_mesh(
 }
 
 template <
-  typename Scalar,
-  typename Index,
   typename Derivedobj>
 int igl::unproject_in_mesh(
   const int x,
   const int y,
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
+  const igl::EmbreeIntersector & ei,
   Eigen::PlainObjectBase<Derivedobj> & obj,
   std::vector<igl::Hit > & hits)
 {
@@ -32,10 +28,10 @@ int igl::unproject_in_mesh(
   using namespace std;
   using namespace Eigen;
   // Source and direction on screen
-  Vector3d win_s = Vector3d(x,y,0);
-  Vector3d win_d(x,y,1);
+  Vector3f win_s = Vector3f(x,y,0);
+  Vector3f win_d(x,y,1);
   // Source, destination and direction in world
-  Vector3d s,d,dir;
+  Vector3f s,d,dir;
   unproject(win_s,s);
   unproject(win_d,d);
   dir = d-s;
@@ -49,13 +45,13 @@ int igl::unproject_in_mesh(
       break;
     case 1:
     {
-      obj = s + dir*hits[0].t;
+      obj = (s + dir*hits[0].t).cast<typename Derivedobj::Scalar>();
       break;
     }
     case 2:
     default:
     {
-      obj = 0.5*((s + dir*hits[0].t) + (s + dir*hits[1].t));
+      obj = 0.5*((s + dir*hits[0].t) + (s + dir*hits[1].t)).cast<typename Derivedobj::Scalar>();
       break;
     }
   }
@@ -63,4 +59,5 @@ int igl::unproject_in_mesh(
 }
 
 #ifndef IGL_HEADER_ONLY
+template int igl::unproject_in_mesh<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(int, int, igl::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
 #endif

+ 2 - 9
include/igl/embree/unproject_in_mesh.h

@@ -9,9 +9,6 @@
 namespace igl
 {
   // Forward define
-  template <
-    typename Scalar,
-    typename Index>
   class EmbreeIntersector;
   // Unproject a screen location (using current opengl viewport, projection, and
   // model view) to a 3D position 
@@ -25,23 +22,19 @@ namespace igl
   // Returns number of hits
   //
   template <
-    typename Scalar,
-    typename Index,
     typename Derivedobj>
   int unproject_in_mesh(
     const int x,
     const int y,
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
+    const igl::EmbreeIntersector & ei,
     Eigen::PlainObjectBase<Derivedobj> & obj);
 
   template <
-    typename Scalar,
-    typename Index,
     typename Derivedobj>
   int unproject_in_mesh(
     const int x,
     const int y,
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
+    const igl::EmbreeIntersector & ei,
     Eigen::PlainObjectBase<Derivedobj> & obj,
     std::vector<igl::Hit > & hits);
 }

+ 1 - 0
include/igl/unproject.cpp

@@ -53,6 +53,7 @@ IGL_INLINE Eigen::PlainObjectBase<Derivedwin> igl::unproject(
 template int igl::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
 template int igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 template Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
+template int igl::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 #endif
 
 #endif