123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- // 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_ARAP_ENERGY_TYPE_DOF_H
- #define IGL_ARAP_ENERGY_TYPE_DOF_H
- #include "igl_inline.h"
- #include <Eigen/Dense>
- #include <Eigen/Sparse>
- #include "ARAPEnergyType.h"
- #include <vector>
- namespace igl
- {
- // Caller example:
- //
- // Once:
- // arap_dof_precomputation(...)
- //
- // Each frame:
- // while(not satisfied)
- // arap_dof_update(...)
- // end
-
- template <typename LbsMatrixType, typename SSCALAR>
- struct ArapDOFData;
-
- ///////////////////////////////////////////////////////////////////////////
- //
- // Arap DOF precomputation consists of two parts the computation. The first is
- // that which depends solely on the mesh (V,F), the linear blend skinning
- // weights (M) and the groups G. Then there's the part that depends on the
- // previous precomputation and the list of free and fixed vertices.
- //
- ///////////////////////////////////////////////////////////////////////////
-
-
- // The code and variables differ from the description in Section 3 of "Fast
- // Automatic Skinning Transformations" by [Jacobson et al. 2012]
- //
- // Here is a useful conversion table:
- //
- // [article] [code]
- // S = \tilde{K} T S = CSM * Lsep
- // S --> R S --> R --shuffled--> Rxyz
- // Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
- // Pi_1 \tilde{K} CSolveBlock1
- // Peq = [T_full; P_pos]
- // T_full B_eq_fix <--- L0
- // P_pos B_eq
- // Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
- // Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
- // Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
- // T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
- //
-
- // Precomputes the system we are going to optimize. This consists of building
- // constructor matrices (to compute covariance matrices from transformations
- // and to build the poisson solve right hand side from rotation matrix entries)
- // and also prefactoring the poisson system.
- //
- // Inputs:
- // V #V by dim list of vertex positions
- // F #F by {3|4} list of face indices
- // M #V * dim by #handles * dim * (dim+1) matrix such that
- // new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
- // vectors formed by the entries in each handle's dim by dim+1
- // transformation matrix. Specifcally, A =
- // reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
- // or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
- // if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
- // handles are ordered according to P then BE (point handles before bone
- // handles)
- // G #V list of group indices (1 to k) for each vertex, such that vertex i
- // is assigned to group G(i)
- // Outputs:
- // data structure containing all necessary precomputation for calling
- // arap_dof_update
- // Returns true on success, false on error
- //
- // See also: lbs_matrix_column
- template <typename LbsMatrixType, typename SSCALAR>
- IGL_INLINE bool arap_dof_precomputation(
- const Eigen::MatrixXd & V,
- const Eigen::MatrixXi & F,
- const LbsMatrixType & M,
- const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
- ArapDOFData<LbsMatrixType, SSCALAR> & data);
-
- // Should always be called after arap_dof_precomputation, but may be called in
- // between successive calls to arap_dof_update, recomputes precomputation
- // given that there are only changes in free and fixed
- //
- // Inputs:
- // fixed_dim list of transformation element indices for fixed (or partailly
- // fixed) handles: not necessarily the complement of 'free'
- // NOTE: the constraints for fixed transformations still need to be
- // present in A_eq
- // A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
- // constraint coefficients. Each row corresponds to a linear constraint,
- // so that A_eq * L = Beq says that the linear transformation entries in
- // the column L should produce the user supplied positional constraints
- // for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
- // constrain on coordinate d of position i
- // Outputs:
- // data structure containing all necessary precomputation for calling
- // arap_dof_update
- // Returns true on success, false on error
- //
- // See also: lbs_matrix_column
- template <typename LbsMatrixType, typename SSCALAR>
- IGL_INLINE bool arap_dof_recomputation(
- const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
- const Eigen::SparseMatrix<double> & A_eq,
- ArapDOFData<LbsMatrixType, SSCALAR> & data);
-
- // Optimizes the transformations attached to each weight function based on
- // precomputed system.
- //
- // Inputs:
- // data precomputation data struct output from arap_dof_precomputation
- // Beq dim*#constraint_points constraint values.
- // L0 #handles * dim * dim+1 list of initial guess transformation entries,
- // also holds fixed transformation entries for fixed handles
- // max_iters maximum number of iterations
- // tol stopping critera parameter. If variables (linear transformation
- // matrix entries) change by less than 'tol' the optimization terminates,
- // 0.75 (weak tolerance)
- // 0.0 (extreme tolerance)
- // Outputs:
- // L #handles * dim * dim+1 list of final optimized transformation entries,
- // allowed to be the same as L
- template <typename LbsMatrixType, typename SSCALAR>
- IGL_INLINE bool arap_dof_update(
- const ArapDOFData<LbsMatrixType,SSCALAR> & data,
- const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
- const Eigen::MatrixXd & L0,
- const int max_iters,
- const double tol,
- Eigen::MatrixXd & L
- );
-
- // Structure that contains fields for all precomputed data or data that needs
- // to be remembered at update
- template <typename LbsMatrixType, typename SSCALAR>
- struct ArapDOFData
- {
- typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
- // Type of arap energy we're solving
- igl::ARAPEnergyType energy;
- //// LU decomposition precomptation data; note: not used by araf_dop_update
- //// any more, replaced by M_FullSolve
- //igl::min_quad_with_fixed_data<double> lu_data;
- // List of indices of fixed transformation entries
- Eigen::Matrix<int,Eigen::Dynamic,1> fixed_dim;
- // List of precomputed covariance scatter matrices multiplied by lbs
- // matrices
- //std::vector<Eigen::SparseMatrix<double> > CSM_M;
- std::vector<Eigen::MatrixXd> CSM_M;
- LbsMatrixType M_KG;
- // Number of mesh vertices
- int n;
- // Number of weight functions
- int m;
- // Number of dimensions
- int dim;
- // Effective dimensions
- int effective_dim;
- // List of indices into C of positional constraints
- Eigen::Matrix<int,Eigen::Dynamic,1> interpolated;
- std::vector<bool> free_mask;
- // Full quadratic coefficients matrix before lagrangian (should be dense)
- LbsMatrixType Q;
-
-
- //// Solve matrix for the global step
- //Eigen::MatrixXd M_Solve; // TODO: remove from here
-
- // Full solve matrix that contains also conversion from rotations to the right hand side,
- // i.e., solves Poisson transformations just from rotations and positional constraints
- MatrixXS M_FullSolve;
-
- // Precomputed condensed matrices (3x3 commutators folded to 1x1):
- MatrixXS CSM;
- MatrixXS CSolveBlock1;
-
- // Print timings at each update
- bool print_timings;
-
- // Dynamics
- bool with_dynamics;
- // I'm hiding the extra dynamics stuff in this struct, which sort of defeats
- // the purpose of this function-based coding style...
-
- // Time step
- double h;
-
- // L0 #handles * dim * dim+1 list of transformation entries from
- // previous solve
- MatrixXS L0;
- //// Lm1 #handles * dim * dim+1 list of transformation entries from
- //// previous-previous solve
- //MatrixXS Lm1;
- // "Velocity"
- MatrixXS Lvel0;
-
- // #V by dim matrix of external forces
- // fext
- MatrixXS fext;
-
- // Mass_tilde: MT * Mass * M
- LbsMatrixType Mass_tilde;
-
- // Force due to gravity (premultiplier)
- Eigen::MatrixXd fgrav;
- // Direction of gravity
- Eigen::Vector3d grav_dir;
- // Magnitude of gravity
- double grav_mag;
-
- // Π1 from the paper
- MatrixXS Pi_1;
-
- // Default values
- ArapDOFData():
- energy(igl::ARAP_ENERGY_TYPE_SPOKES),
- with_dynamics(false),
- h(1),
- grav_dir(0,-1,0),
- grav_mag(0)
- {
- }
- };
- }
- #ifndef IGL_STATIC_LIBRARY
- # include "arap_dof.cpp"
- #endif
- #endif
|