原理:
m i n x ∫ S ∣ ∣ Δ x − Δ x ^ ∣ ∣ 2 d A min_{x}\int_{S}||\Delta x-\Delta \hat{x}||^{2}dA minx∫S∣∣Δx−Δx^∣∣2dA
d = x − x ^ d=x-\hat{x} d=x−x^
=> m i n d ∫ S ∣ ∣ Δ d ∣ ∣ 2 d A min_{d}\int_{S}||\Delta d||^{2}dA mind∫S∣∣Δd∣∣2dA
=> m i n D D T L T M − T M M − 1 L D min_{D}\space D^{T}L^{T}M^{-T}MM^{-1}LD minD DTLTM−TMM−1LD
M : M a s s M a t r i x M:Mass \space Matrix M:Mass Matrix
L : c o t M a t r i x L:cot \space Matrix L:cot Matrix
=> m i n D D T L T M − 1 L D min_{D}\space D^{T}L^{T}M^{-1}LD minD DTLTM−1LD
=> m i n D D T Q D min_{D}\space D^{T}QD minD DTQD
D h a n d l e s D_{handles} Dhandles已知
=> m i n D D T Q D min_{D}\space D^{T}QD minD DTQD subject to D h a n d l e s = D k o w n V a l u e D_{handles}=D_{kownValue} Dhandles=DkownValue
每次拖动鼠标时,变化的只是 D h a n d l e s D_{handles} Dhandles,所以可以先计算出Q,在实时计算时实时更新 D h a n d l e s D_{handles} Dhandles即可,算出D后, V n e w = V o l d + D V_{new}=V_{old}+D Vnew=Vold+D
#include "biharmonic_precompute.h"
#include "cotmatrix.h"
#include "massmatrix.h"
void biharmonic_precompute(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const Eigen::VectorXi & b,
Eigen::SparseMatrix<double> & QQ)
{
Eigen::SparseMatrix<double> L;
cgpl::cotmatrix(V, F, L);
Eigen::SparseMatrix<double> M;
cgpl::massmatrix(V, F, M);
Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver(M);
Eigen::SparseMatrix<double> M_inv_L = solver.solve(L).sparseView();
Eigen::SparseMatrix<double> Q = L.transpose() * M_inv_L; // L^T M^-1 L
typedef Eigen::Triplet<double>T;
std::vector<T>tripleList;
std::vector<bool> Known(V.rows(), false);
for (int i = 0; i < b.rows(); i++)
{
Known[b(i)] = true;
tripleList.push_back(T(b(i), b(i), 1));
}
for (int i = 0; i < Q.outerSize(); i++)
{
for (Eigen::SparseMatrix<double>::InnerIterator it(Q, i); it; ++it)
{
int row = it.row();
int col = it.col();
if (Known[row] == false)
{
tripleList.push_back(T(row, col, it.value()));
}
}
}
QQ.resize(V.rows(), V.rows());
QQ.setFromTriplets(tripleList.begin(), tripleList.end());
}
#include "biharmonic_solve.h"
#include
void biharmonic_solve(
const Eigen::SparseMatrix<double> & QQ,
const Eigen::VectorXi & b,
const Eigen::MatrixXd & bc,
Eigen::MatrixXd & D)
{
D.resize(QQ.cols(), 3);
Eigen::SparseLU<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>>solver;
Eigen::VectorXd dx = Eigen::VectorXd::Zero(QQ.cols());
Eigen::VectorXd dy = Eigen::VectorXd::Zero(QQ.cols());
Eigen::VectorXd dz = Eigen::VectorXd::Zero(QQ.cols());
for (int i = 0; i < b.rows(); i++)
{
dx(b(i)) = bc(i, 0);
dy(b(i)) = bc(i, 1);
dz(b(i)) = bc(i, 2);
}
solver.compute(QQ);
Eigen::VectorXd Dx=solver.solve(dx);
Eigen::VectorXd Dy=solver.solve(dy);
Eigen::VectorXd Dz=solver.solve(dz);
D << Dx, Dy, Dz;
}
原理:
Rigid Transformation: x i = R x i ^ + t x_{i}=R\hat{x_{i}}+t xi=Rxi^+t
1 2 ∫ Ω ‖ ▽ x − ▽ x ^ ‖ 2 d A \frac{1}{2}\int_{Ω} ‖ \triangledown x - \triangledown \hat{x}‖^{2} dA 21∫Ω‖▽x−▽x^‖2dA
=> 1 2 Σ f ∈ F Σ i j ∈ f c i j ‖ ( v i − v j ) − ( v ^ i − v ^ j ) ‖ ² \frac{1}{2} \Sigma_{f \in F} \Sigma_{ ij \in f} c_{ij} ‖ (v_{i}-v_{j}) - (\hat{v}_{i}-\hat{v}_{j})‖² 21Σf∈FΣij∈fcij‖(vi−vj)−(v^i−v^j)‖²
=> 1 6 Σ k = 1 N Σ i j ∈ F ( K ) c i j ‖ ( v i − v j ) − ( v ^ i − v ^ j ) ‖ ² \frac{1}{6} \Sigma_{k=1}^{N} \Sigma_{ ij \in F(K)} c_{ij} ‖ (v_{i}-v_{j}) - (\hat{v}_{i}-\hat{v}_{j})‖² 61Σk=1NΣij∈F(K)cij‖(vi−vj)−(v^i−v^j)‖²
=> 1 6 Σ k = 1 N Σ i j ∈ F ( K ) c i j ( v i − v j ) T ( v i − v j ) + 1 6 Σ k = 1 N Σ i j ∈ F ( K ) c i j ( v i − v j ) T R k ( v ^ i − v ^ j ) \frac{1}{6} \Sigma_{k=1}^{N} \Sigma_{ ij \in F(K)} c_{ij} (v_{i}-v_{j})^{T} (v_{i}-v_{j})+\frac{1}{6} \Sigma_{k=1}^{N} \Sigma_{ ij \in F(K)} c_{ij} (v_{i}-v_{j})^{T}R_{k} (\hat{v}_{i}-\hat{v}_{j}) 61Σk=1NΣij∈F(K)cij(vi−vj)T(vi−vj)+61Σk=1NΣij∈F(K)cij(vi−vj)TRk(v^i−v^j)
=> t r ( V T L V ) + t r ( V T K R ) tr(V^{T}LV)+tr(V^{T}KR) tr(VTLV)+tr(VTKR)
m i n R t r ( V T K R ) min_{R}\space tr(V^{T}KR) minR tr(VTKR)
C T = V T K C^{T}=V^{T}K CT=VTK
用到的一个结论:
C T = U Σ V T C^{T}=U\Sigma V^{T} CT=UΣVT
R = U V T R=UV^{T} R=UVT时 t r ( V T K R ) tr(V^{T}KR) tr(VTKR)有最优解
m i n V t r ( V T L V ) + t r ( V T B ) min_{V}\space tr(V^{T}LV)+tr(V^{T}B) minV tr(VTLV)+tr(VTB)
#include "arap_precompute.h"
#include "cotmatrix.h"
typedef Eigen::Triplet<double> T;
void arap_precompute(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const Eigen::VectorXi & b,
Eigen::SparseMatrix<double> & Q,
Eigen::SparseMatrix<double> & K)
{
Eigen::SparseMatrix<double> L;
cgpl::cotmatrix(V, F, L);
std::vector<T>tripleList;
std::vector<bool> Known(V.rows(), false);
for (int i = 0; i < b.rows(); i++)
{
Known[b(i)] = true;
tripleList.push_back(T(b(i), b(i), 1));
}
for (int i = 0; i < L.outerSize(); i++)
{
for (Eigen::SparseMatrix<double>::InnerIterator it(L, i); it; ++it)
{
int row = it.row();
int col = it.col();
if (Known[row] == false)
{
tripleList.push_back(T(row, col, it.value()));
}
}
}
Q.resize(V.rows(), V.rows());
Q.setFromTriplets(tripleList.begin(), tripleList.end());
int nV = V.rows();
std::vector<T> tripletList;
for(int f = 0; f < F.rows(); f++) {
for(int a = 0; a < 3; a++) {
int i = F(f, (a + 1) % 3);
int j = F(f, (a + 2) % 3);
Eigen::Vector3d diff = V.row(i) - V.row(j);
Eigen::Vector3d eij = L.coeff(i, j) * diff / 6.0;
for(int ki = 0; ki < 3; ki++) {
int k = F(f, (a + ki) % 3);
for(int B = 0; B < 3; B++) {
tripletList.push_back(T(i, 3 * k + B, eij[B]));
tripletList.push_back(T(j, 3 * k + B, -eij[B]));
}
}
}
}
K.resize(nV, 3 * nV);
K.setFromTriplets(tripletList.begin(), tripletList.end());
}
#include "arap_single_iteration.h"
void polar_svd3x3(const Eigen::Matrix3d &C,Eigen::Matrix3d &R)
{
Eigen::JacobiSVD<Eigen::MatrixXd> svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV);
Eigen::Matrix3d V = svd.matrixV();
Eigen::Matrix3d U = svd.matrixU();
R = U* V.transpose() ;
}
void arap_single_iteration(
const Eigen::SparseMatrix<double> & Q,
const Eigen::VectorXi & b,
const Eigen::SparseMatrix<double> & K,
const Eigen::MatrixXd & bc,
Eigen::MatrixXd & U)
{
Eigen::MatrixXd C = K.transpose() * U;
Eigen::MatrixXd R(C.rows(), C.cols());
for(int k = 0; k < Q.cols(); k++) {
Eigen::Matrix3d C_k = C.block(k * 3, 0, 3, 3);
Eigen::Matrix3d R_k;
C_k.normalize();
polar_svd3x3(C_k, R_k);
R.block(k * 3, 0, 3, 3) = R_k;
}
Eigen::MatrixXd B= K * R;
B = -B;
U.resize(Q.cols(), 3);
Eigen::SparseLU<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>>solver;
for (int i = 0; i < b.rows(); i++)
{
B(b(i),0) = bc(i, 0);
B(b(i),1) = bc(i, 1);
B(b(i),2) = bc(i, 2);
}
solver.compute(Q);
Eigen::VectorXd X=solver.solve(B.col(0));
Eigen::VectorXd Y=solver.solve(B.col(1));
Eigen::VectorXd Z=solver.solve(B.col(2));
U << X, Y, Z;
}