frame_field_deformer.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
  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 "frame_field_deformer.h"
  9. #include <Eigen/Dense>
  10. #include <Eigen/Sparse>
  11. #include <vector>
  12. #include <igl/cotangent.h>
  13. #include <igl/cotmatrix.h>
  14. #include <igl/vf.h>
  15. #include <igl/tt.h>
  16. namespace igl
  17. {
  18. class Frame_field_deformer
  19. {
  20. public:
  21. IGL_INLINE Frame_field_deformer();
  22. IGL_INLINE ~Frame_field_deformer();
  23. // Initialize the optimizer
  24. IGL_INLINE void init(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F, const Eigen::MatrixXd& _D1, const Eigen::MatrixXd& _D2, double _Lambda, double _perturb_rotations, int _fixed = 1);
  25. // Run N optimization steps
  26. IGL_INLINE void optimize(int N, bool reset = false);
  27. // Reset optimization
  28. IGL_INLINE void reset_opt();
  29. // Precomputation of all components
  30. IGL_INLINE void precompute_opt();
  31. // Precomputation for deformation energy
  32. IGL_INLINE void precompute_ARAP(Eigen::SparseMatrix<double> & Lff, Eigen::MatrixXd & LfcVc);
  33. // Precomputation for regularization
  34. IGL_INLINE void precompute_SMOOTH(Eigen::SparseMatrix<double> & MS, Eigen::MatrixXd & bS);
  35. // extracts a r x c block from sparse matrix mat into sparse matrix m1
  36. // (r0,c0) is upper left entry of block
  37. IGL_INLINE void extractBlock(Eigen::SparseMatrix<double> & mat, int r0, int c0, int r, int c, Eigen::SparseMatrix<double> & m1);
  38. // computes optimal rotations for faces of m wrt current coords in mw.V
  39. // returns a 3x3 matrix
  40. IGL_INLINE void compute_optimal_rotations();
  41. // global optimization step - linear system
  42. IGL_INLINE void compute_optimal_positions();
  43. // compute the output XField from deformation gradient
  44. IGL_INLINE void computeXField(std::vector< Eigen::Matrix<double,3,2> > & XF);
  45. // computes in WW the ideal warp at each tri to make the frame field a cross
  46. IGL_INLINE void compute_idealWarp(std::vector< Eigen::Matrix<double,3,3> > & WW);
  47. // -------------------------------- Variables ----------------------------------------------------
  48. // Mesh I/O:
  49. Eigen::MatrixXd V; // Original mesh - vertices
  50. Eigen::MatrixXi F; // Original mesh - faces
  51. std::vector<std::vector<int> > VT; // Vertex to triangle topology
  52. std::vector<std::vector<int> > VTi; // Vertex to triangle topology
  53. Eigen::MatrixXd V_w; // Warped mesh - vertices
  54. std::vector< Eigen::Matrix<double,3,2> > FF; // frame field FF in 3D (parallel to m.F)
  55. std::vector< Eigen::Matrix<double,3,3> > WW; // warping matrices to make a cross field (parallel to m.F)
  56. std::vector< Eigen::Matrix<double,3,2> > XF; // pseudo-cross field from solution (parallel to m.F)
  57. int fixed;
  58. double perturb_rotations; // perturbation to rotation matrices
  59. // Numerics
  60. int nfree,nconst; // number of free/constrained vertices in the mesh - default all-but-1/1
  61. Eigen::MatrixXd C; // cotangent matrix of m
  62. Eigen::SparseMatrix<double> L; // Laplacian matrix of m
  63. Eigen::SparseMatrix<double> M; // matrix for global optimization - pre-conditioned
  64. Eigen::MatrixXd RHS; // pre-computed part of known term in global optimization
  65. std::vector< Eigen::Matrix<double,3,3> > RW; // optimal rotation-warping matrices (parallel to m.F) -- INCORPORATES WW
  66. Eigen::SimplicialCholesky<Eigen::SparseMatrix<double> > solver; // solver for linear system in global opt.
  67. // Parameters
  68. private:
  69. double Lambda = 0.1; // weight of energy regularization
  70. };
  71. IGL_INLINE Frame_field_deformer::Frame_field_deformer() {}
  72. IGL_INLINE Frame_field_deformer::~Frame_field_deformer() {}
  73. IGL_INLINE void Frame_field_deformer::init(const Eigen::MatrixXd& _V,
  74. const Eigen::MatrixXi& _F,
  75. const Eigen::MatrixXd& _D1,
  76. const Eigen::MatrixXd& _D2,
  77. double _Lambda,
  78. double _perturb_rotations,
  79. int _fixed)
  80. {
  81. V = _V;
  82. F = _F;
  83. assert(_D1.rows() == _D2.rows());
  84. FF.clear();
  85. for (unsigned i=0; i < _D1.rows(); ++i)
  86. {
  87. Eigen::Matrix<double,3,2> ff;
  88. ff.col(0) = _D1.row(i);
  89. ff.col(1) = _D2.row(i);
  90. FF.push_back(ff);
  91. }
  92. fixed = _fixed;
  93. Lambda = _Lambda;
  94. perturb_rotations = _perturb_rotations;
  95. reset_opt();
  96. precompute_opt();
  97. }
  98. IGL_INLINE void Frame_field_deformer::optimize(int N, bool reset)
  99. {
  100. //Reset optimization
  101. if (reset)
  102. reset_opt();
  103. // Iterative Local/Global optimization
  104. for (int i=0; i<N;i++)
  105. {
  106. compute_optimal_rotations();
  107. compute_optimal_positions();
  108. computeXField(XF);
  109. }
  110. }
  111. IGL_INLINE void Frame_field_deformer::reset_opt()
  112. {
  113. V_w = V;
  114. for (unsigned i=0; i<V_w.rows(); ++i)
  115. for (unsigned j=0; j<V_w.cols(); ++j)
  116. V_w(i,j) += (double(rand())/double(RAND_MAX))*10e-4*perturb_rotations;
  117. }
  118. // precomputation of all components
  119. IGL_INLINE void Frame_field_deformer::precompute_opt()
  120. {
  121. using namespace Eigen;
  122. nfree = V.rows() - fixed; // free vertices (at the beginning ov m.V) - global
  123. nconst = V.rows()-nfree; // #constrained vertices
  124. igl::vf(V,F,VT,VTi); // compute vertex to face relationship
  125. igl::cotangent(V,F,C); // cotangent matrix for opt. rotations - global
  126. igl::cotmatrix(V,F,L);
  127. SparseMatrix<double> MA; // internal matrix for ARAP-warping energy
  128. MatrixXd LfcVc; // RHS (partial) for ARAP-warping energy
  129. SparseMatrix<double> MS; // internal matrix for smoothing energy
  130. MatrixXd bS; // RHS (full) for smoothing energy
  131. precompute_ARAP(MA,LfcVc); // precompute terms for the ARAP-warp part
  132. precompute_SMOOTH(MS,bS); // precompute terms for the smoothing part
  133. compute_idealWarp(WW); // computes the ideal warps
  134. RW.resize(F.rows()); // init rotation matrices - global
  135. M = (1-Lambda)*MA + Lambda*MS; // matrix for linear system - global
  136. RHS = (1-Lambda)*LfcVc + Lambda*bS; // RHS (partial) for linear system - global
  137. solver.compute(M); // system pre-conditioning
  138. if (solver.info()!=Eigen::Success) {fprintf(stderr,"Decomposition failed in pre-conditioning!\n"); exit(-1);}
  139. fprintf(stdout,"Preconditioning done.\n");
  140. }
  141. IGL_INLINE void Frame_field_deformer::precompute_ARAP(Eigen::SparseMatrix<double> & Lff, Eigen::MatrixXd & LfcVc)
  142. {
  143. using namespace Eigen;
  144. fprintf(stdout,"Precomputing ARAP terms\n");
  145. SparseMatrix<double> LL = -4*L;
  146. Lff = SparseMatrix<double>(nfree,nfree);
  147. extractBlock(LL,0,0,nfree,nfree,Lff);
  148. SparseMatrix<double> Lfc = SparseMatrix<double>(nfree,nconst);
  149. extractBlock(LL,0,nfree,nfree,nconst,Lfc);
  150. LfcVc = - Lfc * V_w.block(nfree,0,nconst,3);
  151. }
  152. IGL_INLINE void Frame_field_deformer::precompute_SMOOTH(Eigen::SparseMatrix<double> & MS, Eigen::MatrixXd & bS)
  153. {
  154. using namespace Eigen;
  155. fprintf(stdout,"Precomputing SMOOTH terms\n");
  156. SparseMatrix<double> LL = 4*L*L;
  157. // top-left
  158. MS = SparseMatrix<double>(nfree,nfree);
  159. extractBlock(LL,0,0,nfree,nfree,MS);
  160. // top-right
  161. SparseMatrix<double> Mfc = SparseMatrix<double>(nfree,nconst);
  162. extractBlock(LL,0,nfree,nfree,nconst,Mfc);
  163. MatrixXd MfcVc = Mfc * V_w.block(nfree,0,nconst,3);
  164. bS = (LL*V).block(0,0,nfree,3)-MfcVc;
  165. }
  166. IGL_INLINE void Frame_field_deformer::extractBlock(Eigen::SparseMatrix<double> & mat, int r0, int c0, int r, int c, Eigen::SparseMatrix<double> & m1)
  167. {
  168. std::vector<Eigen::Triplet<double> > tripletList;
  169. for (int k=c0; k<c0+c; ++k)
  170. for (Eigen::SparseMatrix<double>::InnerIterator it(mat,k); it; ++it)
  171. {
  172. if (it.row()>=r0 && it.row()<r0+r)
  173. tripletList.push_back(Eigen::Triplet<double>(it.row()-r0,it.col()-c0,it.value()));
  174. }
  175. m1.setFromTriplets(tripletList.begin(), tripletList.end());
  176. }
  177. IGL_INLINE void Frame_field_deformer::compute_optimal_rotations()
  178. {
  179. using namespace Eigen;
  180. Matrix<double,3,3> r,S,P,PP,D;
  181. for (int i=0;i<F.rows();i++)
  182. {
  183. // input tri --- could be done once and saved in a matrix
  184. P.col(0) = (V.row(F(i,1))-V.row(F(i,0))).transpose();
  185. P.col(1) = (V.row(F(i,2))-V.row(F(i,1))).transpose();
  186. P.col(2) = (V.row(F(i,0))-V.row(F(i,2))).transpose();
  187. P = WW[i] * P; // apply ideal warp
  188. // current tri
  189. PP.col(0) = (V_w.row(F(i,1))-V_w.row(F(i,0))).transpose();
  190. PP.col(1) = (V_w.row(F(i,2))-V_w.row(F(i,1))).transpose();
  191. PP.col(2) = (V_w.row(F(i,0))-V_w.row(F(i,2))).transpose();
  192. // cotangents
  193. D << C(i,2), 0, 0,
  194. 0, C(i,0), 0,
  195. 0, 0, C(i,1);
  196. S = PP*D*P.transpose();
  197. Eigen::JacobiSVD<Matrix<double,3,3> > svd(S, Eigen::ComputeFullU | Eigen::ComputeFullV );
  198. Matrix<double,3,3> su = svd.matrixU();
  199. Matrix<double,3,3> sv = svd.matrixV();
  200. r = su*sv.transpose();
  201. if (r.determinant()<0) // correct reflections
  202. {
  203. su(0,2)=-su(0,2); su(1,2)=-su(1,2); su(2,2)=-su(2,2);
  204. r = su*sv.transpose();
  205. }
  206. RW[i] = r*WW[i]; // RW INCORPORATES IDEAL WARP WW!!!
  207. }
  208. }
  209. IGL_INLINE void Frame_field_deformer::compute_optimal_positions()
  210. {
  211. using namespace Eigen;
  212. // compute variable RHS of ARAP-warp part of the system
  213. MatrixXd b(nfree,3); // fx3 known term of the system
  214. MatrixXd X; // result
  215. int t; // triangles incident to edge (i,j)
  216. int vi,i1,i2; // index of vertex i wrt tri t0
  217. for (int i=0;i<nfree;i++)
  218. {
  219. b.row(i) << 0.0, 0.0, 0.0;
  220. for (int k=0;k<(int)VT[i].size();k++) // for all incident triangles
  221. {
  222. t = VT[i][k]; // incident tri
  223. vi = (i==F(t,0))?0:(i==F(t,1))?1:(i==F(t,2))?2:3; // index of i in t
  224. assert(vi!=3);
  225. i1 = F(t,(vi+1)%3);
  226. i2 = F(t,(vi+2)%3);
  227. b.row(i)+=(C(t,(vi+2)%3)*RW[t]*(V.row(i1)-V.row(i)).transpose()).transpose();
  228. b.row(i)+=(C(t,(vi+1)%3)*RW[t]*(V.row(i2)-V.row(i)).transpose()).transpose();
  229. }
  230. }
  231. b/=2.0;
  232. b=-4*b;
  233. b*=(1-Lambda); // blend
  234. b+=RHS; // complete known term
  235. X = solver.solve(b);
  236. if (solver.info()!=Eigen::Success) {printf("Solving linear system failed!\n"); return;}
  237. // copy result to mw.V
  238. for (int i=0;i<nfree;i++)
  239. V_w.row(i)=X.row(i);
  240. }
  241. IGL_INLINE void Frame_field_deformer::computeXField(std::vector< Eigen::Matrix<double,3,2> > & XF)
  242. {
  243. using namespace Eigen;
  244. Matrix<double,3,3> P,PP,DG;
  245. XF.resize(F.rows());
  246. for (int i=0;i<F.rows();i++)
  247. {
  248. int i0,i1,i2;
  249. // indexes of vertices of face i
  250. i0 = F(i,0); i1 = F(i,1); i2 = F(i,2);
  251. // input frame
  252. P.col(0) = (V.row(i1)-V.row(i0)).transpose();
  253. P.col(1) = (V.row(i2)-V.row(i0)).transpose();
  254. P.col(2) = P.col(0).cross(P.col(1));
  255. // output triangle brought to origin
  256. PP.col(0) = (V_w.row(i1)-V_w.row(i0)).transpose();
  257. PP.col(1) = (V_w.row(i2)-V_w.row(i0)).transpose();
  258. PP.col(2) = PP.col(0).cross(PP.col(1));
  259. // deformation gradient
  260. DG = PP * P.inverse();
  261. XF[i] = DG * FF[i];
  262. }
  263. }
  264. // computes in WW the ideal warp at each tri to make the frame field a cross
  265. IGL_INLINE void Frame_field_deformer::compute_idealWarp(std::vector< Eigen::Matrix<double,3,3> > & WW)
  266. {
  267. using namespace Eigen;
  268. WW.resize(F.rows());
  269. for (int i=0;i<(int)FF.size();i++)
  270. {
  271. Vector3d v0,v1,v2;
  272. v0 = FF[i].col(0);
  273. v1 = FF[i].col(1);
  274. v2=v0.cross(v1); v2.normalize(); // normal
  275. Matrix3d A,AI; // compute affine map A that brings:
  276. A << v0[0], v1[0], v2[0], // first vector of FF to x unary vector
  277. v0[1], v1[1], v2[1], // second vector of FF to xy plane
  278. v0[2], v1[2], v2[2]; // triangle normal to z unary vector
  279. AI = A.inverse();
  280. // polar decomposition to discard rotational component (unnecessary but makes it easier)
  281. Eigen::JacobiSVD<Matrix<double,3,3> > svd(AI, Eigen::ComputeFullU | Eigen::ComputeFullV );
  282. //Matrix<double,3,3> au = svd.matrixU();
  283. Matrix<double,3,3> av = svd.matrixV();
  284. DiagonalMatrix<double,3> as(svd.singularValues());
  285. WW[i] = av*as*av.transpose();
  286. }
  287. }
  288. }
  289. IGL_INLINE void igl::frame_field_deformer(
  290. const Eigen::MatrixXd& V,
  291. const Eigen::MatrixXi& F,
  292. const Eigen::MatrixXd& FF1,
  293. const Eigen::MatrixXd& FF2,
  294. Eigen::MatrixXd& V_d,
  295. Eigen::MatrixXd& FF1_d,
  296. Eigen::MatrixXd& FF2_d,
  297. const int iterations,
  298. const double lambda,
  299. const bool perturb_initial_guess)
  300. {
  301. using namespace Eigen;
  302. // Solvers
  303. Frame_field_deformer deformer;
  304. // Init optimizer
  305. deformer.init(V, F, FF1, FF2, lambda, perturb_initial_guess ? 0.1 : 0);
  306. // Optimize
  307. deformer.optimize(iterations,true);
  308. // Copy positions
  309. V_d = deformer.V_w;
  310. // Allocate
  311. FF1_d.resize(F.rows(),3);
  312. FF2_d.resize(F.rows(),3);
  313. // Copy frame field
  314. for(unsigned i=0; i<deformer.XF.size(); ++i)
  315. {
  316. FF1_d.row(i) = deformer.XF[i].col(0);
  317. FF2_d.row(i) = deformer.XF[i].col(1);
  318. }
  319. }
  320. #ifndef IGL_HEADER_ONLY
  321. // Explicit template specialization
  322. #endif