Selaa lähdekoodia

bone heat

Former-commit-id: c2d904ac4e45633fde179cc60c3d6a6b6d5981df
Alec Jacobson 10 vuotta sitten
vanhempi
commit
00b14da175

+ 1 - 0
RELEASE_HISTORY.txt

@@ -1,3 +1,4 @@
+1.0.3  Bone heat method
 1.0.2  Bug fix in winding number code
 1.0.2  Bug fix in winding number code
 1.0.1  Bug fixes and more CGAL support
 1.0.1  Bug fixes and more CGAL support
 1.0.0  Major beta release: many renames, tutorial, triangle wrapper, org. build
 1.0.0  Major beta release: many renames, tutorial, triangle wrapper, org. build

+ 1 - 1
VERSION.txt

@@ -3,4 +3,4 @@
 # Anyone may increment Minor to indicate a small change.
 # Anyone may increment Minor to indicate a small change.
 # Major indicates a large change or large number of changes (upload to website)
 # Major indicates a large change or large number of changes (upload to website)
 # World indicates a substantial change or release
 # World indicates a substantial change or release
-1.0.2
+1.0.3

+ 116 - 0
include/igl/embree/bone_heat.cpp

@@ -0,0 +1,116 @@
+// 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
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bone_heat.h"
+#include "EmbreeIntersector.h"
+#include "bone_visible.h"
+#include "../project_to_line_segment.h"
+#include "../cotmatrix.h"
+#include "../massmatrix.h"
+#include "../mat_min.h"
+#include <Eigen/Sparse>
+
+bool igl::bone_heat(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const Eigen::MatrixXd & C,
+  const Eigen::VectorXi & P,
+  const Eigen::MatrixXi & BE,
+  const Eigen::MatrixXi & CE,
+  Eigen::MatrixXd & W)
+{
+  using namespace std;
+  using namespace Eigen;
+  assert(CE.rows() == 0 && "Cage edges not supported.");
+  assert(C.cols() == V.cols() && "V and C should have same #cols");
+  assert(BE.cols() == 2 && "BE should have #cols=2");
+  assert(F.cols() == 3 && "F should contain triangles.");
+  assert(V.cols() == 3 && "V should contain 3D positions.");
+
+  const int n = V.rows();
+  const int np = P.rows();
+  const int nb = BE.rows();
+  const int m = np + nb;
+
+  // "double sided lighting"
+  MatrixXi FF;
+  FF.resize(F.rows()*2,F.cols());
+  FF << F, F.rowwise().reverse();
+  // Initialize intersector
+  EmbreeIntersector ei;
+  ei.init(V.cast<float>(),F.cast<int>());
+
+  typedef Matrix<bool,Dynamic,1> VectorXb;
+  typedef Matrix<bool,Dynamic,Dynamic> MatrixXb;
+  MatrixXb vis_mask(n,m);
+  // Distances
+  MatrixXd D(n,m);
+  // loop over points
+  for(int j = 0;j<np;j++)
+  {
+    const Vector3d p = C.row(P(j));
+    D.col(j) = (V.rowwise()-p.transpose()).rowwise().norm();
+    VectorXb vj;
+    bone_visible(V,F,ei,p,p,vj);
+    vis_mask.col(j) = vj;
+  }
+
+  // loop over bones
+  for(int j = 0;j<nb;j++)
+  {
+    const Vector3d s = C.row(BE(j,0));
+    const Vector3d d = C.row(BE(j,1));
+    VectorXd t,sqrD;
+    project_to_line_segment(V,s,d,t,sqrD);
+    D.col(np+j) = sqrD.array().sqrt();
+    VectorXb vj;
+    bone_visible(V,F,ei,s,d,vj);
+    vis_mask.col(np+j) = vj;
+  }
+
+  if(CE.rows() > 0)
+  {
+    cerr<<"Error: Cage edges are not supported. Ignored."<<endl;
+  }
+
+  MatrixXd PP = MatrixXd::Zero(n,m);
+  VectorXd min_D;
+  VectorXd Hdiag = VectorXd::Zero(n);
+  VectorXi J;
+  mat_min(D,2,min_D,J);
+  for(int i = 0;i<n;i++)
+  {
+    PP(i,J(i)) = 1;
+    if(vis_mask(i,J(i)))
+    {
+      double hii = pow(min_D(i),-2.); 
+      Hdiag(i) = (hii>1e10?1e10:hii);
+    }
+  }
+  SparseMatrix<double> Q,L,M;
+  cotmatrix(V,F,L);
+  massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
+  const auto & H = Hdiag.asDiagonal();
+  Q = (-L+M*H);
+  SimplicialLLT <SparseMatrix<double > > llt;
+  llt.compute(Q);
+  switch(llt.info())
+  {
+    case Eigen::Success:
+      break;
+    case Eigen::NumericalIssue:
+      cerr<<"Error: Numerical issue."<<endl;
+      return false;
+    default:
+      cerr<<"Error: Other."<<endl;
+      return false;
+  }
+
+  const auto & rhs = M*H*PP;
+  W = llt.solve(rhs);
+  return true;
+}

+ 44 - 0
include/igl/embree/bone_heat.h

@@ -0,0 +1,44 @@
+// 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
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BONE_HEAT_H
+#define IGL_BONE_HEAT_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+  // BONE_HEAT  Compute skinning weights W given a surface mesh (V,F) and an
+  // internal skeleton (C,BE) according to "Automatic Rigging" [Baran and
+  // Popovic 2007].
+  //
+  // Inputs:
+  //   V  #V by 3 list of mesh vertex positions
+  //   F  #F by 3 list of mesh corner indices into V
+  //   C  #C by 3 list of joint locations
+  //   P  #P list of point handle indices into C
+  //   BE  #BE by 2 list of bone edge indices into C
+  //   CE  #CE by 2 list of cage edge indices into **P**
+  // Outputs:
+  //   W  #V by #P+#BE matrix of weights.
+  // Returns true only on success.
+  //
+  IGL_INLINE bool bone_heat(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    const Eigen::MatrixXd & C,
+    const Eigen::VectorXi & P,
+    const Eigen::MatrixXi & BE,
+    const Eigen::MatrixXi & CE,
+    Eigen::MatrixXd & W);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "bone_heat.cpp"
+#endif
+
+#endif

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

@@ -6,7 +6,6 @@
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "bone_visible.h"
 #include "bone_visible.h"
-#include "EmbreeIntersector.h"
 #include <igl/project_to_line.h>
 #include <igl/project_to_line.h>
 #include <igl/EPS.h>
 #include <igl/EPS.h>
 #include <igl/Timer.h>
 #include <igl/Timer.h>
@@ -24,10 +23,6 @@ IGL_INLINE void igl::bone_visible(
   const Eigen::PlainObjectBase<DerivedSD> & d,
   const Eigen::PlainObjectBase<DerivedSD> & d,
   Eigen::PlainObjectBase<Derivedflag>  & flag)
   Eigen::PlainObjectBase<Derivedflag>  & flag)
 {
 {
-  using namespace igl;
-  using namespace std;
-  using namespace Eigen;
-  flag.resize(V.rows());
   // "double sided lighting"
   // "double sided lighting"
   Eigen::PlainObjectBase<DerivedF> FF;
   Eigen::PlainObjectBase<DerivedF> FF;
   FF.resize(F.rows()*2,F.cols());
   FF.resize(F.rows()*2,F.cols());
@@ -35,13 +30,33 @@ IGL_INLINE void igl::bone_visible(
   // Initialize intersector
   // Initialize intersector
   EmbreeIntersector ei;
   EmbreeIntersector ei;
   ei.init(V.template cast<float>(),FF.template cast<int>());
   ei.init(V.template cast<float>(),FF.template cast<int>());
+  return bone_visible(V,F,ei,s,d,flag);
+}
+
+template <
+  typename DerivedV, 
+  typename DerivedF, 
+  typename DerivedSD,
+  typename Derivedflag>
+IGL_INLINE void igl::bone_visible(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const igl::EmbreeIntersector & ei,
+  const Eigen::PlainObjectBase<DerivedSD> & s,
+  const Eigen::PlainObjectBase<DerivedSD> & d,
+  Eigen::PlainObjectBase<Derivedflag>  & flag)
+{
+  using namespace igl;
+  using namespace std;
+  using namespace Eigen;
+  flag.resize(V.rows());
   const double sd_norm = (s-d).norm();
   const double sd_norm = (s-d).norm();
   // Embree seems to be parallel when constructing but not when tracing rays
   // Embree seems to be parallel when constructing but not when tracing rays
 #pragma omp parallel for
 #pragma omp parallel for
   // loop over mesh vertices
   // loop over mesh vertices
   for(int v = 0;v<V.rows();v++)
   for(int v = 0;v<V.rows();v++)
   {
   {
-    Vector3d Vv = V.row(v);
+    const Vector3d Vv = V.row(v);
     // Project vertex v onto line segment sd
     // Project vertex v onto line segment sd
     //embree.intersectSegment
     //embree.intersectSegment
     double t,sqrd;
     double t,sqrd;

+ 36 - 21
include/igl/embree/bone_visible.h

@@ -9,29 +9,30 @@
 #define IGL_BONE_VISIBLE_H
 #define IGL_BONE_VISIBLE_H
 #include <igl/igl_inline.h>
 #include <igl/igl_inline.h>
 #include <Eigen/Core>
 #include <Eigen/Core>
-//
-// BONE_VISIBLE  test whether vertices of mesh are "visible" to a given bone,
-// where "visible" is defined as in [Baran & Popovic 07]. Instead of checking
-// whether each point can see *any* of the bone, we just check if each point
-// can see its own projection onto the bone segment. In other words, we project
-// each vertex v onto the bone, projv. Then we check if there are any
-// intersections between the line segment (projv-->v) and the mesh.
-//
-// [flag] = bone_visible(V,F,s,d);
-//
-// Input:
-//    s  row vector of position of start end point of bone
-//    d  row vector of position of dest end point of bone
-//    V  #V by 3 list of vertex positions
-//    F  #F by 3 list of triangle indices
-// Output:
-//    flag  #V by 1 list of bools (true) visible, (false) obstructed
-//
-// Note: This checks for hits along the segment which are facing in *any*
-// direction from the ray.
-//
+#include "EmbreeIntersector.h"
 namespace igl
 namespace igl
 {
 {
+  //
+  // BONE_VISIBLE  test whether vertices of mesh are "visible" to a given bone,
+  // where "visible" is defined as in [Baran & Popovic 07]. Instead of checking
+  // whether each point can see *any* of the bone, we just check if each point
+  // can see its own projection onto the bone segment. In other words, we project
+  // each vertex v onto the bone, projv. Then we check if there are any
+  // intersections between the line segment (projv-->v) and the mesh.
+  //
+  // [flag] = bone_visible(V,F,s,d);
+  //
+  // Input:
+  //    V  #V by 3 list of vertex positions
+  //    F  #F by 3 list of triangle indices
+  //    s  row vector of position of start end point of bone
+  //    d  row vector of position of dest end point of bone
+  // Output:
+  //    flag  #V by 1 list of bools (true) visible, (false) obstructed
+  //
+  // Note: This checks for hits along the segment which are facing in *any*
+  // direction from the ray.
+  //
   template <
   template <
     typename DerivedV, 
     typename DerivedV, 
     typename DerivedF, 
     typename DerivedF, 
@@ -43,6 +44,20 @@ namespace igl
     const Eigen::PlainObjectBase<DerivedSD> & s,
     const Eigen::PlainObjectBase<DerivedSD> & s,
     const Eigen::PlainObjectBase<DerivedSD> & d,
     const Eigen::PlainObjectBase<DerivedSD> & d,
     Eigen::PlainObjectBase<Derivedflag>  & flag);
     Eigen::PlainObjectBase<Derivedflag>  & flag);
+  // Inputs:
+  //  ei  EmbreeIntersector for mesh (V,F) should be double sided
+  template <
+    typename DerivedV, 
+    typename DerivedF, 
+    typename DerivedSD,
+    typename Derivedflag>
+  IGL_INLINE void bone_visible(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const igl::EmbreeIntersector & ei,
+    const Eigen::PlainObjectBase<DerivedSD> & s,
+    const Eigen::PlainObjectBase<DerivedSD> & d,
+    Eigen::PlainObjectBase<Derivedflag>  & flag);
 }
 }
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
 #  include "bone_visible.cpp"
 #  include "bone_visible.cpp"

+ 1 - 1
include/igl/min_quad_with_fixed.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) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can

+ 5 - 5
include/igl/mosek/mosek_quadprog.cpp

@@ -16,11 +16,6 @@
 #include "../harwell_boeing.h"
 #include "../harwell_boeing.h"
 #include "../EPS.h"
 #include "../EPS.h"
 
 
-// Little function mosek needs in order to know how to print to std out
-static void MSKAPI printstr(void *handle, char str[])
-{
-  printf("%s",str);
-}
 
 
 igl::MosekData::MosekData()
 igl::MosekData::MosekData()
 {
 {
@@ -109,6 +104,11 @@ IGL_INLINE bool igl::mosek_quadprog(
   mosek_guarded(MSK_makeenv(&env,NULL,NULL,NULL,NULL));
   mosek_guarded(MSK_makeenv(&env,NULL,NULL,NULL,NULL));
 #endif
 #endif
   ///* Directs the log stream to the 'printstr' function. */
   ///* Directs the log stream to the 'printstr' function. */
+  //// Little function mosek needs in order to know how to print to std out
+  //const auto & printstr = [](void *handle, char str[])
+  //{
+  //  printf("%s",str);
+  //}
   //mosek_guarded(MSK_linkfunctoenvstream(env,MSK_STREAM_LOG,NULL,printstr));
   //mosek_guarded(MSK_linkfunctoenvstream(env,MSK_STREAM_LOG,NULL,printstr));
   // initialize mosek environment
   // initialize mosek environment
   mosek_guarded(MSK_initenv(env));
   mosek_guarded(MSK_initenv(env));

+ 3 - 2
include/igl/project_to_line_segment.cpp

@@ -28,13 +28,14 @@ IGL_INLINE void igl::project_to_line_segment(
 #pragma omp parallel for if (np>10000)
 #pragma omp parallel for if (np>10000)
   for(int p = 0;p<np;p++)
   for(int p = 0;p<np;p++)
   {
   {
+    const Eigen::PlainObjectBase<DerivedS> Pp = P.row(p);
     if(t(p)<0)
     if(t(p)<0)
     {
     {
-      sqrD(p) = (P.row(p)-S).squaredNorm();
+      sqrD(p) = (Pp-S).squaredNorm();
       t(p) = 0;
       t(p) = 0;
     }else if(t(p)>1)
     }else if(t(p)>1)
     {
     {
-      sqrD(p) = (P.row(p)-D).squaredNorm();
+      sqrD(p) = (Pp-D).squaredNorm();
       t(p) = 1;
       t(p) = 1;
     }
     }
   }
   }