direct_delta_mush.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // This file is part of libigl, a simple C++ geometry processing library.
  2. //
  3. // Copyright (C) 2020 Xiangyu Kong <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "direct_delta_mush.h"
  9. #include "cotmatrix.h"
  10. #include <iostream>
  11. // TODOs
  12. // 1. U_precomputed, Psi, Omega should be #V by 10 instead of #V by 16
  13. // 2. Vectorize Psi computation.
  14. template <
  15. typename DerivedV,
  16. typename DerivedF,
  17. typename DerivedC,
  18. typename DerivedE,
  19. typename DerivedOmega,
  20. typename DerivedU>
  21. IGL_INLINE void igl::direct_delta_mush(
  22. const Eigen::MatrixBase<DerivedV> & V,
  23. const Eigen::MatrixBase<DerivedF> & F,
  24. const Eigen::MatrixBase<DerivedC> & C,
  25. const Eigen::MatrixBase<DerivedE> & E,
  26. const std::vector<Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d> > & T,
  27. const Eigen::MatrixBase<DerivedOmega> & Omega,
  28. Eigen::PlainObjectBase<DerivedU> & U)
  29. {
  30. using namespace std;
  31. using namespace Eigen;
  32. cout << "START DDM" << endl;
  33. cout << "V: " << V.rows() << " x " << V.cols() << " Sum: " << V.sum()
  34. << "\nF: " << F.rows() << " x " << F.cols() << " Sum: " << F.sum()
  35. << "\nC: " << C.rows() << " x " << C.cols() << " Sum: " << C.sum()
  36. << "\nE: " << E.rows() << " x " << E.cols() << " Sum: " << E.sum()
  37. << "\nT: " << T.size()
  38. << "\nOmega: " << Omega.rows() << " x " << Omega.cols() << " Sum: " << Omega.sum()
  39. << endl;
  40. assert(V.cols() == 3 && "V should contain 3D positions.");
  41. assert(F.cols() == 3 && "F should contain triangles.");
  42. assert(C.cols() == 3 && "C should contain 3D bone endpoint positions.");
  43. assert(E.cols() == 2 && "E should contain 2 endpoint indices forming bone edges.");
  44. assert(E.rows() == T.size() && "E.rows() should equal to T.size()");
  45. assert(Omega.rows() == V.rows() && "Omega contain the same number of rows as V.");
  46. assert(Omega.cols() == T.size() * 16 && "Omega should have #T*10 columns.");
  47. int n = V.rows();
  48. int m = T.size();
  49. Eigen::MatrixXd U_homogeneous(n, 4);
  50. U_homogeneous << V, Eigen::VectorXd::Ones(n);
  51. U.resize(n, 3);
  52. // R matrix
  53. Eigen::MatrixXd R_matrices(n, 9);
  54. Eigen::MatrixXd T_matrices(n, 3);
  55. for (int i = 0; i < n; i++)
  56. {
  57. Eigen::MatrixXd Q_mat = Eigen::MatrixXd::Zero(4, 4);
  58. for (int j = 0; j < m; j++)
  59. {
  60. Eigen::MatrixXd Omega_curr = Omega.block(i, j * 16, 1, 16);
  61. Omega_curr.resize(4, 4);
  62. Eigen::Affine3d M_curr = T[j];
  63. Q_mat += M_curr.matrix() * Omega_curr;
  64. }
  65. Eigen::MatrixXd Q_i = Q_mat.block(0, 0, 3, 3);
  66. Eigen::MatrixXd q_i = Q_mat.block(0, 3, 3, 1);
  67. Eigen::MatrixXd p_i = Q_mat.block(3, 0, 1, 3); // .transpose()
  68. Eigen::MatrixXd SVD_i = Q_i - q_i * p_i;
  69. Eigen::JacobiSVD<MatrixXd> svd;
  70. svd.compute(SVD_i, Eigen::ComputeFullU | Eigen::ComputeFullV );
  71. // rotation and translation
  72. Eigen::MatrixXd R_i = svd.matrixU() * svd.matrixV().transpose();
  73. Eigen::VectorXd t_i = q_i - R_i * p_i.transpose();
  74. // Gamma
  75. Eigen::MatrixXd Gamma_i(3, 4);
  76. Gamma_i.block(0, 0, 3, 3) = R_i;
  77. Gamma_i.block(0, 3, 3, 1) = t_i;
  78. // transform
  79. Eigen::VectorXd u_i = U_homogeneous.row(i);
  80. U.row(i) = Gamma_i * u_i;
  81. }
  82. cout << "END DDM" << endl;
  83. }
  84. template <
  85. typename DerivedV,
  86. typename DerivedF,
  87. typename DerivedC,
  88. typename DerivedE,
  89. typename DerivedW,
  90. typename DerivedOmega>
  91. IGL_INLINE void igl::direct_delta_mush_precomputation(
  92. const Eigen::MatrixBase<DerivedV> & V,
  93. const Eigen::MatrixBase<DerivedF> & F,
  94. const Eigen::MatrixBase<DerivedC> & C,
  95. const Eigen::MatrixBase<DerivedE> & E,
  96. const Eigen::SparseMatrix<DerivedW> & W,
  97. const int p,
  98. const typename DerivedV::Scalar lambda,
  99. const typename DerivedV::Scalar kappa,
  100. const typename DerivedV::Scalar alpha,
  101. Eigen::PlainObjectBase<DerivedOmega> & Omega)
  102. {
  103. using namespace std;
  104. using namespace Eigen;
  105. cout << "START DDM Precomputation" << endl;
  106. cout << "Using params:"
  107. << "\np: " << p
  108. << "\nlambda: " << lambda
  109. << "\nkappa: " << kappa
  110. << endl;
  111. cout << "V: " << V.rows() << " x " << V.cols() << " Sum: " << V.sum()
  112. << "\nF: " << F.rows() << " x " << F.cols() << " Sum: " << F.sum()
  113. << "\nC: " << C.rows() << " x " << C.cols() << " Sum: " << C.sum()
  114. << "\nE: " << E.rows() << " x " << E.cols() << " Sum: " << E.sum()
  115. << "\nW: " << W.rows() << " x " << W.cols() << " Sum: " << W.sum()
  116. << endl;
  117. assert(V.cols() == 3 && "V should contain 3D positions.");
  118. assert(F.cols() == 3 && "F should contain triangles.");
  119. assert(C.cols() == 3 && "C should contain 3D bone endpoint positions.");
  120. assert(E.cols() == 2 && "E should contain 2 endpoint indices forming bone edges.");
  121. assert(W.rows() == V.rows() && "W.rows() should be equal to V.rows().");
  122. assert(W.cols() == E.rows() && "W.cols() should be equal to E.rows().");
  123. assert(p > 0 && "Laplacian iteration p should be positive.");
  124. assert(lambda > 0 && "lambda should be positive.");
  125. assert(kappa > 0 && kappa < lambda && "kappa should be positive and less than lambda.");
  126. assert(alpha >= 0 && alpha < 1 && "alpha should be non-negative and less than 1.");
  127. const int n = V.rows();
  128. const int m = E.rows();
  129. // U: #V by 4, homogeneous version of V
  130. Eigen::MatrixXd U_homogeneous(n, 4);
  131. U_homogeneous << V, Eigen::VectorXd::Ones(n);
  132. // Identity of #V by #V
  133. Eigen::SparseMatrix<double> I(n, n);
  134. I.setIdentity();
  135. // Laplacian: L_bar = L \times D_L^{-1}
  136. Eigen::SparseMatrix<double> L;
  137. igl::cotmatrix(V, F, L);
  138. Eigen::MatrixXd D_L = L.diagonal().asDiagonal();
  139. Eigen::SparseMatrix<double> D_L_sparse = D_L.sparseView();
  140. Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> ldlt;
  141. ldlt.compute(D_L_sparse); // this will take quite a while to compute
  142. Eigen::SparseMatrix<double> L_bar = ldlt.solve(L).transpose();
  143. // Implicitly and iteratively solve
  144. // w'_{ij} = \sum_{k=1}^{n}{C_{ki} w_{kj}}, C = (I + kappa L_bar)^{-p}:
  145. // W' = C^T \times W
  146. Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> ldlt_W_prime;
  147. Eigen::SparseMatrix<double> C_calc((I + kappa * L_bar).transpose());
  148. Eigen::SparseMatrix<double> W_prime(W);
  149. ldlt_W_prime.compute(C_calc);
  150. cout << "computing W" << endl;
  151. for (int iter = 0; iter < p; iter++)
  152. {
  153. W_prime.makeCompressed();
  154. W_prime = ldlt_W_prime.solve(W_prime);
  155. }
  156. cout << "W_prime: " << W_prime.rows() << " x " << W_prime.cols()
  157. << " Sum: " << W_prime.sum() << endl;
  158. // Psi was hard to solve iteratively since i couldn't express u_k \times u_k^T as matrix form
  159. Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> ldlt_U_tilde;
  160. Eigen::SparseMatrix<double> B_calc((I + lambda * L_bar).transpose());
  161. ldlt_U_tilde.compute(B_calc);
  162. Eigen::SparseMatrix<double> U_tilde = U_homogeneous.sparseView();
  163. cout << "computing U_tilde" << endl;
  164. for (int i = 0; i < p; i++)
  165. {
  166. U_tilde.makeCompressed();
  167. U_tilde = ldlt_U_tilde.solve(U_tilde);
  168. }
  169. cout << "U_tilde: " << U_tilde.rows() << " x " << U_tilde.cols()
  170. << " Sum: " << U_tilde.sum() << endl;
  171. // TODO: sparse didn't work here - malloc error
  172. Eigen::MatrixXd U_tilde_dense = U_tilde.toDense();
  173. Eigen::MatrixXd B_inv_dense = U_homogeneous.transpose().householderQr().solve(
  174. U_tilde_dense.transpose());
  175. Eigen::SparseMatrix<double> B_inv = B_inv_dense.sparseView();
  176. // Eigen::SparseQR<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>> qr_B;
  177. // Eigen::SparseMatrix<double> U_sparse = U_homogeneous.sparseView();
  178. // Eigen::SparseMatrix<double> V_sparse_transpose(U_sparse.transpose());
  179. // Eigen::SparseMatrix<double> V_tilde_transpose(U_tilde.transpose());
  180. // V_sparse_transpose.makeCompressed();
  181. // qr_B.compute(V_sparse_transpose);
  182. // Eigen::SparseMatrix<double> B_inv = qr_B.solve(V_tilde_transpose);
  183. cout << "B_inv: " << B_inv.rows() << " x " << B_inv.cols() << " Sum: " << B_inv.sum() << endl;
  184. // U_precomputed: #V by 16(10)
  185. // U_precomputed.row(i) = u_i \dot u_i^T \in R^{4 x 4}
  186. Eigen::MatrixXd U_precomputed(n, 16);
  187. for (int k = 0; k < n; k++)
  188. {
  189. Eigen::MatrixXd u_full = U_homogeneous.row(k).transpose() * U_homogeneous.row(k);
  190. Eigen::VectorXd u_full_vector(
  191. Eigen::Map<Eigen::VectorXd>(u_full.data(), u_full.cols() * u_full.rows()));
  192. U_precomputed.row(k) = u_full_vector;
  193. }
  194. cout << "U_precomputed: " << U_precomputed.rows() << " x " << U_precomputed.cols()
  195. << " Sum: " << U_precomputed.sum() << endl;
  196. // Psi: #V by #T*16 (10) of \Psi_{ij}s.
  197. // this takes a while since it is not vectorized
  198. // Eigen::MatrixXd Psi = Eigen::MatrixXd::Ones(n, m * 16); // for debugging to skip computation
  199. Eigen::MatrixXd Psi(n, m * 16);
  200. for (int i = 0; i < n; i++)
  201. {
  202. for (int j = 0; j < m; j++)
  203. {
  204. Eigen::VectorXd Psi_curr = Eigen::VectorXd::Zero(16);
  205. for (int k = 0; k < n; k++)
  206. {
  207. Psi_curr += B_inv.coeff(k, i) * W.coeff(k, j) * U_precomputed.row(k);
  208. }
  209. Psi.block(i, j * 16, 1, 16) = Psi_curr.transpose();
  210. }
  211. }
  212. cout << "Psi: " << Psi.rows() << " x " << Psi.cols() << " Sum: " << Psi.sum() << endl;
  213. // precomputed P matrix: 4 by 4
  214. // p_i p_i^T , p_i
  215. // p_i^T , 1
  216. // p_i: sum_{j=1}^{n} Psi_{ij} top right 3 by 1 column
  217. Eigen::MatrixXd P_vectors(n, 16);
  218. for (int i = 0; i < n; i++)
  219. {
  220. Eigen::Vector3d p_i = Eigen::Vector3d::Zero(3);
  221. for (int j = 0; j < m; j++)
  222. {
  223. Eigen::Vector3d p_i_curr(3);
  224. p_i_curr << Psi(i, j * 16 + 3), Psi(i, j * 16 + 7), Psi(i, j * 16 + 11);
  225. p_i += p_i_curr;
  226. }
  227. Eigen::MatrixXd p_matrix(4, 4);
  228. p_matrix.block(0, 0, 3, 3) = p_i * p_i.transpose();
  229. p_matrix.block(3, 0, 1, 3) = p_i.transpose();
  230. p_matrix.block(0, 3, 3, 1) = p_i;
  231. p_matrix(3, 3) = 1;
  232. P_vectors.row(i) = Eigen::Map<Eigen::VectorXd>(
  233. p_matrix.data(), p_matrix.cols() * p_matrix.rows());
  234. }
  235. cout << "P_vectors: " << P_vectors.rows() << " x " << P_vectors.cols() << " Sum: "
  236. << P_vectors.sum() << endl;
  237. // Omega
  238. Omega.resize(n, m * 16);
  239. for (int i = 0; i < n; i++)
  240. {
  241. Eigen::MatrixXd p_vector = P_vectors.row(i);
  242. for (int j = 0; j < m; j++)
  243. {
  244. Eigen::MatrixXd Omega_curr(1, 16);
  245. Eigen::MatrixXd Psi_curr = Psi.block(i, j * 16, 1, 16);
  246. Omega_curr = (1 - alpha) * Psi_curr + alpha * W_prime.coeff(i, j) * p_vector;
  247. Omega.block(i, j * 16, 1, 16) = Omega_curr;
  248. }
  249. }
  250. cout << "Omega: " << Omega.rows() << " x " << Omega.cols() << " Sum: " << Omega.sum() << endl;
  251. cout << "END DDM Precomputation" << endl;
  252. }
  253. template <
  254. typename DerivedOmega,
  255. typename DerivedU>
  256. IGL_INLINE void igl::direct_delta_mush_pose_evaluation(
  257. const std::vector<Eigen::Affine3d, Eigen::aligned_allocator<Eigen::Affine3d> > & T,
  258. const Eigen::MatrixBase<DerivedOmega> & Omega,
  259. Eigen::PlainObjectBase<DerivedU> & U)
  260. {
  261. using namespace std;
  262. using namespace Eigen;
  263. cout << "START DDM Pose Eval" << endl;
  264. // not sure what this is
  265. cout << "END DDM Pose Eval" << endl;
  266. }
  267. #ifdef IGL_STATIC_LIBRARY
  268. // Explicit template instantiation
  269. template void
  270. 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::Matrix<double, -1, -1, 0, -1, -1> >(
  271. Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &,
  272. Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &,
  273. Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &,
  274. Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &,
  275. std::__1::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const &,
  276. Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &,
  277. Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &);
  278. template void
  279. 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>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(
  280. Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &,
  281. Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &,
  282. Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &,
  283. Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &,
  284. Eigen::SparseMatrix<double, 0, int> const &, int,
  285. Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar,
  286. Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar,
  287. Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar,
  288. Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &);
  289. template void
  290. igl::direct_delta_mush_pose_evaluation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(
  291. std::__1::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const &,
  292. Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &,
  293. Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &);
  294. #endif