Dem Bones  1.2.0
Skinning Decomposition Library
DemBones.h
Go to the documentation of this file.
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 <set>
17 #include "ConvexLS.h"
18 
19 #ifndef DEM_BONES_MAT_BLOCKS
20 #include "MatBlocks.h"
21 #define DEM_BONES_DEM_BONES_MAT_BLOCKS_UNDEFINED
22 #endif
23 
24 namespace Dem
25 {
26 
65 template<class _Scalar, class _AniMeshScalar>
66 class DemBones {
67 public:
68  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
69 
70  using MatrixX=Eigen::Matrix<_Scalar, Eigen::Dynamic, Eigen::Dynamic>;
71  using Matrix4=Eigen::Matrix<_Scalar, 4, 4>;
72  using Matrix3=Eigen::Matrix<_Scalar, 3, 3>;
73  using VectorX=Eigen::Matrix<_Scalar, Eigen::Dynamic, 1>;
74  using Vector4=Eigen::Matrix<_Scalar, 4, 1>;
75  using Vector3=Eigen::Matrix<_Scalar, 3, 1>;
76  using SparseMatrix=Eigen::SparseMatrix<_Scalar>;
77  using Triplet=Eigen::Triplet<_Scalar>;
78 
80  int nIters;
81 
84 
88  _Scalar transAffine;
90  _Scalar transAffineNorm;
91 
95  int nnz;
97  _Scalar weightsSmooth;
101  _Scalar weightEps;
102 
106  nTransIters(5), transAffine(_Scalar(10)), transAffineNorm(_Scalar(4)),
107  nWeightsIters(3), nnz(8), weightsSmooth(_Scalar(1e-4)), weightsSmoothStep(_Scalar(1)),
108  weightEps(_Scalar(1e-15)),
109  iter(_iter), iterTransformations(_iterTransformations), iterWeights(_iterWeights) {
110  clear();
111  }
112 
114  int nV;
116  int nB;
118  int nS;
120  int nF;
121 
123  Eigen::VectorXi fStart;
125  Eigen::VectorXi subjectID;
126 
129 
132 
135 
140 
142  Eigen::VectorXi lockM;
143 
145  Eigen::Matrix<_AniMeshScalar, Eigen::Dynamic, Eigen::Dynamic> v;
146 
148  std::vector<std::vector<int>> fv;
149 
151  const int& iter;
152 
155 
157  const int& iterWeights;
158 
161  void clear() {
162  nV=nB=nS=nF=0;
163  fStart.resize(0);
164  subjectID.resize(0);
165  u.resize(0, 0);
166  w.resize(0, 0);
167  lockW.resize(0);
168  m.resize(0, 0);
169  lockM.resize(0);
170  v.resize(0, 0);
171  fv.resize(0);
172  modelSize=-1;
173  laplacian.resize(0, 0);
174  }
175 
186  void init() {
187  if (modelSize<0) modelSize=sqrt((u-(u.rowwise().sum()/nV).replicate(1, nV)).squaredNorm()/nV/nS);
188  if (laplacian.cols()!=nV) computeSmoothSolver();
189 
190  if (((int)w.rows()!=nB)||((int)w.cols()!=nV)) { //No skinning weight
191  if (((int)m.rows()!=nF*4)||((int)m.cols()!=nB*4)) { //No transformation
192  int targetNB=nB;
193  //LBG-VQ
194  nB=1;
195  label=Eigen::VectorXi::Zero(nV);
196  computeTransFromLabel();
197 
198  bool cont=true;
199  while (cont) {
201  int prev=nB;
202  split(targetNB, 3);
203  for (int rep=0; rep<nInitIters; rep++) {
204  computeTransFromLabel();
205  computeLabel();
206  pruneBones(3);
207  }
208  cont=(nB<targetNB)&&(nB>prev);
209  cbInitSplitEnd();
210  }
211  lockM=Eigen::VectorXi::Zero(nB);
212  labelToWeights();
213  } else initWeights(); //Has transformations
214  } else { //Has skinning weights
215  if (((int)m.rows()!=nF*4)||((int)m.cols()!=nB*4)) { //No transformation
216  m=Matrix4::Identity().replicate(nF, nB);
217  lockM=Eigen::VectorXi::Zero(nB);
218  }
219  }
220 
221  if (lockW.size()!=nV) lockW=VectorX::Zero(nV);
222  if (lockM.size()!=nB) lockM=Eigen::VectorXi::Zero(nB);
223  }
224 
238  if (nTransIters==0) return;
239 
240  init();
242 
243  compute_vuT();
244  compute_uuT();
245 
246  for (_iterTransformations=0; _iterTransformations<nTransIters; _iterTransformations++) {
248  #pragma omp parallel for
249  for (int k=0; k<nF; k++)
250  for (int j=0; j<nB; j++)
251  if (lockM(j)==0) {
252  Matrix4 qpT=vuT.blk4(k, j);
253  for (int it=uuT.outerIdx(j); it<uuT.outerIdx(j+1); it++)
254  if (uuT.innerIdx(it)!=j) qpT-=m.blk4(k, uuT.innerIdx(it))*uuT.val.blk4(subjectID(k), it);
255  qpT2m(qpT, k, j);
256  }
257  if (cbTransformationsIterEnd()) return;
258  }
259 
261  }
262 
276  void computeWeights() {
277  if (nWeightsIters==0) return;
278 
279  init();
280  cbWeightsBegin();
281 
282  compute_mTm();
283 
284  aTb=MatrixX::Zero(nB, nV);
285  wSolver.init(nnz);
286  std::vector<Triplet, Eigen::aligned_allocator<Triplet>> trip;
287  trip.reserve(nV*nnz);
288 
289  for (_iterWeights=0; _iterWeights<nWeightsIters; _iterWeights++) {
291 
292  compute_ws();
293  compute_aTb();
294 
295  double reg_scale=pow(modelSize, 2)*nF;
296 
297  trip.clear();
298  #pragma omp parallel for
299  for (int i=0; i<nV; i++) {
300  MatrixX aTai;
301  compute_aTa(i, aTai);
302  aTai=(1-lockW(i))*(aTai/reg_scale+weightsSmooth*MatrixX::Identity(nB, nB))+lockW(i)*MatrixX::Identity(nB, nB);
303  VectorX aTbi=(1-lockW(i))*(aTb.col(i)/reg_scale+weightsSmooth*ws.col(i))+lockW(i)*w.col(i);
304 
305  VectorX x=(1-lockW(i))*ws.col(i)+lockW(i)*w.col(i);
306  Eigen::ArrayXi idx=Eigen::ArrayXi::LinSpaced(nB, 0, nB-1);
307  std::sort(idx.data(), idx.data()+nB, [&x](int i1, int i2) { return x(i1)>x(i2); });
308  int nnzi=std::min(nnz, nB);
309  while (x(idx(nnzi-1))<weightEps) nnzi--;
310 
311  VectorX x0=w.col(i).toDense().cwiseMax(0.0);
312  x=indexing_vector(x0, idx.head(nnzi));
313  _Scalar s=x.sum();
314  if (s>_Scalar(0.1)) x/=s; else x=VectorX::Constant(nnzi, _Scalar(1)/nnzi);
315 
316  wSolver.solve(indexing_row_col(aTai, idx.head(nnzi), idx.head(nnzi)), indexing_vector(aTbi, idx.head(nnzi)), x, true, true);
317 
318  #pragma omp critical
319  for (int j=0; j<nnzi; j++)
320  if (x(j)!=0) trip.push_back(Triplet(idx[j], i, x(j)));
321  }
322 
323  w.resize(nB, nV);
324  w.setFromTriplets(trip.begin(), trip.end());
325 
326  if (cbWeightsIterEnd()) return;
327  }
328 
329  cbWeightsEnd();
330  }
331 
344  void compute() {
345  init();
346 
347  for (_iter=0; _iter<nIters; _iter++) {
348  cbIterBegin();
350  computeWeights();
351  if (cbIterEnd()) break;
352  }
353  }
354 
356  _Scalar rmse() {
357  _Scalar e=0;
358  #pragma omp parallel for
359  for (int i=0; i<nV; i++) {
360  _Scalar ei=0;
361  Matrix4 mki;
362  for (int k=0; k<nF; k++) {
363  mki.setZero();
364  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it) mki+=it.value()*m.blk4(k, it.row());
365  ei+=(mki.template topLeftCorner<3, 3>()*u.vec3(subjectID(k), i)+mki.template topRightCorner<3, 1>()-v.vec3(k, i).template cast<_Scalar>()).squaredNorm();
366  }
367  #pragma omp atomic
368  e+=ei;
369  }
370  return std::sqrt(e/nF/nV);
371  }
372 
374  virtual void cbInitSplitBegin() {}
376  virtual void cbInitSplitEnd() {}
377 
379  virtual void cbIterBegin() {}
381  virtual bool cbIterEnd() { return false; }
382 
384  virtual void cbWeightsBegin() {}
386  virtual void cbWeightsEnd() {}
387 
389  virtual void cbTranformationsBegin() {}
391  virtual void cbTransformationsEnd() {}
392 
394  virtual void cbTransformationsIterBegin() {}
396  virtual bool cbTransformationsIterEnd() { return false; }
397 
399  virtual void cbWeightsIterBegin() {}
401  virtual bool cbWeightsIterEnd() { return false; }
402 
403 private:
404  int _iter, _iterTransformations, _iterWeights;
405 
411  void qpT2m(const Matrix4& _qpT, int k, int j) {
412  if (_qpT(3, 3)!=0) {
413  Matrix4 qpT=_qpT/_qpT(3, 3);
414  Eigen::JacobiSVD<Matrix3> svd(qpT.template topLeftCorner<3, 3>()-qpT.template topRightCorner<3, 1>()*qpT.template bottomLeftCorner<1, 3>(), Eigen::ComputeFullU|Eigen::ComputeFullV);
415  Matrix3 d=Matrix3::Identity();
416  d(2, 2)=(svd.matrixU()*svd.matrixV().transpose()).determinant();
417  m.rotMat(k, j)=svd.matrixU()*d*svd.matrixV().transpose();
418  m.transVec(k, j)=qpT.template topRightCorner<3, 1>()-m.rotMat(k, j)*qpT.template bottomLeftCorner<1, 3>().transpose();
419  }
420  }
421 
426  _Scalar errorVtxBone(int i, int j, bool par=true) {
427  _Scalar e=0;
428  #pragma omp parallel for if(par)
429  for (int k=0; k<nF; k++)
430  #pragma omp atomic
431  e+=(m.rotMat(k, j)*u.vec3(subjectID(k), i)+m.transVec(k, j)-v.vec3(k, i).template cast<_Scalar>()).squaredNorm();
432  return e;
433  }
434 
436  Eigen::VectorXi label;
437 
439  struct TripletLess {
440  bool operator() (const Triplet& t1, const Triplet& t2) {
441  return t1.value()>t2.value();
442  }
443  };
444 
447  void computeLabel() {
448  VectorX ei(nV);
449  Eigen::VectorXi seed=Eigen::VectorXi::Constant(nB, -1);
450  VectorX gMin(nB);
451  #pragma omp parallel for
452  for (int i=0; i<nV; i++) {
453  int j=label(i);
454  if (j!=-1) {
455  ei(i)=errorVtxBone(i, j, false);
456  if ((seed(j)==-1)||(ei(i)<gMin(j))) {
457  #pragma omp critical
458  if ((seed(j)==-1)||(ei(i)<gMin(j))) {
459  gMin(j)=ei(i);
460  seed(j)=i;
461  }
462  }
463  }
464  }
465 
466  std::priority_queue<Triplet, std::vector<Triplet, Eigen::aligned_allocator<Triplet>>, TripletLess> heap;
467  for (int j=0; j<nB; j++) if (seed(j)!=-1) heap.push(Triplet(j, seed(j), ei(seed(j))));
468 
469  if (laplacian.cols()!=nV) computeSmoothSolver();
470 
471  std::vector<bool> dirty(nV, true);
472  while (!heap.empty()) {
473  Triplet top=heap.top();
474  heap.pop();
475  int i=(int)top.col();
476  int j=(int)top.row();
477  if (dirty[i]) {
478  label(i)=j;
479  ei(i)=top.value();
480  dirty[i]=false;
481  for (typename SparseMatrix::InnerIterator it(laplacian, i); it; ++it) {
482  int i2=(int)it.row();
483  if (dirty[i2]) {
484  double tmp=(label(i2)==j)?ei(i2):errorVtxBone(i2, j);
485  heap.push(Triplet(j, i2, tmp));
486  }
487  }
488  }
489  }
490 
491  #pragma omp parallel for
492  for (int i=0; i<nV; i++)
493  if (label(i)==-1) {
494  _Scalar gMin;
495  for (int j=0; j<nB; j++) {
496  _Scalar ej=errorVtxBone(i, j, false);
497  if ((label(i)==-1)||(gMin>ej)) {
498  gMin=ej;
499  label(i)=j;
500  }
501  }
502  }
503  }
504 
507  void computeTransFromLabel() {
508  m=Matrix4::Identity().replicate(nF, nB);
509  #pragma omp parallel for
510  for (int k=0; k<nF; k++) {
511  MatrixX qpT=MatrixX::Zero(4, 4*nB);
512  for (int i=0; i<nV; i++)
513  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();
514  for (int j=0; j<nB; j++) qpT2m(qpT.blk4(0, j), k, j);
515  }
516  }
517 
520  void labelToWeights() {
521  std::vector<Triplet, Eigen::aligned_allocator<Triplet>> trip(nV);
522  for (int i=0; i<nV; i++) trip[i]=Triplet(label(i), i, _Scalar(1));
523  w.resize(nB, nV);
524  w.setFromTriplets(trip.begin(), trip.end());
525  lockW=VectorX::Zero(nV);
526  }
527 
532  void split(int maxB, int threshold) {
533  //Centroids
534  MatrixX cu=MatrixX::Zero(3*nS, nB);
535  Eigen::VectorXi s=Eigen::VectorXi::Zero(nB);
536  for (int i=0; i<nV; i++) {
537  cu.col(label(i))+=u.col(i);
538  s(label(i))++;
539  }
540  for (int j=0; j<nB; j++) if (s(j)!=0) cu.col(j)/=_Scalar(s(j));
541 
542  //Distance to centroid & error
543  VectorX d(nV), e(nV);
544  VectorX minD=VectorX::Constant(nB, std::numeric_limits<_Scalar>::max());
545  VectorX minE=VectorX::Constant(nB, std::numeric_limits<_Scalar>::max());
546  VectorX ce=VectorX::Zero(nB);
547 
548  #pragma omp parallel for
549  for (int i=0; i<nV; i++) {
550  int j=label(i);
551  d(i)=(u.col(i)-cu.col(j)).norm();
552  e(i)=sqrt(errorVtxBone(i, j, false));
553  if (d(i)<minD(j)) {
554  #pragma omp critical
555  minD(j)=std::min(minD(j), d(i));
556  }
557  if (e(i)<minE(j)) {
558  #pragma omp critical
559  minE(j)=std::min(minE(j), e(i));
560  }
561  #pragma omp atomic
562  ce(j)+=e(i);
563  }
564 
565  //Seed
566  Eigen::VectorXi seed=Eigen::VectorXi::Constant(nB, -1);
567  VectorX gMax(nB);
568 
569  #pragma omp parallel for
570  for (int i=0; i<nV; i++) {
571  int j=label(i);
572  double tmp=abs((e(i)-minE(j))*(d(i)-minD(j)));
573 
574  if ((seed(j)==-1)||(tmp>gMax(j))) {
575  #pragma omp critical
576  if ((seed(j)==-1)||(tmp>gMax(j))) {
577  gMax(j)=tmp;
578  seed(j)=i;
579  }
580  }
581  }
582 
583  int countID=nB;
584  _Scalar avgErr=ce.sum()/nB;
585  for (int j=0; j<nB; j++)
586  if ((countID<maxB)&&(s(j)>threshold*2)&&(ce(j)>avgErr/100)) {
587  int newLabel=countID++;
588  int i=seed(j);
589  for (typename SparseMatrix::InnerIterator it(laplacian, i); it; ++it) label(it.row())=newLabel;
590  }
591  nB=countID;
592  }
593 
597  void pruneBones(int threshold) {
598  Eigen::VectorXi s=Eigen::VectorXi::Zero(nB);
599  #pragma omp parallel for
600  for (int i=0; i<nV; i++) {
601  #pragma omp atomic
602  s(label(i))++;
603  }
604 
605  Eigen::VectorXi newID(nB);
606  int countID=0;
607  for (int j=0; j<nB; j++)
608  if (s(j)<threshold) newID(j)=-1; else newID(j)=countID++;
609 
610  if (countID==nB) return;
611 
612  for (int j=0; j<nB; j++)
613  if (newID(j)!=-1) m.template middleCols<4>(newID(j)*4)=m.template middleCols<4>(j*4);
614 
615  #pragma omp parallel for
616  for (int i=0; i<nV; i++) label(i)=newID(label(i));
617 
618  nB=countID;
619  m.conservativeResize(nF*4, nB*4);
620  computeLabel();
621  }
622 
625  void initWeights() {
626  label=Eigen::VectorXi::Constant(nV, -1);
627  #pragma omp parallel for
628  for (int i=0; i<nV; i++) {
629  _Scalar gMin;
630  for (int j=0; j<nB; j++) {
631  _Scalar ej=errorVtxBone(i, j, false);
632  if ((label(i)==-1)||(gMin>ej)) {
633  gMin=ej;
634  label(i)=j;
635  }
636  }
637  }
638  computeLabel();
639  labelToWeights();
640  }
641 
643  MatrixX vuT;
644 
647  void compute_vuT() {
648  vuT=MatrixX::Zero(nF*4, nB*4);
649  #pragma omp parallel for
650  for (int k=0; k<nF; k++) {
651  MatrixX vuTp=MatrixX::Zero(4, nB*4);
652  for (int i=0; i<nV; i++)
653  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it) {
654  Matrix4 tmp=Vector4(v.vec3(k, i).template cast<_Scalar>().homogeneous())*u.vec3(subjectID(k), i).homogeneous().transpose();
655  vuT.blk4(k, it.row())+=it.value()*tmp;
656  vuTp.blk4(0, it.row())+=pow(it.value(), transAffineNorm)*tmp;
657  }
658  for (int j=0; j<nB; j++)
659  if (vuTp(3, j*4+3)!=0)
660  vuT.blk4(k, j)+=(transAffine*vuT(k*4+3, j*4+3)/vuTp(3, j*4+3))*vuTp.blk4(0, j);
661  }
662  }
663 
665  struct SparseMatrixBlock {
666  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
667  MatrixX val;
668  Eigen::VectorXi innerIdx, outerIdx;
669  } uuT;
670 
673  void compute_uuT() {
674  Eigen::MatrixXi pos=Eigen::MatrixXi::Constant(nB, nB, -1);
675  #pragma omp parallel for
676  for (int i=0; i<nV; i++)
677  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it)
678  for (typename SparseMatrix::InnerIterator jt(w, i); jt; ++jt)
679  pos(it.row(), jt.row())=1;
680 
681  uuT.outerIdx.resize(nB+1);
682  uuT.innerIdx.resize(nB*nB);
683  int nnz=0;
684  for (int j=0; j<nB; j++) {
685  uuT.outerIdx(j)=nnz;
686  for (int i=0; i<nB; i++)
687  if (pos(i, j)!=-1) {
688  uuT.innerIdx(nnz)=i;
689  pos(i, j)=nnz++;
690  }
691  }
692  uuT.outerIdx(nB)=nnz;
693  uuT.innerIdx.conservativeResize(nnz);
694  uuT.val=MatrixX::Zero(nS*4, nnz*4);
695 
696  #pragma omp parallel for
697  for (int i=0; i<nV; i++)
698  for (typename SparseMatrix::InnerIterator it(w, i); it; ++it)
699  for (typename SparseMatrix::InnerIterator jt(w, i); jt; ++jt)
700  if (it.row()>=jt.row()) {
701  double _w=it.value()*jt.value();
702  MatrixX _uuT(4*nS, 4);
703  Vector4 _u;
704  for (int s=0; s<nS; s++) {
705  _u=u.vec3(s, i).homogeneous();
706  _uuT.blk4(s, 0)=_w*_u*_u.transpose();
707  }
708  int p=pos(it.row(), jt.row())*4;
709  for (int c=0; c<4; c++)
710  for (int r=0; r<4*nS; r++)
711  #pragma omp atomic
712  uuT.val(r, p+c)+=_uuT(r, c);
713  }
714 
715  for (int i=0; i<nB; i++)
716  for (int j=i+1; j<nB; j++)
717  if (pos(i, j)!=-1)
718  uuT.val.middleCols(pos(i, j)*4, 4)=uuT.val.middleCols(pos(j, i)*4, 4);
719  }
720 
721 
722 
724  MatrixX mTm;
725 
728  void compute_mTm() {
729  Eigen::MatrixXi idx(2, nB*(nB+1)/2);
730  int nPairs=0;
731  for (int i=0; i<nB; i++)
732  for (int j=i; j<nB; j++) {
733  idx(0, nPairs)=i;
734  idx(1, nPairs)=j;
735  nPairs++;
736  }
737 
738  mTm=MatrixX::Zero(nS*nB*4, nB*4);
739  #pragma omp parallel for
740  for (int p=0; p<nPairs; p++) {
741  int i=idx(0, p);
742  int j=idx(1, p);
743  for (int k=0; k<nF; k++)
744  mTm.blk4(subjectID(k)*nB+i, j)+=m.blk4(k, i).template topRows<3>().transpose()*m.blk4(k, j).template topRows<3>();
745  if (i!=j) for (int s=0; s<nS; s++) mTm.blk4(s*nB+j, i)=mTm.blk4(s*nB+i, j);
746  }
747  }
748 
750  MatrixX aTb;
751 
754  void compute_aTb() {
755  #pragma omp parallel for
756  for (int i=0; i<nV; i++)
757  for (int j=0; j<nB; j++)
758  if ((aTb(j, i)==0)&&(ws(j, i)>weightEps))
759  for (int k=0; k<nF; k++)
760  aTb(j, i)+=v.vec3(k, i).template cast<_Scalar>().dot(m.blk4(k, j).template topRows<3>()*u.vec3(subjectID(k), i).homogeneous());
761  }
762 
764  _Scalar modelSize;
765 
767  SparseMatrix laplacian;
768 
770  Eigen::SparseLU<SparseMatrix> smoothSolver;
771 
774  void computeSmoothSolver() {
775  int nFV=(int)fv.size();
776 
777  _Scalar epsDis=0;
778  for (int f=0; f<nFV; f++) {
779  int nf=(int)fv[f].size();
780  for (int g=0; g<nf; g++) {
781  int i=fv[f][g];
782  int j=fv[f][(g+1)%nf];
783  epsDis+=(u.col(i)-u.col(j)).norm();
784  }
785  }
786  epsDis=epsDis*weightEps/(_Scalar)nS;
787 
788  std::vector<Triplet, Eigen::aligned_allocator<Triplet>> triplet;
789  VectorX d=VectorX::Zero(nV);
790  std::vector<std::set<int>> isComputed(nV);
791 
792  #pragma omp parallel for
793  for (int f=0; f<nFV; f++) {
794  int nf=(int)fv[f].size();
795  for (int g=0; g<nf; g++) {
796  int i=fv[f][g];
797  int j=fv[f][(g+1)%nf];
798 
799  bool needCompute=false;
800  #pragma omp critical
801  if (isComputed[i].find(j)==isComputed[i].end()) {
802  needCompute=true;
803  isComputed[i].insert(j);
804  isComputed[j].insert(i);
805  }
806 
807  if (needCompute) {
808  double val=0;
809  for (int s=0; s<nS; s++) {
810  double du=(u.vec3(s, i)-u.vec3(s, j)).norm();
811  for (int k=fStart(s); k<fStart(s+1); k++)
812  val+=pow((v.vec3(k, i).template cast<_Scalar>()-v.vec3(k, j).template cast<_Scalar>()).norm()-du, 2);
813  }
814  val=1/(sqrt(val/nF)+epsDis);
815 
816  #pragma omp critical
817  triplet.push_back(Triplet(i, j, -val));
818  #pragma omp atomic
819  d(i)+=val;
820 
821  #pragma omp critical
822  triplet.push_back(Triplet(j, i, -val));
823  #pragma omp atomic
824  d(j)+=val;
825  }
826  }
827  }
828 
829  for (int i=0; i<nV; i++)
830  triplet.push_back(Triplet(i, i, d(i)));
831 
832  laplacian.resize(nV, nV);
833  laplacian.setFromTriplets(triplet.begin(), triplet.end());
834 
835  for (int i=0; i<nV; i++)
836  if (d(i)!=0) laplacian.row(i)/=d(i);
837 
838  laplacian=weightsSmoothStep*laplacian+SparseMatrix((VectorX::Ones(nV)).asDiagonal());
839  smoothSolver.compute(laplacian);
840  }
841 
843  MatrixX ws;
844 
847  void compute_ws() {
848  ws=w.transpose();
849  #pragma omp parallel for
850  for (int j=0; j<nB; j++) ws.col(j)=smoothSolver.solve(ws.col(j));
851  ws.transposeInPlace();
852 
853  #pragma omp parallel for
854  for (int i=0; i<nV; i++) {
855  ws.col(i)=ws.col(i).cwiseMax(0.0);
856  _Scalar si=ws.col(i).sum();
857  if (si<_Scalar(0.1)) ws.col(i)=VectorX::Constant(nB, _Scalar(1)/nB); else ws.col(i)/=si;
858  }
859  }
860 
862  ConvexLS<_Scalar> wSolver;
863 
868  void compute_aTa(int i, MatrixX& aTa) {
869  aTa=MatrixX::Zero(nB, nB);
870  for (int j1=0; j1<nB; j1++)
871  for (int j2=j1; j2<nB; j2++) {
872  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());
873  if (j1!=j2) aTa(j2, j1)=aTa(j1, j2);
874  }
875  }
876 };
877 
878 }
879 
880 #ifdef DEM_BONES_DEM_BONES_MAT_BLOCKS_UNDEFINED
881 #undef blk4
882 #undef rotMat
883 #undef transVec
884 #undef vec3
885 #undef DEM_BONES_MAT_BLOCKS
886 #endif
887 
888 #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:139
Dem::DemBones::rmse
_Scalar rmse()
Definition: DemBones.h:356
Dem::DemBones::lockW
VectorX lockW
Skinning weights lock control, size = nV, lockW(i) is the amount of input skinning weights will be ke...
Definition: DemBones.h:134
Dem::DemBones::weightsSmooth
_Scalar weightsSmooth
[parameter] Weights smoothness soft constraint, default = 1e-4
Definition: DemBones.h:97
Dem::DemBones::cbTransformationsEnd
virtual void cbTransformationsEnd()
Callback function invoked after each bone transformations update.
Definition: DemBones.h:391
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:154
Dem::DemBones::nV
int nV
Number of vertices, typically indexed by i.
Definition: DemBones.h:114
Dem::DemBones::init
void init()
Initialize missing skinning weights and/or bone transformations.
Definition: DemBones.h:186
Dem::DemBones::cbWeightsIterEnd
virtual bool cbWeightsIterEnd()
Callback function invoked after each local weights update iteration, stop iteration if return true.
Definition: DemBones.h:401
Dem
Definition: ConvexLS.h:15
Dem::DemBones::transAffineNorm
_Scalar transAffineNorm
[parameter] p-norm for bone translations affinity soft constraint, default = 4.0
Definition: DemBones.h:90
Dem::DemBones::Vector4
Eigen::Matrix< _Scalar, 4, 1 > Vector4
Definition: DemBones.h:74
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:128
Dem::DemBones::computeTranformations
void computeTranformations()
Update bone transformations by running nTransIters iterations with transAffine and transAffineNorm re...
Definition: DemBones.h:237
Dem::DemBones::transAffine
_Scalar transAffine
[parameter] Translations affinity soft constraint, default = 10.0
Definition: DemBones.h:88
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:148
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:157
Dem::DemBones::SparseMatrix
Eigen::SparseMatrix< _Scalar > SparseMatrix
Definition: DemBones.h:76
Dem::indexing_vector
Eigen::CwiseNullaryOp< indexing_functor_vector< ArgType, IndexType >, typename indexing_functor_vector< ArgType, IndexType >::VectorType > indexing_vector(const Eigen::MatrixBase< ArgType > &arg, const IndexType &indices)
Definition: Indexing.h:115
Dem::DemBones::cbInitSplitBegin
virtual void cbInitSplitBegin()
Callback function invoked before each spliting of bone clusters in initialization.
Definition: DemBones.h:374
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:125
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:123
Dem::DemBones::cbTranformationsBegin
virtual void cbTranformationsBegin()
Callback function invoked before each bone transformations update.
Definition: DemBones.h:389
ConvexLS.h
Dem::DemBones::nIters
int nIters
[parameter] Number of global iterations, default = 30
Definition: DemBones.h:80
Dem::DemBones::nnz
int nnz
[parameter] Number of non-zero weights per vertex, default = 8
Definition: DemBones.h:95
Dem::DemBones::weightsSmoothStep
_Scalar weightsSmoothStep
[parameter] Step size for the weights smoothness soft constraint, default = 1.0
Definition: DemBones.h:99
Dem::DemBones::nS
int nS
Number of subjects, typically indexed by s.
Definition: DemBones.h:118
Dem::DemBones::VectorX
Eigen::Matrix< _Scalar, Eigen::Dynamic, 1 > VectorX
Definition: DemBones.h:73
Dem::DemBones::nTransIters
int nTransIters
[parameter] Number of bone transformations update iterations per global iteration,...
Definition: DemBones.h:86
Dem::DemBones::nF
int nF
Number of total frames, typically indexed by k, nF = fStart(nS)
Definition: DemBones.h:120
Dem::DemBones::DemBones
DemBones()
Constructor and setting default parameters.
Definition: DemBones.h:105
Dem::DemBones::cbWeightsEnd
virtual void cbWeightsEnd()
Callback function invoked after each skinning weights update.
Definition: DemBones.h:386
Dem::DemBones::iter
const int & iter
[zero indexed, read only] Current global iteration number that can be used for callback functions
Definition: DemBones.h:151
Dem::DemBones::cbWeightsBegin
virtual void cbWeightsBegin()
Callback function invoked before each skinning weights update.
Definition: DemBones.h:384
Dem::DemBones::Vector3
Eigen::Matrix< _Scalar, 3, 1 > Vector3
Definition: DemBones.h:75
Dem::DemBones::Triplet
Eigen::Triplet< _Scalar > Triplet
Definition: DemBones.h:77
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:131
Dem::DemBones::nInitIters
int nInitIters
[parameter] Number of clustering update iterations in the initalization, default = 10
Definition: DemBones.h:83
Dem::DemBones::weightEps
_Scalar weightEps
[parameter] Epsilon for weights solver, default = 1e-15
Definition: DemBones.h:101
Dem::DemBones::MatrixX
Eigen::Matrix< _Scalar, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Definition: DemBones.h:70
Dem::DemBones::nB
int nB
Number of bones, typically indexed by j.
Definition: DemBones.h:116
Dem::DemBones::Matrix4
Eigen::Matrix< _Scalar, 4, 4 > Matrix4
Definition: DemBones.h:71
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:145
Dem::DemBones::cbIterEnd
virtual bool cbIterEnd()
Callback function invoked after each global iteration update, stop iteration if return true.
Definition: DemBones.h:381
Dem::DemBones::cbTransformationsIterEnd
virtual bool cbTransformationsIterEnd()
Callback function invoked after each local bone transformations update iteration, stop iteration if r...
Definition: DemBones.h:396
Dem::DemBones::cbInitSplitEnd
virtual void cbInitSplitEnd()
Callback function invoked after each spliting of bone clusters in initialization.
Definition: DemBones.h:376
Dem::DemBones
Smooth skinning decomposition with rigid bones and sparse, convex weights.
Definition: DemBones.h:66
Dem::DemBones::lockM
Eigen::VectorXi lockM
Bone transformation lock control, size = nB, lockM(j) is the amount of input transformations will be ...
Definition: DemBones.h:142
Dem::DemBones::compute
void compute()
Skinning decomposition by nIters iterations of alternative updating weights and bone transformations.
Definition: DemBones.h:344
Dem::DemBones::computeWeights
void computeWeights()
Update skinning weights by running nWeightsIters iterations with weightsSmooth and weightsSmoothStep ...
Definition: DemBones.h:276
Dem::indexing_row_col
Eigen::CwiseNullaryOp< indexing_functor_row_col< ArgType, RowIndexType, ColIndexType >, typename indexing_functor_row_col< ArgType, RowIndexType, ColIndexType >::MatrixType > indexing_row_col(const Eigen::MatrixBase< ArgType > &arg, const RowIndexType &row_indices, const ColIndexType &col_indices)
Definition: Indexing.h:47
Dem::DemBones::Matrix3
Eigen::Matrix< _Scalar, 3, 3 > Matrix3
Definition: DemBones.h:72
Dem::DemBones::cbWeightsIterBegin
virtual void cbWeightsIterBegin()
Callback function invoked before each local weights update iteration.
Definition: DemBones.h:399
Dem::DemBones::clear
void clear()
Clear all data.
Definition: DemBones.h:161
Dem::DemBones::nWeightsIters
int nWeightsIters
[parameter] Number of weights update iterations per global iteration, default = 3
Definition: DemBones.h:93
Dem::DemBones::cbIterBegin
virtual void cbIterBegin()
Callback function invoked before each global iteration update.
Definition: DemBones.h:379
Dem::DemBones::cbTransformationsIterBegin
virtual void cbTransformationsIterBegin()
Callback function invoked before each local bone transformations update iteration.
Definition: DemBones.h:394