浏览代码

- added tutorial example for picking using embree

Former-commit-id: 4a3d53e53ae050d5b86d975fccaaaa233cb5acf7
Daniele Panozzo 11 年之前
父节点
当前提交
9962c08af2

+ 86 - 4
include/igl/embree/unproject_in_mesh.cpp

@@ -1,15 +1,16 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 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 
+//
+// 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_in_mesh.h"
 #include "EmbreeIntersector.h"
 #include <igl/unproject.h>
 #include <vector>
 
+#ifndef IGL_OPENGL_4
 template <
   typename Derivedobj>
 IGL_INLINE int igl::unproject_in_mesh(
@@ -64,8 +65,89 @@ IGL_INLINE int igl::unproject_in_mesh(
   }
   return hits.size();
 }
+#endif
+
+template <typename Derivedobj>
+IGL_INLINE int igl::unproject_in_mesh(
+  const Eigen::Vector2f& pos,
+  const Eigen::Matrix4f& model,
+  const Eigen::Matrix4f& proj,
+  const Eigen::Vector4f& viewport,
+  const igl::EmbreeIntersector & ei,
+  Eigen::PlainObjectBase<Derivedobj> & obj,
+  std::vector<igl::Hit > & hits)
+{
+  using namespace igl;
+  using namespace std;
+  using namespace Eigen;
+  // Source and direction on screen
+  Vector3f win_s(pos(0),pos(1),0);
+  Vector3f win_d(pos(0),pos(1),1);
+  // Source, destination and direction in world
+  Vector3f s,d,dir;
+  s = igl::unproject(win_s,model,proj,viewport);
+  d = igl::unproject(win_d,model,proj,viewport);
+  dir = d-s;
+
+  // Shoot ray, collect all hits (could just collect first two)
+  int num_rays_shot;
+  hits.clear();
+  ei.intersectRay(s,dir,hits,num_rays_shot);
+  switch(hits.size())
+  {
+    case 0:
+      break;
+    case 1:
+    {
+      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)).cast<typename Derivedobj::Scalar>();
+      break;
+    }
+  }
+  return hits.size();
+}
+
+IGL_INLINE bool igl::unproject_in_mesh(
+  const Eigen::Vector2f& pos,
+  const Eigen::MatrixXi& F,
+  const Eigen::Matrix4f& model,
+  const Eigen::Matrix4f& proj,
+  const Eigen::Vector4f& viewport,
+  const igl::EmbreeIntersector & ei,
+  int& fid,
+  int& vid)
+{
+  using namespace std;
+  using namespace Eigen;
+  MatrixXd obj;
+  vector<igl::Hit> hits;
+
+  unproject_in_mesh(pos,model,proj,viewport,ei,obj,hits);
+
+  if (hits.size()> 0)
+  {
+    Vector3d bc(1.0-hits[0].u-hits[0].v, hits[0].u, hits[0].v);
+    int i;
+    bc.maxCoeff(&i);
+
+    fid = hits[0].id;
+    vid = F(fid,i);
+    return true;
+  }
+
+  return false;
+}
+
+#ifndef IGL_OPENLGL_4
 
 #ifdef IGL_STATIC_LIBRARY
 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> >&);
 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> >&);
 #endif
+
+#endif

+ 57 - 5
include/igl/embree/unproject_in_mesh.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 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 
+//
+// 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_IN_MESH
 #define IGL_UNPROJECT_IN_MESH
@@ -17,8 +17,10 @@ namespace igl
 {
   // Forward define
   class EmbreeIntersector;
+
+  #ifndef IGL_OPENGL_4
   // Unproject a screen location (using current opengl viewport, projection, and
-  // model view) to a 3D position 
+  // model view) to a 3D position
   //
   // Inputs:
   //    x  x-coordinate of mouse location
@@ -44,6 +46,56 @@ namespace igl
     const igl::EmbreeIntersector & ei,
     Eigen::PlainObjectBase<Derivedobj> & obj,
     std::vector<igl::Hit > & hits);
+  #endif
+
+// Unproject a screen location (using the given model, proj and viewewport) to a 3D position
+// and a set of hits
+//
+// Inputs:
+//    pos        screen space coordinates
+//    model      model matrix
+//    proj       projection matrix
+//    viewport   vieweport vector
+//    ei         EmbreeIntersector containing (V,F)
+// Outputs:
+//    obj        3d unprojected mouse point in mesh
+//    hits       vector of embree hits
+// Returns number of hits
+template <
+  typename Derivedobj>
+IGL_INLINE int unproject_in_mesh(
+  const Eigen::Vector2f& pos,
+  const Eigen::Matrix4f& model,
+  const Eigen::Matrix4f& proj,
+  const Eigen::Vector4f& viewport,
+  const igl::EmbreeIntersector & ei,
+  Eigen::PlainObjectBase<Derivedobj> & obj,
+  std::vector<igl::Hit > & hits);
+
+// Unproject a screen location (using the given model, proj and viewewport) to a 3D position
+// and a set of hits
+//
+// Inputs:
+//    pos        screen space coordinates
+//    F          #F by 3 face matrix
+//    model      model matrix
+//    proj       projection matrix
+//    viewport   vieweport vector
+//    ei         EmbreeIntersector containing (V,F)
+// Outputs:
+//    fid        id of the first face hit
+//    vid        vertex id of the closest vertex hit
+// Returns true if there is a hit
+IGL_INLINE bool unproject_in_mesh(
+  const Eigen::Vector2f& pos,
+  const Eigen::MatrixXi& F,
+  const Eigen::Matrix4f& model,
+  const Eigen::Matrix4f& proj,
+  const Eigen::Vector4f& viewport,
+  const igl::EmbreeIntersector & ei,
+  int& fid,
+  int& vid);
+
 }
 #ifndef IGL_STATIC_LIBRARY
 #  include "unproject_in_mesh.cpp"

+ 33 - 4
include/igl/unproject.cpp

@@ -1,13 +1,16 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 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 
+//
+// 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.h"
 #ifndef IGL_NO_OPENGL
+#ifndef IGL_OPENGL_4
 
+#include <Eigen/Dense>
+#include <Eigen/LU>
 #include "OpenGL_convenience.h"
 
 IGL_INLINE int igl::unproject(
@@ -54,6 +57,31 @@ IGL_INLINE Eigen::PlainObjectBase<Derivedwin> igl::unproject(
   return obj;
 }
 
+#endif
+#endif
+
+
+Eigen::Vector3f igl::unproject(const Eigen::Vector3f& win,
+                          const Eigen::Matrix4f& model,
+                          const Eigen::Matrix4f& proj,
+                          const Eigen::Vector4f& viewport)
+{
+  Eigen::Matrix4f Inverse = (proj * model).inverse();
+
+  Eigen::Vector4f tmp;
+  tmp << win, 1;
+  tmp(0) = (tmp(0) - viewport(0)) / viewport(2);
+  tmp(1) = (tmp(1) - viewport(1)) / viewport(3);
+  tmp = tmp.array() * 2.0f - 1.0f;
+
+  Eigen::Vector4f obj = Inverse * tmp;
+  obj /= obj(3);
+
+  return obj.head(3);
+}
+
+#ifndef IGL_NO_OPENGL
+#ifndef IGL_OPENGL_4
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instanciation
@@ -66,3 +94,4 @@ template int igl::unproject<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<
 #endif
 
 #endif
+#endif

+ 24 - 4
include/igl/unproject.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 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 
+//
+// 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_H
 #define IGL_UNPROJECT_H
@@ -32,8 +32,28 @@ namespace igl
   template <typename Derivedwin>
   IGL_INLINE Eigen::PlainObjectBase<Derivedwin> unproject(
     const Eigen::PlainObjectBase<Derivedwin> & win);
+
+// Eigen reimplementation of gluUnproject
+// Inputs:
+//   win  screen space x, y, and z coordinates
+// Returns:
+//   the unprojected x, y, and z coordinates
+// Returns return value of gluUnProject call
+IGL_INLINE Eigen::Vector3f unproject(const Eigen::Vector3f& win,
+                                     const Eigen::Matrix4f& model,
+                                     const Eigen::Matrix4f& proj,
+                                     const Eigen::Vector4f& viewport);
+
+template <typename Derivedwin, typename Derivedobj>
+IGL_INLINE int unproject(
+  const Eigen::PlainObjectBase<Derivedwin> & win,
+  Eigen::PlainObjectBase<Derivedobj> & obj);
+template <typename Derivedwin>
+IGL_INLINE Eigen::PlainObjectBase<Derivedwin> unproject(
+  const Eigen::PlainObjectBase<Derivedwin> & win);
 }
 
+
 #ifndef IGL_STATIC_LIBRARY
 #  include "unproject.cpp"
 #endif

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

@@ -52,25 +52,6 @@ Eigen::Vector3f project(const Eigen::Vector3f&  obj,
   return tmp.head(3);
 }
 
-Eigen::Vector3f unproject(const Eigen::Vector3f& win,
-                          const Eigen::Matrix4f& model,
-                          const Eigen::Matrix4f& proj,
-                          const Eigen::Vector4f& viewport)
-{
-  Eigen::Matrix4f Inverse = (proj * model).inverse();
-
-  Eigen::Vector4f tmp;
-  tmp << win, 1;
-  tmp(0) = (tmp(0) - viewport(0)) / viewport(2);
-  tmp(1) = (tmp(1) - viewport(1)) / viewport(3);
-  tmp = tmp.array() * 2.0f - 1.0f;
-
-  Eigen::Vector4f obj = Inverse * tmp;
-  obj /= obj(3);
-
-  return obj.head(3);
-}
-
 Eigen::Matrix4f lookAt (
                         const Eigen::Vector3f& eye,
                         const Eigen::Vector3f& center,
@@ -178,6 +159,7 @@ Eigen::Matrix4f translate(
 #include <igl/axis_angle_to_quat.h>
 #include <igl/trackball.h>
 #include <igl/snap_to_canonical_view_quat.h>
+#include <igl/unproject.h>
 #include <TwOpenGLCore.h>
 
 // Plugin manager (exported to other compilation units)
@@ -1075,8 +1057,8 @@ namespace igl
         case TRANSLATE:
         {
           //translation
-          Eigen::Vector3f pos1 = unproject(Eigen::Vector3f(mouse_x, viewport[3] - mouse_y, down_mouse_z), view * model, proj, viewport);
-          Eigen::Vector3f pos0 = unproject(Eigen::Vector3f(down_mouse_x, viewport[3] - down_mouse_y, down_mouse_z), view * model, proj, viewport);
+          Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, viewport[3] - mouse_y, down_mouse_z), view * model, proj, viewport);
+          Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, viewport[3] - down_mouse_y, down_mouse_z), view * model, proj, viewport);
 
           Eigen::Vector3f diff = pos1 - pos0;
           options.model_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);

+ 15 - 0
tutorial/107_Picking/CMakeLists.txt

@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.6)
+project(107_Picking)
+
+include("../CMakeLists.shared")
+
+find_package(EMBREE REQUIRED)
+
+include_directories(${EMBREE_INCLUDE_DIRS})
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+add_executable(${CMAKE_PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${CMAKE_PROJECT_NAME} ${SHARED_LIBRARIES} ${EMBREE_LIBRARIES})

+ 68 - 0
tutorial/107_Picking/main.cpp

@@ -0,0 +1,68 @@
+#include <igl/readOFF.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/embree/EmbreeIntersector.h>
+#include <igl/embree/unproject_in_mesh.h>
+
+#include <algorithm>
+
+using namespace Eigen;
+using namespace std;
+
+// Mesh
+Eigen::MatrixXd V;
+Eigen::MatrixXi F;
+
+// Per-vertex color
+MatrixXd C;
+
+igl::EmbreeIntersector* ei;
+
+vector<int> picked_vertices;
+
+bool mouse_down(igl::Viewer& viewer, int button, int modifier)
+{
+
+  int vid, fid;
+
+  // Cast a ray in the view direction starting from the mouse position
+  bool hit = unproject_in_mesh(Vector2f(viewer.current_mouse_x,viewer.viewport(3) - viewer.current_mouse_y),
+                                F,
+                                viewer.view * viewer.model,
+                                viewer.proj,
+                                viewer.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.set_colors(C);
+    return true;
+  }
+
+  return false;
+}
+
+int main(int argc, char *argv[])
+{
+  // Load a mesh in OFF format
+  igl::readOFF("../shared/fertility.off", V, F);
+
+  // Create a BVH for raycasting
+  ei = new igl::EmbreeIntersector();
+  ei->init(V.cast<float>(),F);
+
+  // Initialize the colors to white for all vertices
+  C = MatrixXd::Constant(V.rows(),3,1);
+
+  // Show mesh
+  igl::Viewer viewer;
+  viewer.set_mesh(V, F);
+  viewer.callback_mouse_down = &mouse_down;
+  viewer.set_colors(C);
+  viewer.options.show_lines = false;
+  viewer.launch();
+}

+ 4 - 0
tutorial/CMakeLists.shared

@@ -50,6 +50,10 @@ link_directories(
 
 #set(CMAKE_CXX_FLAGS -Wall -W -pedantic -std=c99)
 
+# Disable deprecated opengl code from libigl
+add_definitions(-DIGL_OPENGL_4)
+
+
 if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register")