Bläddra i källkod

direct delta mush tutorial

Dxyk 5 år sedan
förälder
incheckning
6eb02be7db

+ 39 - 15
include/igl/direct_delta_mush.cpp

@@ -6,24 +6,42 @@
 // 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 "direct_delta_mush.h"
+#include "cotmatrix.h"
+#include "diag.h"
+
+
+// ===== DEBUG: START
+#include <Eigen/Geometry>
+#include <Eigen/Sparse>
+#include <Eigen/LU>
+#include <iostream>
+
+using namespace std;
+// ===== DEBUG: END
+
+// TODOs:
+// 1. All `Scalar`s are temporarily substituted as `DerivedV`
 
 template <
   typename DerivedV,
   typename DerivedF,
   typename DerivedC,
   typename DerivedE,
+  typename DerivedW,
   typename DerivedT,
+  typename DerivedTAlloc,
   typename DerivedU>
-IGL_INLINE void direct_delta_mush(
+IGL_INLINE void igl::direct_delta_mush(
   const Eigen::MatrixBase<DerivedV> &V,
   const Eigen::MatrixBase<DerivedF> &F,
   const Eigen::MatrixBase<DerivedC> &C,
   const Eigen::MatrixBase<DerivedE> &E,
-  const std::vector<
-    Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>> &T,
+  const Eigen::MatrixBase<DerivedW> &W,
+  const std::vector<DerivedT, DerivedTAlloc> &T,
   Eigen::PlainObjectBase<DerivedU> &U)
 {
-  return;
+  cout << "START DDM" << endl;
+  cout << "END DDM" << endl;
 }
 
 template <
@@ -31,33 +49,39 @@ template <
   typename DerivedF,
   typename DerivedC,
   typename DerivedE,
+  typename DerivedW,
   typename DerivedOmega>
-IGL_INLINE void precomputation(
+IGL_INLINE void igl::direct_delta_mush_precomputation(
   const Eigen::MatrixBase<DerivedV> &V,
   const Eigen::MatrixBase<DerivedF> &F,
   const Eigen::MatrixBase<DerivedC> &C,
   const Eigen::MatrixBase<DerivedE> &E,
+  const Eigen::MatrixBase<DerivedW> &W,
   const int p,
   const typename DerivedV::Scalar lambda,
   const typename DerivedV::Scalar kappa,
   Eigen::PlainObjectBase<DerivedOmega> &Omega)
 {
-  return;
+  cout << "START DDM Precomputation" << endl;
+  cout << "END DDM Precomputation" << endl;
 }
 
 template <
-  typename DerivedV,
-  typename DerivedF,
-  typename DerivedC,
-  typename DerivedE,
   typename DerivedT,
+  typename DerivedTAlloc,
   typename DerivedOmega,
   typename DerivedU>
-IGL_INLINE void pose_evaluation(
-  const std::vector<
-    Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>> &T,
+IGL_INLINE void igl::direct_delta_mush_pose_evaluation(
+  const std::vector<DerivedT, DerivedTAlloc> &T,
   const Eigen::MatrixBase<DerivedOmega> &Omega,
   Eigen::PlainObjectBase<DerivedU> &U)
 {
-  return;
-}
+  cout << "START DDM Pose Eval" << endl;
+  cout << "END DDM Pose Eval" << endl;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::direct_delta_mush<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::__1::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::direct_delta_mush_precomputation<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<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 19 - 12
include/igl/direct_delta_mush.h

@@ -8,10 +8,12 @@
 #ifndef IGL_DIRECT_DELTA_MUSH_H
 #define IGL_DIRECT_DELTA_MUSH_H
 
-#include <igl/igl_inline.h>
+#include "igl_inline.h"
 
 #include <Eigen/Core>
-#include <Eigen/Geometry>
+// #include <Eigen/Geometry>
+#include <Eigen/Sparse>
+// #include <Eigen/LU>
 #include <vector>
 
 namespace igl {
@@ -31,15 +33,17 @@ namespace igl {
     typename DerivedF,
     typename DerivedC,
     typename DerivedE,
+    typename DerivedW,
     typename DerivedT,
+    typename DerivedTAlloc,
     typename DerivedU>
   IGL_INLINE void direct_delta_mush(
     const Eigen::MatrixBase<DerivedV> &V,
     const Eigen::MatrixBase<DerivedF> &F,
     const Eigen::MatrixBase<DerivedC> &C,
     const Eigen::MatrixBase<DerivedE> &E,
-    const std::vector<
-      Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>> &T, /* should eventually be templated more generally than double */
+    const Eigen::MatrixBase<DerivedW> &W,
+    const std::vector<DerivedT, DerivedTAlloc> &T,
     Eigen::PlainObjectBase<DerivedU> &U);
 
   // Precomputation
@@ -49,6 +53,7 @@ namespace igl {
   //   F  #F by 3 list of triangle indices into rows of V
   //   C  #C by 3 list of rest pose bone endpoint positions
   //   E  #T by 2 list of bone edge indices into rows of C
+  //   W  #V by #C list of weights // TODO: this could be a sparse matrix?
   //   p  number of smoothing iterations
   //   lambda  smoothing step size
   //   kappa  smoothness parameter (section 3.3)
@@ -59,12 +64,14 @@ namespace igl {
     typename DerivedF,
     typename DerivedC,
     typename DerivedE,
+    typename DerivedW,
     typename DerivedOmega>
-  IGL_INLINE void precomputation(
+  IGL_INLINE void direct_delta_mush_precomputation(
     const Eigen::MatrixBase<DerivedV> &V,
     const Eigen::MatrixBase<DerivedF> &F,
     const Eigen::MatrixBase<DerivedC> &C,
     const Eigen::MatrixBase<DerivedE> &E,
+    const Eigen::MatrixBase<DerivedW> &W,
     const int p,
     const typename DerivedV::Scalar lambda,
     const typename DerivedV::Scalar kappa,
@@ -76,18 +83,18 @@ namespace igl {
   // Outputs:
   //   U  #V by 3 list of output vertex positions
   template <
-    typename DerivedV,
-    typename DerivedF,
-    typename DerivedC,
-    typename DerivedE,
     typename DerivedT,
+    typename DerivedTAlloc,
     typename DerivedOmega,
     typename DerivedU>
-  IGL_INLINE void pose_evaluation(
-    const std::vector<
-      Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>> &T, /* should eventually be templated more generally than double */
+  IGL_INLINE void direct_delta_mush_pose_evaluation(
+    const std::vector<DerivedT, DerivedTAlloc> &T,
     const Eigen::MatrixBase<DerivedOmega> &Omega,
     Eigen::PlainObjectBase<DerivedU> &U);
 } // namespace igl
 
+#ifndef IGL_STATIC_LIBRARY
+#  include "direct_delta_mush.cpp"
+#endif
+
 #endif

+ 6 - 0
tutorial/408_DirectDeltaMush/CMakeLists.txt

@@ -0,0 +1,6 @@
+get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+project(${PROJECT_NAME})
+
+add_executable(${PROJECT_NAME}_bin main.cpp)
+target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)
+

+ 152 - 0
tutorial/408_DirectDeltaMush/main.cpp

@@ -0,0 +1,152 @@
+#include <igl/direct_delta_mush.h>
+#include <igl/directed_edge_orientations.h>
+#include <igl/directed_edge_parents.h>
+#include <igl/forward_kinematics.h>
+#include <igl/PI.h>
+#include <igl/lbs_matrix.h>
+#include <igl/deform_skeleton.h>
+#include <igl/dqs.h>
+#include <igl/readDMAT.h>
+#include <igl/readOBJ.h>
+#include <igl/readTGF.h>
+#include <igl/opengl/glfw/Viewer.h>
+
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+
+#include "tutorial_shared_path.h"
+
+typedef std::vector<Eigen::Quaterniond, Eigen::aligned_allocator<Eigen::Quaterniond>>
+  RotationList;
+
+typedef std::vector<Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d>>
+  TransformationList;
+
+const Eigen::RowVector3d sea_green(70. / 255., 252. / 255., 167. / 255.);
+Eigen::MatrixXd V, W, C, U, M, Omega;
+Eigen::MatrixXi F, BE;
+Eigen::VectorXi P;
+std::vector<RotationList> poses;
+double anim_t = 0.0;
+double anim_t_dir = 0.015;
+bool use_dqs = false;
+bool recompute = true;
+float p = 10;
+float lambda = 1.;
+float kappa = 1.;
+
+bool pre_draw(igl::opengl::glfw::Viewer &viewer)
+{
+  using namespace Eigen;
+  using namespace std;
+  if (recompute) {
+    // Find pose interval
+    const int begin = (int)floor(anim_t) % poses.size();
+    const int end = (int)(floor(anim_t) + 1) % poses.size();
+    const double t = anim_t - floor(anim_t);
+
+    // Interpolate pose and identity
+    RotationList anim_pose(poses[begin].size());
+    for (int e = 0; e < poses[begin].size(); e++) {
+      anim_pose[e] = poses[begin][e].slerp(t, poses[end][e]);
+    }
+    // Propagate relative rotations via FK to retrieve absolute transformations
+    RotationList vQ;
+    vector<Vector3d> vT;
+    igl::forward_kinematics(C, BE, P, anim_pose, vQ, vT);
+    const int dim = C.cols();
+    MatrixXd T(BE.rows() * (dim + 1), dim);
+    TransformationList T_list(BE.rows());
+    for (int e = 0; e < BE.rows(); e++) {
+      Affine3d a = Affine3d::Identity();
+      a.translate(vT[e]);
+      a.rotate(vQ[e]);
+      T.block(e * (dim + 1), 0, dim + 1, dim) =
+        a.matrix().transpose().block(0, 0, dim + 1, dim);
+    }
+    // Compute deformation via LBS as matrix multiplication
+    if (use_dqs) {
+      igl::direct_delta_mush(V, F, C, BE, W, T_list, U);
+    }
+    else {
+      U = M * T;
+    }
+
+    // Also deform skeleton edges
+    MatrixXd CT;
+    MatrixXi BET;
+    igl::deform_skeleton(C, BE, T, CT, BET);
+
+    viewer.data().set_vertices(U);
+    viewer.data().set_edges(CT, BET, sea_green);
+    viewer.data().compute_normals();
+    if (viewer.core().is_animating) {
+      anim_t += anim_t_dir;
+    }
+    else {
+      recompute = false;
+    }
+  }
+  return false;
+}
+
+bool key_down(igl::opengl::glfw::Viewer &viewer, unsigned char key, int mods)
+{
+  recompute = true;
+  switch (key) {
+    case 'D':
+    case 'd':
+      use_dqs = !use_dqs;
+      return true;
+    case ' ':
+      viewer.core().is_animating = !viewer.core().is_animating;
+      return true;
+  }
+  return false;
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace Eigen;
+  using namespace std;
+  igl::readOBJ(TUTORIAL_SHARED_PATH "/arm.obj", V, F);
+  U = V;
+  igl::readTGF(TUTORIAL_SHARED_PATH "/arm.tgf", C, BE);
+  // retrieve parents for forward kinematics
+  igl::directed_edge_parents(BE, P);
+  RotationList rest_pose;
+  igl::directed_edge_orientations(C, BE, rest_pose);
+  poses.resize(4, RotationList(4, Quaterniond::Identity()));
+  // poses[1] // twist
+  const Quaterniond twist(AngleAxisd(igl::PI, Vector3d(1, 0, 0)));
+  poses[1][2] = rest_pose[2] * twist * rest_pose[2].conjugate();
+  const Quaterniond bend(AngleAxisd(-igl::PI * 0.7, Vector3d(0, 0, 1)));
+  poses[3][2] = rest_pose[2] * bend * rest_pose[2].conjugate();
+
+  igl::readDMAT(TUTORIAL_SHARED_PATH "/arm-weights.dmat", W);
+  igl::lbs_matrix(V, W, M);
+
+  // Precomputation for Direct Delta Mush
+  cout<<"Initializing Direct Delta Mush..."<<endl;
+  igl::direct_delta_mush_precomputation(V, F, C, BE, W, p, lambda, kappa, Omega);
+
+  // Plot the mesh with pseudocolors
+  igl::opengl::glfw::Viewer viewer;
+  viewer.data().set_mesh(U, F);
+  viewer.data().set_edges(C, BE, sea_green);
+  viewer.data().show_lines = false;
+  viewer.data().show_overlay_depth = false;
+  viewer.data().line_width = 1;
+  viewer.core().trackball_angle.normalize();
+  viewer.callback_pre_draw = &pre_draw;
+  viewer.callback_key_down = &key_down;
+  viewer.core().is_animating = false;
+  viewer.core().camera_zoom = 2.5;
+  viewer.core().animation_max_fps = 30.;
+  cout << "Press [d] to toggle between LBS and DQS" << endl
+       << "Press [space] to toggle animation" << endl;
+  viewer.launch();
+}

+ 1 - 0
tutorial/CMakeLists.txt

@@ -92,6 +92,7 @@ if(TUTORIALS_CHAPTER4)
   add_subdirectory("405_AsRigidAsPossible")
   add_subdirectory("406_FastAutomaticSkinningTransformations")
   add_subdirectory("407_BiharmonicCoordinates")
+  add_subdirectory("408_DirectDeltaMush")
 endif()
 
 # Chapter 5