Browse Source

unproject onto mesh abstracted away from embree

Former-commit-id: d96f195df20fae746154cb1d2b55d3dbf53c18c5
Alec Jacobson 9 years ago
parent
commit
81d3908f7b

+ 14 - 21
include/igl/embree/unproject_onto_mesh.cpp

@@ -7,8 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "unproject_onto_mesh.h"
 #include "EmbreeIntersector.h"
-#include <igl/unproject.h>
-#include <igl/embree/unproject_in_mesh.h>
+#include "../unproject_onto_mesh.h"
 #include <vector>
 
 IGL_INLINE bool igl::embree::unproject_onto_mesh(
@@ -23,20 +22,14 @@ IGL_INLINE bool igl::embree::unproject_onto_mesh(
 {
   using namespace std;
   using namespace Eigen;
-  MatrixXd obj;
-  vector<igl::Hit> hits;
-
-  // This is lazy, it will find more than just the first hit
-  unproject_in_mesh(pos,model,proj,viewport,ei,obj,hits);
-
-  if (hits.size()> 0)
+  const auto & shoot_ray = [&ei](
+    const Eigen::Vector3f& s,
+    const Eigen::Vector3f& dir,
+    igl::Hit & hit)->bool
   {
-    bc << 1.0-hits[0].u-hits[0].v, hits[0].u, hits[0].v;
-    fid = hits[0].id;
-    return true;
-  }
-
-  return false;
+    return ei.intersectRay(s,dir,hit);
+  };
+  return igl::unproject_onto_mesh(pos,model,proj,viewport,shoot_ray,fid,bc);
 }
 
 IGL_INLINE bool igl::embree::unproject_onto_mesh(
@@ -50,14 +43,14 @@ IGL_INLINE bool igl::embree::unproject_onto_mesh(
   int& vid)
 {
   Eigen::Vector3f bc;
-  bool hit = unproject_onto_mesh(pos,F,model,proj,viewport,ei,fid,bc);
-  int i;
-  if (hit)
+  if(!igl::embree::unproject_onto_mesh(pos,F,model,proj,viewport,ei,fid,bc))
   {
-    bc.maxCoeff(&i);
-    vid = F(fid,i);
+    return false;
   }
-  return hit;
+  int i;
+  bc.maxCoeff(&i);
+  vid = F(fid,i);
+  return true;
 }
 
 

+ 3 - 2
include/igl/unproject_in_mesh.h

@@ -49,8 +49,9 @@ namespace igl
   //    model      model matrix
   //    proj       projection matrix
   //    viewport   vieweport vector
-  //    shoot_ray  function handle that outputs hits of a given ray against a
-  //      mesh (embedded in function handles as captured variable/data)
+  //    shoot_ray  function handle that outputs first hit of a given ray
+  //      against a mesh (embedded in function handles as captured
+  //      variable/data)
   // Outputs:
   //    obj        3d unprojected mouse point in mesh
   //    hits       vector of hits

+ 76 - 0
include/igl/unproject_onto_mesh.cpp

@@ -0,0 +1,76 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_onto_mesh.h"
+#include "unproject.h"
+#include "unproject_ray.h"
+#include "ray_mesh_intersect.h"
+#include <vector>
+
+template < typename DerivedV, typename DerivedF, typename Derivedbc>
+IGL_INLINE bool igl::unproject_onto_mesh(
+  const Eigen::Vector2f& pos,
+  const Eigen::Matrix4f& model,
+  const Eigen::Matrix4f& proj,
+  const Eigen::Vector4f& viewport,
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  int & fid,
+  Eigen::PlainObjectBase<Derivedbc> & bc)
+{
+  using namespace std;
+  using namespace Eigen;
+  const auto & shoot_ray = [&V,&F](
+    const Eigen::Vector3f& s,
+    const Eigen::Vector3f& dir,
+    igl::Hit & hit)->bool
+  {
+    std::vector<igl::Hit> hits;
+    if(!ray_mesh_intersect(s,dir,V,F,hits))
+    {
+      return false;
+    }
+    hit = hits[0];
+    return true;
+  };
+  return unproject_onto_mesh(pos,model,proj,viewport,shoot_ray,fid,bc);
+}
+
+template <typename Derivedbc>
+IGL_INLINE bool igl::unproject_onto_mesh(
+  const Eigen::Vector2f& pos,
+  const Eigen::Matrix4f& model,
+  const Eigen::Matrix4f& proj,
+  const Eigen::Vector4f& viewport,
+  const std::function<
+    bool(
+      const Eigen::Vector3f&,
+      const Eigen::Vector3f&,
+      igl::Hit &)
+      > & shoot_ray,
+  int & fid,
+  Eigen::PlainObjectBase<Derivedbc> & bc)
+{
+  using namespace std;
+  using namespace Eigen;
+  Vector3f s,dir;
+  unproject_ray(pos,model,proj,viewport,s,dir);
+  Hit hit;
+  if(!shoot_ray(s,dir,hit))
+  {
+    return false;
+  }
+  bc.resize(3);
+  bc << 1.0-hit.u-hit.v, hit.u, hit.v;
+  fid = hit.id;
+  return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+#endif
+

+ 74 - 0
include/igl/unproject_onto_mesh.h

@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNPROJECT_ONTO_MESH
+#define IGL_UNPROJECT_ONTO_MESH
+#include "igl_inline.h"
+#include "Hit.h"
+#include <Eigen/Core>
+#include <functional>
+
+namespace igl
+{
+  // Unproject a screen location (using current opengl viewport, projection, and
+  // model view) to a 3D position _onto_ a given mesh, if the ray through the
+  // given screen location (x,y) _hits_ the mesh.
+  //
+  // Inputs:
+  //    pos        screen space coordinates
+  //    model      model matrix
+  //    proj       projection matrix
+  //    viewport   vieweport vector
+  //    V   #V by 3 list of mesh vertex positions
+  //    F   #F by 3 list of mesh triangle indices into V
+  // Outputs:
+  //    fid  id of the first face hit
+  //    bc  barycentric coordinates of hit
+  // Returns true if there's a hit
+  template < typename DerivedV, typename DerivedF, typename Derivedbc>
+  IGL_INLINE bool unproject_onto_mesh(
+    const Eigen::Vector2f& pos,
+    const Eigen::Matrix4f& model,
+    const Eigen::Matrix4f& proj,
+    const Eigen::Vector4f& viewport,
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    int & fid,
+    Eigen::PlainObjectBase<Derivedbc> & bc);
+  //
+  // Inputs:
+  //    pos        screen space coordinates
+  //    model      model matrix
+  //    proj       projection matrix
+  //    viewport   vieweport vector
+  //    shoot_ray  function handle that outputs hits of a given ray against a
+  //      mesh (embedded in function handles as captured variable/data)
+  // Outputs:
+  //    fid  id of the first face hit
+  //    bc  barycentric coordinates of hit
+  // Returns true if there's a hit
+  template <typename Derivedbc>
+  IGL_INLINE bool unproject_onto_mesh(
+    const Eigen::Vector2f& pos,
+    const Eigen::Matrix4f& model,
+    const Eigen::Matrix4f& proj,
+    const Eigen::Vector4f& viewport,
+    const std::function<
+      bool(
+        const Eigen::Vector3f&,
+        const Eigen::Vector3f&,
+        igl::Hit  &)
+        > & shoot_ray,
+    int & fid,
+    Eigen::PlainObjectBase<Derivedbc> & bc);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "unproject_onto_mesh.cpp"
+#endif
+#endif
+
+

+ 21 - 10
include/igl/viewer/Viewer.cpp

@@ -306,6 +306,22 @@ namespace viewer
     callback_mouse_scroll_data  = nullptr;
     callback_key_down_data      = nullptr;
     callback_key_up_data        = nullptr;
+
+#ifndef IGL_VIEWER_VIEWER_QUIET
+    const std::string usage(R"(igl::viewer::Viewer usage:
+  [drag]  Rotate scene
+  A,a     Toggle animation (tight draw loop)
+  I,i     Toggle invert normals
+  L,l     Toggle wireframe
+  O,o     Toggle orthographic/perspective projection
+  T,t     Toggle filled faces
+  Z       Snap to canonical view
+  [,]     Toggle between rotation control types (e.g. trackball, two-axis
+          valuator with fixed up)
+
+)");
+    std::cout<<usage;
+#endif
   }
 
   IGL_INLINE void Viewer::init_plugins()
@@ -456,18 +472,13 @@ namespace viewer
         return true;
 
     for (unsigned int i = 0; i<plugins.size(); ++i)
+    {
       if (plugins[i]->key_pressed(unicode_key, modifiers))
+      {
         return true;
-    const std::string usage(R"(igl::viewer::Viewer:
-A,a  Toggle animation (tight draw loop)
-I,i  Toggle invert normals
-L,l  Toggle wireframe
-O,o  Toggle orthographic/perspective projection
-T,t  Toggle filled faces
-Z    Snap to canonical view
-[,]  Toggle between rotation control types (e.g. trackball, two-axis valuator
-     with fixed up)
-)");
+      }
+    }
+
     switch(unicode_key)
     {
       case 'A':

+ 38 - 62
tutorial/607_Picking/main.cpp

@@ -1,74 +1,50 @@
+#include "tutorial_shared_path.h"
 #include <igl/readOFF.h>
+#include <igl/unproject_onto_mesh.h>
 #include <igl/viewer/Viewer.h>
-#include <igl/embree/EmbreeIntersector.h>
-#include <igl/embree/unproject_onto_mesh.h>
-
-#include <algorithm>
-
-#include "tutorial_shared_path.h"
-
-// Mesh
-Eigen::MatrixXd V;
-Eigen::MatrixXi F;
-
-// Per-vertex color
-Eigen::MatrixXd C;
-
-igl::embree::EmbreeIntersector* ei;
-
-std::vector<int> picked_vertices;
-
-bool mouse_down(igl::viewer::Viewer& viewer, int button, int modifier)
-{
-
-  using namespace Eigen;
-  using namespace std;
-
-  int vid, fid;
-
-  // Cast a ray in the view direction starting from the mouse position
-  double x = viewer.current_mouse_x;
-  double y = viewer.core.viewport(3) - viewer.current_mouse_y;
-  bool hit = igl::embree::unproject_onto_mesh(Vector2f(x,y),
-                                F,
-                                viewer.core.view * viewer.core.model,
-                                viewer.core.proj,
-                                viewer.core.viewport,
-                                *ei,
-                                fid,
-                                vid);
-
-  // If the ray hits a face, assign a red color to the closest vertex
-  if (hit)
-  {
-    cerr << "Picked face(vertex): " << fid << " (" << vid << ")" << endl;
-    C.row(vid) << 1,0,0;
-    viewer.data.set_colors(C);
-    return true;
-  }
-
-  return false;
-}
+#include <iostream>
 
 int main(int argc, char *argv[])
 {
-
-  using namespace Eigen;
-  using namespace std;
+  // Mesh with per-face color
+  Eigen::MatrixXd V, C;
+  Eigen::MatrixXi F;
   // Load a mesh in OFF format
   igl::readOFF(TUTORIAL_SHARED_PATH "/fertility.off", V, F);
-
-  // Create a BVH for raycasting
-  ei = new igl::embree::EmbreeIntersector();
-  ei->init(V.cast<float>(),F);
-
-  // Initialize the colors to white for all vertices
-  C = MatrixXd::Constant(V.rows(),3,1);
-
-  // Show mesh
+  // Initialize white
+  C = Eigen::MatrixXd::Constant(F.rows(),3,1);
   igl::viewer::Viewer viewer;
+  viewer.callback_mouse_down = 
+    [&V,&F,&C](igl::viewer::Viewer& viewer, int, int)->bool
+  {
+    int fid;
+    Eigen::Vector3f bc;
+    // Cast a ray in the view direction starting from the mouse position
+    double x = viewer.current_mouse_x;
+    double y = viewer.core.viewport(3) - viewer.current_mouse_y;
+    if(igl::unproject_onto_mesh(
+      Eigen::Vector2f(x,y),
+      viewer.core.view * viewer.core.model,
+      viewer.core.proj,
+      viewer.core.viewport,
+      V,
+      F,
+      fid,
+      bc))
+    {
+      // paint hit red
+      C.row(fid)<<1,0,0;
+      viewer.data.set_colors(C);
+      return true;
+    }
+    return false;
+  };
+  std::cout<<R"(Usage:
+  [click]  Pick face on shape
+
+)";
+  // Show mesh
   viewer.data.set_mesh(V, F);
-  viewer.callback_mouse_down = &mouse_down;
   viewer.data.set_colors(C);
   viewer.core.show_lines = false;
   viewer.launch();