// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2013 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/. #ifndef IGL_LBS_MATRIX_H #define IGL_LBS_MATRIX_H #include "igl_inline.h" #include #include namespace igl { /// Linear blend skinning can be expressed by V' = M * T where V' is /// a #V by dim matrix of deformed vertex positions (one vertex per row), M is a /// #V by (dim+1)*#T (composed of weights and rest positions) and T is a /// #T*(dim+1) by dim matrix of #T stacked transposed transformation matrices. /// See equations (1) and (2) in "Fast Automatic Skinning Transformations" /// [Jacobson et al 2012] /// /// @param[in] V #V by dim list of rest positions /// @param[in] W #V+ by #T list of weights /// @param[out] M #V by #T*(dim+1) /// /// In MATLAB: /// /// kron(ones(1,size(W,2)),[V ones(size(V,1),1)]).*kron(W,ones(1,size(V,2)+1)) IGL_INLINE void lbs_matrix( const Eigen::MatrixXd & V, const Eigen::MatrixXd & W, Eigen::MatrixXd & M); /// Construct a matrix that when multiplied against a column of /// affine transformation entries computes new coordinates of the vertices /// /// \note I'm not sure it makes since that the result is stored as a sparse matrix. /// The number of non-zeros per row *is* dependent on the number of mesh /// vertices and handles. /// /// @param[in] V #V by dim list of vertex rest positions /// @param[in] W #V by #handles list of correspondence weights /// @param[out] 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 /// /// \fileinfo IGL_INLINE void lbs_matrix_column( const Eigen::MatrixXd & V, const Eigen::MatrixXd & W, Eigen::SparseMatrix& M); /// \overload IGL_INLINE void lbs_matrix_column( const Eigen::MatrixXd & V, const Eigen::MatrixXd & W, Eigen::MatrixXd & M); /// \overload /// \brief W as a full matrix of weights /// (each vertex has #handles weights), a constant number of weights are given /// for each vertex. /// /// @param[in] W #V by k list of k correspondence weights per vertex /// @param[in] WI #V by k list of k correspondence weight indices per vertex. Such that /// W(j,WI(i)) gives the ith most significant correspondence weight on vertex j IGL_INLINE void lbs_matrix_column( const Eigen::MatrixXd & V, const Eigen::MatrixXd & W, const Eigen::MatrixXi & WI, Eigen::SparseMatrix& M); /// \overload IGL_INLINE void lbs_matrix_column( const Eigen::MatrixXd & V, const Eigen::MatrixXd & W, const Eigen::MatrixXi & WI, Eigen::MatrixXd & M); } #ifndef IGL_STATIC_LIBRARY #include "lbs_matrix.cpp" #endif #endif