Dem Bones  1.0
Skinning Decomposition Library
DemBones.h
1 // Dem Bones - Skinning Decomposition Library //
3 // Copyright (c) 2019, Electronic Arts. All rights reserved. //
5 
6 
7 
8 #ifndef DEM_BONES_DEM_BONES
9 #define DEM_BONES_DEM_BONES
10 
11 #include <Eigen/Dense>
12 #include <Eigen/Sparse>
13 #include <Eigen/StdVector>
14 #include <algorithm>
15 #include <queue>
16 #include "ConvexLS.h"
17 
18 #ifndef DEM_BONES_MAT_BLOCKS
19 #include "MatBlocks.h"
20 #define DEM_BONES_DEM_BONES_MAT_BLOCKS_UNDEFINED
21 #endif
22 
23 namespace Dem
24 {
25 
64 template<class _Scalar, class _AniMeshScalar>
65 class DemBones {
66 public:
67  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
68 
69  using MatrixX=Eigen::Matrix<_Scalar, Eigen::Dynamic, Eigen::Dynamic>;
70  using Matrix4=Eigen::Matrix<_Scalar, 4, 4>;
71  using Matrix3=Eigen::Matrix<_Scalar, 3, 3>;
72  using VectorX=Eigen::Matrix<_Scalar, Eigen::Dynamic, 1>;
73  using Vector4=Eigen::Matrix<_Scalar, 4, 1>;
74  using Vector3=Eigen::Matrix<_Scalar, 3, 1>;
75  using SparseMatrix=Eigen::SparseMatrix<_Scalar>;
76  using Triplet=Eigen::Triplet<_Scalar>;
77 
79  int nIters;
80 
83 
87  _Scalar transAffine;
89  _Scalar transAffineNorm;
90 
94  int nnz;
96  _Scalar weightsSmooth;
100  _Scalar weightEps;
101 
104  DemBones(): nIters(30), nInitIters(10),
105  nTransIters(5), transAffine(_Scalar(10)), transAffineNorm(_Scalar(4)),
106  nWeightsIters(3), nnz(8), weightsSmooth(_Scalar(1e-4)), weightsSmoothStep(_Scalar(1)),
107  weightEps(_Scalar(1e-15)),
108  iter(_iter), iterTransformations(_iterTransformations), iterWeights(_iterWeights) {
109  clear();
110  }
111 
113  int nV;
115  int nB;
117  int nS;
119  int nF;
120 
122  Eigen::VectorXi fStart;
124  Eigen::VectorXi subjectID;
125 
127  MatrixX u;
128 
130  SparseMatrix w;
131 
135  MatrixX m;
136 
138  Eigen::Matrix<_AniMeshScalar, Eigen::Dynamic, Eigen::Dynamic> v;
139 
141  std::vector<std::vector<int>> fv;
142 
144  const int& iter;
145 
148 
150  const int& iterWeights;
151 
154  void clear() {
155  nV=nB=nS=nF=0;
156  fStart.resize(0);
157  subjectID.resize(0);
158  u.resize(0, 0);
159  w.resize(0, 0);
160  m.resize(0, 0);
161  v.resize(0, 0);
162  fv.resize(0);
163  modelSize=-1;
164  laplacian.resize(0, 0);
165  }
166 
177  void init() {
178  if (modelSize<0) modelSize=sqrt((u-(u.rowwise().sum()/nV).replicate(1, nV)).squaredNorm()/nV/nS);
179  if (laplacian.cols()!=nV) computeSmoothSolver();
180 
181  if (((int)w.rows()!=nB)||((int)w.cols()!=nV)) { //No skinning weight
182  if (((int)m.rows()!=nF*4)||((int)m.cols()!=nB*4)) { //No transformation
183  int targetNB=nB;
184  //LBG-VQ
185  nB=1;
186  label=Eigen::VectorXi::Zero(nV);
187  computeTransFromLabel();
188 
189  bool cont=true;
190  while (cont) {
192  split(targetNB, nnz);
193  cont=(nB<targetNB);
194  for (int rep=0; rep<nInitIters; rep++) {
195  computeTransFromLabel();
196  computeLabel();
197  pruneBones(nnz);
198  }
199  cbInitSplitEnd();
200  }
201  m.conservativeResize(nF*4, nB*4);
202  labelToWeights();
203  } else initWeights(); //Has transformations
204  } else { //Has skinning weights
205  if (((int)m.rows()!=nF*4)||((int)m.cols()!=nB*4)) { //No transformation
206  m=Matrix4::Identity().replicate(nF, nB);
207  }
208  }
209  }
210 
224  if (nTransIters==0) return;
225 
226  init();
228 
229  compute_vuT();
230  compute_uuT();
231 
232  for (_iterTransformations=0; _iterTransformations<nTransIters; _iterTransformations++) {
234  #pragma omp parallel for
235  for (int k=0; k<nF; k++)
236  for (int j=0; j<nB; j++) {
237  Matrix4 qpT=vuT.blk4(k, j);
238  for (int it=uuT.outerIdx(j); it<uuT.outerIdx(j + 1); it++)
239  if (uuT.innerIdx(it)!=j) qpT-=m.blk4(k, uuT.innerIdx(it))*uuT.val.blk4(subjectID(k), it);
240  qpT2m(qpT, k, j);
241 
242  }
244  }
245 
247  }
248 
262  void computeWeights() {
263  if (nWeightsIters==0) return;
264 
265  init();
266  cbWeightsBegin();
267 
268  compute_mTm();
269 
270  aTb=MatrixX::Zero(nB, nV);
271  wSolver.init(nnz);
272  std::vector<Triplet, Eigen::aligned_allocator<Triplet>> trip;
273  trip.reserve(nV*nnz);
274 
275  for (_iterWeights=0; _iterWeights<nWeightsIters; _iterWeights++) {
277 
278  compute_ws();
279  compute_aTb();
280 
281  double reg=pow(modelSize, 2)*nF*weightsSmooth;
282 
283  trip.clear();
284  #pragma omp parallel for
285  for (int i=0; i<nV; i++) {
286  MatrixX aTai;
287  compute_aTa(i, aTai);
288  aTai+=reg*MatrixX::Identity(nB, nB);
289  VectorX aTbi=aTb.col(i)+reg*ws.col(i);
290 
291  VectorX x=ws.col(i);
292  Eigen::ArrayXi idx=Eigen::ArrayXi::LinSpaced(nB, 0, nB-1);
293  std::sort(idx.data(), idx.data()+nB, [&x](int i1, int i2) { return x(i1)>x(i2); });
294  int nnzi=std::min(nnz, nB);
295  while (x(idx(nnzi-1))<weightEps) nnzi--;
296 
297  x=indexing_vector(w.col(i).toDense().cwiseMax(0.0), idx.head(nnzi));
298  _Scalar s=x.sum();
299  if (s>_Scalar(0.1)) x/=s; else x=VectorX::Constant(nnzi, _Scalar(1)/nnzi);
300 
301  wSolver.solve(indexing_row_col(aTai, idx.head(nnzi), idx.head(nnzi)), indexing_vector(aTbi, idx.head(nnzi)), x, true, true);
302 
303  #pragma omp critical
304  for (int j=0; j<nnzi; j++)
305  if (x(j)!=0) trip.push_back(Triplet(idx[j], i, x(j)));
306  }
307 
308  w.resize(nB, nV);
309  w.setFromTriplets(trip.begin(), trip.end());
310 
312  }
313 
314  cbWeightsEnd();
315  }
316 
329  void compute() {
330  init();
331 
332  for (_iter=0; _iter<nIters; _iter++) {
333  cbIterBegin();
335  computeWeights();
336  cbIterEnd();
337  }
338  }
339 
341  _Scalar rmse() {
342  _Scalar e=0;
343  #pragma omp parallel for
344  for (int i=0; i<nV; i++) {
345  _Scalar ei = 0;
346  Matrix4 mki;
347  for (int k=0; k<nF; k++) {
348  mki.setZero();
349  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it) mki+=it.value()*m.blk4(k, it.row());
350  ei+=(mki.template topLeftCorner<3, 3>()*u.vec3(subjectID(k), i)+mki.template topRightCorner<3, 1>()-v.vec3(k, i).template cast<_Scalar>()).squaredNorm();
351  }
352  #pragma omp atomic
353  e+=ei;
354  }
355  return std::sqrt(e/nF/nV);
356  }
357 
359  virtual void cbInitSplitBegin() {}
361  virtual void cbInitSplitEnd() {}
362 
364  virtual void cbIterBegin() {}
366  virtual void cbIterEnd() {}
367 
369  virtual void cbWeightsBegin() {}
371  virtual void cbWeightsEnd() {}
372 
374  virtual void cbTranformationsBegin() {}
376  virtual void cbTransformationsEnd() {}
377 
379  virtual void cbTransformationsIterBegin() {}
381  virtual void cbTransformationsIterEnd() {}
382 
384  virtual void cbWeightsIterBegin() {}
386  virtual void cbWeightsIterEnd() {}
387 
388 private:
389  int _iter, _iterTransformations, _iterWeights;
390 
396  void qpT2m(const Matrix4& _qpT, int k, int j) {
397  if (_qpT(3, 3)!=0) {
398  Matrix4 qpT=_qpT/_qpT(3, 3);
399  Eigen::JacobiSVD<Matrix3> svd(qpT.template topLeftCorner<3, 3>()-qpT.template topRightCorner<3, 1>()*qpT.template bottomLeftCorner<1, 3>(), Eigen::ComputeFullU|Eigen::ComputeFullV);
400  Matrix3 d=Matrix3::Identity();
401  d(2, 2)=(svd.matrixU()*svd.matrixV().transpose()).determinant();
402  m.rotMat(k, j)=svd.matrixU()*d*svd.matrixV().transpose();
403  m.transVec(k, j)=qpT.template topRightCorner<3, 1>()-m.rotMat(k, j)*qpT.template bottomLeftCorner<1, 3>().transpose();
404  }
405  }
406 
411  _Scalar errorVtxBone(int i, int j, bool par=true) {
412  _Scalar e=0;
413  #pragma omp parallel for if(par)
414  for (int k=0; k<nF; k++)
415  #pragma omp atomic
416  e+=(m.rotMat(k, j)*u.vec3(subjectID(k), i)+m.transVec(k, j)-v.vec3(k, i).template cast<_Scalar>()).squaredNorm();
417  return e;
418  }
419 
421  Eigen::VectorXi label;
422 
424  struct TripletLess {
425  bool operator() (const Triplet& t1, const Triplet& t2) {
426  return t1.value()>t2.value();
427  }
428  };
429 
432  void computeLabel() {
433  VectorX ei(nV);
434  Eigen::VectorXi seed=Eigen::VectorXi::Constant(nB, -1);
435  VectorX gMin(nB);
436  #pragma omp parallel for
437  for (int i=0; i<nV; i++) {
438  int j=label(i);
439  if (j!=-1) {
440  ei(i)=errorVtxBone(i, j, false);
441  if ((seed(j)==-1)||(ei(i)<gMin(j))) {
442  #pragma omp critical
443  if ((seed(j)==-1)||(ei(i)<gMin(j))) {
444  gMin(j)=ei(i);
445  seed(j)=i;
446  }
447  }
448  }
449  }
450 
451  std::priority_queue<Triplet, std::vector<Triplet, Eigen::aligned_allocator<Triplet>>, TripletLess> heap;
452  for (int j=0; j<nB; j++) if (seed(j)!=-1) heap.push(Triplet(j, seed(j), ei(seed(j))));
453 
454  if (laplacian.cols()!=nV) computeSmoothSolver();
455 
456  std::vector<bool> dirty(nV, true);
457  while (!heap.empty()) {
458  Triplet top=heap.top();
459  heap.pop();
460  int i=(int)top.col();
461  int j=(int)top.row();
462  if (dirty[i]) {
463  label(i)=j;
464  ei(i)=top.value();
465  dirty[i]=false;
466  for (typename SparseMatrix::InnerIterator it(laplacian, i); it; ++it) {
467  int i2=(int)it.row();
468  if (dirty[i2]) {
469  double tmp=(label(i2)==j)?ei(i2):errorVtxBone(i2, j);
470  heap.push(Triplet(j, i2, tmp));
471  }
472  }
473  }
474  }
475 
476  #pragma omp parallel for
477  for (int i=0; i<nV; i++)
478  if (label(i)==-1) {
479  _Scalar gMin;
480  for (int j=0; j<nB; j++) {
481  _Scalar ej=errorVtxBone(i, j, false);
482  if ((label(i)==-1)||(gMin>ej)) {
483  gMin=ej;
484  label(i)=j;
485  }
486  }
487  }
488  }
489 
492  void computeTransFromLabel() {
493  m=Matrix4::Identity().replicate(nF, nB);
494  #pragma omp parallel for
495  for (int k=0; k<nF; k++) {
496  MatrixX qpT=MatrixX::Zero(4, 4*nB);
497  for (int i=0; i<nV; i++)
498  if (label(i)!=-1) qpT.blk4(0, label(i))+=Vector4(v.vec3(k, i).template cast<_Scalar>().homogeneous())*u.vec3(subjectID(k), i).homogeneous().transpose();
499  for (int j=0; j<nB; j++) qpT2m(qpT.blk4(0, j), k, j);
500  }
501  }
502 
505  void labelToWeights() {
506  std::vector<Triplet, Eigen::aligned_allocator<Triplet>> trip(nV);
507  for (int i=0; i<nV; i++) trip[i]=Triplet(label(i), i, _Scalar(1));
508  w.resize(nB, nV);
509  w.setFromTriplets(trip.begin(), trip.end());
510  }
511 
516  void split(int maxB, int threshold) {
517  //Centroids
518  MatrixX cu=MatrixX::Zero(3*nS, nB);
519  Eigen::VectorXi s=Eigen::VectorXi::Zero(nB);
520  for (int i=0; i<nV; i++) {
521  cu.col(label(i))+=u.col(i);
522  s(label(i))++;
523  }
524  for (int j=0; j<nB; j++) if (s(j)!=0) cu.col(j)/=_Scalar(s(j));
525 
526  //Seed & cluster error
527  Eigen::VectorXi seed=Eigen::VectorXi::Constant(nB, -1);
528  VectorX gMax(nB);
529  VectorX ce=VectorX::Zero(nB);
530 
531  #pragma omp parallel for
532  for (int i=0; i<nV; i++) {
533  int j=label(i);
534 
535  double e=errorVtxBone(i, j, false);
536  #pragma omp atomic
537  ce(j)+=e;
538 
539  double tmp=e*(u.col(i)-cu.col(j)).squaredNorm();
540 
541  if ((seed(j)==-1)||(tmp>gMax(j))) {
542  #pragma omp critical
543  if ((seed(j)==-1)||(tmp>gMax(j))) {
544  gMax(j)=tmp;
545  seed(j)=i;
546  }
547  }
548  }
549 
550  int countID=nB;
551  _Scalar avgErr=ce.sum()/nB;
552  for (int j=0; j<nB; j++)
553  if ((countID<maxB)&&(s(j)>threshold*2)&&(ce(j)>avgErr/100)) {
554  int newLabel=countID++;
555  int i=seed(j);
556  for (typename SparseMatrix::InnerIterator it(laplacian, i); it; ++it) label(it.row())=newLabel;
557  }
558  nB=countID;
559  }
560 
564  void pruneBones(int threshold) {
565  Eigen::VectorXi s=Eigen::VectorXi::Zero(nB);
566  #pragma omp parallel for
567  for (int i=0; i<nV; i++) {
568  #pragma omp atomic
569  s(label(i))++;
570  }
571 
572  Eigen::VectorXi newID(nB);
573  int countID=0;
574  for (int j=0; j<nB; j++)
575  if (s(j)<threshold) newID(j)=-1; else newID(j)=countID++;
576 
577  if (countID==nB) return;
578 
579  for (int j=0; j<nB; j++)
580  if (newID(j)!=-1) m.template middleCols<4>(newID(j)*4)=m.template middleCols<4>(j*4);
581 
582  #pragma omp parallel for
583  for (int i=0; i<nV; i++) label(i)=newID(label(i));
584 
585  nB=countID;
586  m.conservativeResize(nF*4, nB*4);
587  computeLabel();
588  }
589 
592  void initWeights() {
593  label=Eigen::VectorXi::Constant(nV, -1);
594  #pragma omp parallel for
595  for (int i=0; i<nV; i++) {
596  _Scalar gMin;
597  for (int j=0; j<nB; j++) {
598  _Scalar ej=errorVtxBone(i, j, false);
599  if ((label(i)==-1)||(gMin>ej)) {
600  gMin=ej;
601  label(i)=j;
602  }
603  }
604  }
605  computeLabel();
606  labelToWeights();
607  }
608 
610  MatrixX vuT;
611 
614  void compute_vuT() {
615  vuT=MatrixX::Zero(nF*4, nB*4);
616  #pragma omp parallel for
617  for (int k=0; k<nF; k++) {
618  MatrixX vuTp=MatrixX::Zero(4, nB*4);
619  for (int i=0; i<nV; i++)
620  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it) {
621  Matrix4 tmp=Vector4(v.vec3(k, i).template cast<_Scalar>().homogeneous())*u.vec3(subjectID(k), i).homogeneous().transpose();
622  vuT.blk4(k, it.row())+=it.value()*tmp;
623  vuTp.blk4(0, it.row())+=pow(it.value(), transAffineNorm)*tmp;
624  }
625  for (int j=0; j<nB; j++)
626  if (vuTp(3, j*4+3)!=0)
627  vuT.blk4(k, j)+=(transAffine*vuT(k*4+3, j*4+3)/vuTp(3, j*4+3))*vuTp.blk4(0, j);
628  }
629  }
630 
632  struct SparseMatrixBlock {
633  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
634  MatrixX val;
635  Eigen::VectorXi innerIdx, outerIdx;
636  } uuT;
637 
640  void compute_uuT() {
641  Eigen::MatrixXi pos=Eigen::MatrixXi::Constant(nB, nB, -1);
642  #pragma omp parallel for
643  for (int i=0; i<nV; i++)
644  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it)
645  for (typename SparseMatrix::InnerIterator jt(w, i); jt; ++jt)
646  pos(it.row(), jt.row())=1;
647 
648  uuT.outerIdx.resize(nB+1);
649  uuT.innerIdx.resize(nB*nB);
650  int nnz=0;
651  for (int j=0; j<nB; j++) {
652  uuT.outerIdx(j)=nnz;
653  for (int i=0; i<nB; i++)
654  if (pos(i, j)!=-1) {
655  uuT.innerIdx(nnz)=i;
656  pos(i, j)=nnz++;
657  }
658  }
659  uuT.outerIdx(nB)=nnz;
660  uuT.innerIdx.conservativeResize(nnz);
661  uuT.val=MatrixX::Zero(nS*4, nnz*4);
662 
663  #pragma omp parallel for
664  for (int i=0; i<nV; i++)
665  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it)
666  for (typename SparseMatrix::InnerIterator jt(w, i); jt; ++jt)
667  if (it.row()>=jt.row()) {
668  double _w=it.value()*jt.value();
669  MatrixX _uuT(4*nS, 4);
670  Vector4 _u;
671  for (int s=0; s<nS; s++) {
672  _u=u.vec3(s, i).homogeneous();
673  _uuT.blk4(s, 0)=_w*_u*_u.transpose();
674  }
675  int p=pos(it.row(), jt.row())*4;
676  for (int c=0; c<4; c++)
677  for (int r=0; r<4*nS; r++)
678  #pragma omp atomic
679  uuT.val(r, p+c)+=_uuT(r, c);
680  }
681 
682  for (int i=0; i<nB; i++)
683  for (int j=i+1; j<nB; j++)
684  if (pos(i, j)!=-1)
685  uuT.val.middleCols(pos(i, j)*4, 4)=uuT.val.middleCols(pos(j, i)*4, 4);
686  }
687 
688 
689 
691  MatrixX mTm;
692 
695  void compute_mTm() {
696  Eigen::MatrixXi idx(2, nB*(nB+1)/2);
697  int nPairs=0;
698  for (int i=0; i<nB; i++)
699  for (int j=i; j<nB; j++) {
700  idx(0, nPairs)=i;
701  idx(1, nPairs)=j;
702  nPairs++;
703  }
704 
705  mTm=MatrixX::Zero(nS*nB*4, nB*4);
706  #pragma omp parallel for
707  for (int p=0; p<nPairs; p++) {
708  int i=idx(0, p);
709  int j=idx(1, p);
710  for (int k=0; k<nF; k++)
711  mTm.blk4(subjectID(k)*nB+i, j)+=m.blk4(k, i).template topRows<3>().transpose()*m.blk4(k, j).template topRows<3>();
712  if (i!=j) for (int s=0; s<nS; s++) mTm.blk4(s*nB+j, i)=mTm.blk4(s*nB+i, j);
713  }
714  }
715 
717  MatrixX aTb;
718 
721  void compute_aTb() {
722  #pragma omp parallel for
723  for (int i=0; i<nV; i++)
724  for (int j=0; j<nB; j++)
725  if ((aTb(j, i)==0)&&(ws(j, i)>weightEps))
726  for (int k=0; k<nF; k++)
727  aTb(j, i)+=v.vec3(k, i).template cast<_Scalar>().dot(m.blk4(k, j).template topRows<3>()*u.vec3(subjectID(k), i).homogeneous());
728  }
729 
731  _Scalar modelSize;
732 
734  SparseMatrix laplacian;
735 
737  Eigen::SparseLU<SparseMatrix> smoothSolver;
738 
741  void computeSmoothSolver() {
742  int nFV=(int)fv.size();
743 
744  _Scalar epsDis=0;
745  for (int f=0; f<nFV; f++) {
746  int nf=(int)fv[f].size();
747  for (int g=0; g<nf; g++) {
748  int i=fv[f][g];
749  int j=fv[f][(g+1)%nf];
750  epsDis+=(u.col(i)-u.col(j)).norm();
751  }
752  }
753  epsDis=epsDis*weightEps/(_Scalar)nS;
754 
755  std::vector<Triplet, Eigen::aligned_allocator<Triplet>> triplet;
756  VectorX d=VectorX::Zero(nV);
757 
758  #pragma omp parallel for
759  for (int f=0; f<nFV; f++) {
760  int nf=(int)fv[f].size();
761  for (int g=0; g<nf; g++) {
762  int i=fv[f][g];
763  int j=fv[f][(g+1)%nf];
764 
765  if (i<j) {
766  double val=0;
767  for (int s=0; s<nS; s++) {
768  double du=(u.vec3(s, i)-u.vec3(s, j)).norm();
769  for (int k=fStart(s); k<fStart(s+1); k++)
770  val+=pow((v.vec3(k, i).template cast<_Scalar>()-v.vec3(k, j).template cast<_Scalar>()).norm()-du, 2);
771  }
772  val=1/(sqrt(val/nF)+epsDis);
773 
774  #pragma omp critical
775  triplet.push_back(Triplet(i, j, -val));
776  #pragma omp atomic
777  d(i)+=val;
778 
779  #pragma omp critical
780  triplet.push_back(Triplet(j, i, -val));
781  #pragma omp atomic
782  d(j)+=val;
783  }
784  }
785  }
786 
787  for (int i=0; i<nV; i++)
788  triplet.push_back(Triplet(i, i, d(i)));
789 
790  laplacian.resize(nV, nV);
791  laplacian.setFromTriplets(triplet.begin(), triplet.end());
792 
793  for (int i=0; i<nV; i++)
794  if (d(i)!=0) laplacian.row(i)/=d(i);
795 
796  laplacian=weightsSmoothStep*laplacian+SparseMatrix((VectorX::Ones(nV)).asDiagonal());
797  smoothSolver.compute(laplacian);
798  }
799 
801  MatrixX ws;
802 
805  void compute_ws() {
806  ws=w.transpose();
807  #pragma omp parallel for
808  for (int j=0; j<nB; j++) ws.col(j)=smoothSolver.solve(ws.col(j));
809  ws.transposeInPlace();
810 
811  #pragma omp parallel for
812  for (int i=0; i<nV; i++) {
813  ws.col(i)=ws.col(i).cwiseMax(0.0);
814  _Scalar si=ws.col(i).sum();
815  if (si<_Scalar(0.1)) ws.col(i)=VectorX::Constant(nB, _Scalar(1)/nB); else ws.col(i)/=si;
816  }
817  }
818 
820  ConvexLS<_Scalar> wSolver;
821 
826  void compute_aTa(int i, MatrixX& aTa) {
827  aTa=MatrixX::Zero(nB, nB);
828  for (int j1=0; j1<nB; j1++)
829  for (int j2=j1; j2<nB; j2++) {
830  for (int s=0; s<nS; s++) aTa(j1, j2)+=u.vec3(s, i).homogeneous().dot(mTm.blk4(s*nB+j1, j2)*u.vec3(s, i).homogeneous());
831  if (j1!=j2) aTa(j2, j1)=aTa(j1, j2);
832  }
833  }
834 };
835 
836 }
837 
838 #ifdef DEM_BONES_DEM_BONES_MAT_BLOCKS_UNDEFINED
839 #undef blk4
840 #undef rotMat
841 #undef transVec
842 #undef vec3
843 #undef DEM_BONES_MAT_BLOCKS
844 #endif
845 
846 #endif
Dem::DemBones::m
MatrixX m
Bone transformations, size = [4*nF*4, 4*nB], m.blk4(k, j) is the 4*4 relative transformation matrix o...
Definition: DemBones.h:135
Dem::DemBones::rmse
_Scalar rmse()
Definition: DemBones.h:341
Dem::DemBones::weightsSmooth
_Scalar weightsSmooth
[parameter] Weights smoothness soft constraint, default = 1e-4
Definition: DemBones.h:96
Dem::DemBones::cbTransformationsEnd
virtual void cbTransformationsEnd()
Callback function invoked after each bone transformations update.
Definition: DemBones.h:376
Dem::DemBones::iterTransformations
const int & iterTransformations
[zero indexed, read only] Current bone transformations update iteration number that can be used for c...
Definition: DemBones.h:147
Dem::DemBones::nV
int nV
Number of vertices, typically indexed by i.
Definition: DemBones.h:113
Dem::DemBones::init
void init()
Initialize missing skinning weights and/or bone transformations.
Definition: DemBones.h:177
Dem::DemBones::transAffineNorm
_Scalar transAffineNorm
[parameter] p-norm for bone translations affinity soft constraint, default = 4.0
Definition: DemBones.h:89
Dem::DemBones::u
MatrixX u
Geometry at the rest poses, size = [3*nS, nV], u.col(i).segment(3*s, 3) is the rest pose of vertex i ...
Definition: DemBones.h:127
Dem::DemBones::computeTranformations
void computeTranformations()
Update bone transformations by running nTransIters iterations with transAffine and transAffineNorm re...
Definition: DemBones.h:223
Dem::DemBones::transAffine
_Scalar transAffine
[parameter] Translations affinity soft constraint, default = 10.0
Definition: DemBones.h:87
Dem::DemBones::fv
std::vector< std::vector< int > > fv
Mesh topology, size=[number of polygons], fv[p] is the vector of vertex indices of polygon p.
Definition: DemBones.h:141
Dem::DemBones::iterWeights
const int & iterWeights
[zero indexed, read only] Current weights update iteration number that can be used for callback funct...
Definition: DemBones.h:150
Dem::DemBones::cbInitSplitBegin
virtual void cbInitSplitBegin()
Callback function invoked before each spliting of bone clusters in initialization.
Definition: DemBones.h:359
Dem::DemBones::subjectID
Eigen::VectorXi subjectID
Subject index of the frame, size = nF, subjectID(k)=s, where fStart(s) <= k < fStart(s+1)
Definition: DemBones.h:124
MatBlocks.h
Defines some macros to access sub-blocks of packing transformation/position matrices for convenience.
Dem::DemBones::fStart
Eigen::VectorXi fStart
Start frame indices, size = nS+1, fStart(s), fStart(s+1) are data frames for subject s.
Definition: DemBones.h:122
Dem::DemBones::cbWeightsIterEnd
virtual void cbWeightsIterEnd()
Callback function invoked after each local weights update iteration.
Definition: DemBones.h:386
Dem::DemBones::cbTranformationsBegin
virtual void cbTranformationsBegin()
Callback function invoked before each bone transformations update.
Definition: DemBones.h:374
Dem::DemBones::nIters
int nIters
[parameter] Number of global iterations, default = 30
Definition: DemBones.h:79
Dem::DemBones::nnz
int nnz
[parameter] Number of non-zero weights per vertex, default = 8
Definition: DemBones.h:94
Dem::DemBones::weightsSmoothStep
_Scalar weightsSmoothStep
[parameter] Step size for the weights smoothness soft constraint, default = 1.0
Definition: DemBones.h:98
Dem::DemBones::nS
int nS
Number of subjects, typically indexed by s.
Definition: DemBones.h:117
Dem::DemBones::nTransIters
int nTransIters
[parameter] Number of bone transformations update iterations per global iteration,...
Definition: DemBones.h:85
Dem::DemBones::nF
int nF
Number of total frames, typically indexed by k, nF = fStart(nS)
Definition: DemBones.h:119
Dem::DemBones::DemBones
DemBones()
Constructor and setting default parameters.
Definition: DemBones.h:104
Dem::DemBones::cbWeightsEnd
virtual void cbWeightsEnd()
Callback function invoked after each skinning weights update.
Definition: DemBones.h:371
Dem::DemBones::iter
const int & iter
[zero indexed, read only] Current global iteration number that can be used for callback functions
Definition: DemBones.h:144
Dem::DemBones::cbWeightsBegin
virtual void cbWeightsBegin()
Callback function invoked before each skinning weights update.
Definition: DemBones.h:369
Dem::DemBones::cbIterEnd
virtual void cbIterEnd()
Callback function invoked after each global iteration update.
Definition: DemBones.h:366
Dem::DemBones::w
SparseMatrix w
Skinning weights, size = [nB, nV], w.col(i) are the skinning weights of vertex i, w(j,...
Definition: DemBones.h:130
Dem::DemBones::nInitIters
int nInitIters
[parameter] Number of clustering update iterations in the initalization, default = 10
Definition: DemBones.h:82
Dem::DemBones::weightEps
_Scalar weightEps
[parameter] Epsilon for weights solver, default = 1e-15
Definition: DemBones.h:100
Dem::DemBones::nB
int nB
Number of bones, typically indexed by j.
Definition: DemBones.h:115
Dem::DemBones::cbTransformationsIterEnd
virtual void cbTransformationsIterEnd()
Callback function invoked after each local bone transformations update iteration.
Definition: DemBones.h:381
Dem::DemBones::v
Eigen::Matrix< _AniMeshScalar, Eigen::Dynamic, Eigen::Dynamic > v
Animated mesh sequence, size = [3*nF, nV], v.col(i).segment(3*k, 3) is the position of vertex i at fr...
Definition: DemBones.h:138
Dem::DemBones::cbInitSplitEnd
virtual void cbInitSplitEnd()
Callback function invoked after each spliting of bone clusters in initialization.
Definition: DemBones.h:361
Dem::DemBones
Smooth skinning decomposition with rigid bones and sparse, convex weights.
Definition: DemBones.h:65
Dem::DemBones::compute
void compute()
Skinning decomposition by nIters iterations of alternative updating weights and bone transformations.
Definition: DemBones.h:329
Dem::DemBones::computeWeights
void computeWeights()
Update skinning weights by running nWeightsIters iterations with weightsSmooth and weightsSmoothStep ...
Definition: DemBones.h:262
Dem::DemBones::cbWeightsIterBegin
virtual void cbWeightsIterBegin()
Callback function invoked before each local weights update iteration.
Definition: DemBones.h:384
Dem::DemBones::clear
void clear()
Clear all data.
Definition: DemBones.h:154
Dem::DemBones::nWeightsIters
int nWeightsIters
[parameter] Number of weights update iterations per global iteration, default = 3
Definition: DemBones.h:92
Dem::DemBones::cbIterBegin
virtual void cbIterBegin()
Callback function invoked before each global iteration update.
Definition: DemBones.h:364
Dem::DemBones::cbTransformationsIterBegin
virtual void cbTransformationsIterBegin()
Callback function invoked before each local bone transformations update iteration.
Definition: DemBones.h:379