To get started: Clone this repository by issuing
git clone --recursive http://github.com/alecjacobson/geometry-processing-deformation.git
See introduction.
Once built, you can execute the assignment from inside the build/
by running
on a given mesh:
./deformation [path to mesh.obj]
When the mesh is blue, the system is in "place handles" mode. Click on the mesh
to select vertex locations for control point handles. After pressing space to switch to
deformation mode, drag the handles. Pressing m
will switch between different
deformation methods.
In this assignment we explore smooth deformation of an existing shape. Shape deformation has many applications in geometry process; we will focus on interactive handle-based deformation. In this setup, the user repositions a sparse set of points and the goal is to propagate the transformation at these "handles" to the rest of the shape. To be interactive we should aim for computing the new deformation of the shape at around 30 frames per second.
Shape deformation is the transformation from its rest shape to a
new/current/deformed shape. If the position of a point on some 3D rest shape
given by
The propagation of the handles' deformation can be thought of in two complementary ways:
- as a scattered data interpolation problem, where handles provide sparse samples of an unknown displacement field, or
- as a shape optimization problem, where we try to define a new shape that retains the details of the old shape but fulfills the handle constraints.
In the following discussion we will take advantage of the ability to switch
between thinking of the unknowns as the positions of the deformed shape (
We will limit ourselves to continuous deformations of shapes. That is, the shape will not tear, crack or change its topological features.
If we represent our shape discretely as a triangle
mesh (e.g., with rest vertices
in
A rest surface
Similarly the deformed surface can be represented as a position function
For the handle-based deformation problem we would like to find a new surface
(defined by
- adds as little distortion as possible to the shape, and
- satisfies the users constraints at selected handle positions.
We can cast this as an energy optimization problem. Suppose we have
energy functional
To ensure that the user's
where
While the constraints are straightforward, we have many choices for how to
formulate the energy function
where
If we assume that the deformation between the rest shape given by
Let us first consider minimizing the integral of squared variation of the displacement field:
where
the Jacobian
matrix of the displacement field
If
$\mathbf{I} \in \mathbb{R}^{3 \times 3}$ is the identity matrix, then the quantity$\mathbf{F} := \mathbf{I} + {\nabla}\mathbf{d}$ is referred to as the deformation gradient in the mechanics community.
This is simply the familiar Dirichlet energy applied to each coordinate function of the displacement field independently.
We can discretize this over our triangle mesh surface the same way we have in smoothing and parameterization assignments:
where the rows of
While easy to implement, this method suffers from a couple immediate problems:
- it is not smooth at constraints, and
- then influence of handles dies off too quickly.
By minimizing the Dirichlet energy, each coordinate of "displacement field" is a harmonic function. Intuitively (however abstractly) we can think of each function as diffusing the user's constraints as if they were heat values. As such, each function diffuses quickly to an average, slowly varying value over most of the domain. As a displacement field a constant value for each coordinate function would mean a translation: most of the shape is simply translated.
The gradient operator (
If we think of the gradient of the position function
Unfortunately, the gradient of the position function
If we model distortion as the change in a local feature descriptor, then a natural local and relative descriptor would be one that compared the position of some point on the shape to the average of its local neighborhood. We have studied an operator that computes this in the smoothing assignment. The Laplace(-Beltrami) operator can be derived as taking exactly the difference of a functions value at a point and the average (i.e., centroid) of an infinitesimal region around that point:
(see, e.g., "Differential coordinates for local mesh morphing and deformation" [Alexa et al. 2003] and expanded upon in "Laplacian Surface Editing" [Sorkine et al. 2004]).
When applied to the embedding function
Let's replace the gradient feature above with this second-order feature descriptor and massage our optimization problem back in terms of displacements:
Just as we can show that harmonic functions (
The fact that each coordinate of the displacement field
To discretize this energy we can make use of our discrete Laplacian operator
where
The logical continuation of harmonic and biharmonic deformation is to consider triharmonic (
$\Delta ^{3}\mathbf{d} = 0$ ) and tetraharmonic ($\Delta ^{4}\mathbf{d} = 0$ ) and so on. It's straightforward to implement these, though there are diminishing returns and increasing costs.
With out loss of generality, assume that the rows of the unknown displacements
Since the displacements at handles are known before the optimization, we can separate the knowns and unknowns in the energy:
where
This quadratic optimization problem may solved by setting all partial
derivatives with respect to degrees of freedom in
If we don't change which vertices are handles, but only change the positions
of the selected handles, then only igl::min_quad_with_fixed
does this for you).
Actually the entire term
$\mathbf{Q}_\text{u,u}^{-1}\mathbf{Q}_\text{u,h} =: \mathbf{W} \in \mathbb{R}^{(n-k)\times k}$ does not change. The columns of$\mathbf{W}$ reveal how unknown displacements respond to each handle point's displacement (see also "An intuitive framework for real-time freeform modeling" [Botsch & Kobbelt 2004]). This provides a gateway to the relationship with linear blend skinning and automatic (biharmonic) weighting functions (see "Bounded Biharmonic Weights for Real-Time Deformation" [Jacobson et al. 2011]).
Biharmonic displacements work well for small deformations and deformations that
do not imply a large rotation. However, the Laplacian of the position function
This means that if the user transforms all of the handle locations by a rigid
transformation
In the scenario where each handle
where the translation vector
We do not know the rotation
If we treat
Optimizing this energy will ensure global rotation invariance. To ensure
local rotation invariance, we can replace
For embedded solid shapes, we can take the rest shape given by
$\widetilde{\mathbf{x}}$ as the parameterization${\Omega}$ , so that${\nabla}\widetilde{\mathbf{x}} = \mathbf{I}$ . This allows us to rewrite the as-rigid-as-possible energy as the square of the difference between the deformation gradient and the closest rotation:
This form provides a bridge between the as-rigid-as-possible energy common in geometry processing to corotated linear elasticity used in mechanics/physically-based simulation (made explicit in "A simple geometric model for elastic deformations" [Chao et al. 2010]). See Section 3.4 of "FEM Simulation of 3D Deformable Solids" [Sifakis 2012] for a graphics-mechanics perspective.
For a triangle mesh with displacing vertices, the gradient of the embedding
function is constant inside each triangle. In this way we can write the raw
gradient energy above as a double sum over all half-edges
where
To inject localized best fit rotations, we will assign an unknown rotation
matrix
where
We have assigned a rotation for each vertex: there are
$n$ rotation matrices as auxiliary degrees of freedom. This is in contrast to assigning rotations per face (as in "A Local/Global Approach to Mesh Parameterization" [Liu et al. 2008]). Per-face--or more generally per-element--rotations work well for codimension zero objects (triangle meshes in$\mathbb{R}^{2}$ or tetrahedral meshes in$\mathbb{R}^{3}$ ). But for triangle mesh surfaces in$\mathbb{R}^{3}$ (i.e., codimension 1), per-face rotations would lead to "crumpling") because bending along edges would not be measured.
The simplest method for optimizing the ARAP energy is by alternating between
- finding the optimal rotations
$\mathbf{R}_k$ assuming the vertex positions$\mathbf{V}$ are fixed, and - finding the optimal vertex positions
$\mathbf{V}$ assuming all rotations$\mathbf{R}_k$ are fixed.
Each rotation
Observing the discrete energy above we can see that the energy is quadratic in
if we stack the rotation matrices
where
Let's take it slow. The
$\mathbf{K}$ matrix is represents the bilinear form that combines unknown vertex positions and unknown rotations. We have identified above that we can write this in summation or matrix form:
$$ \frac{1}{6} \sum\limits_{k=1}^n \sum\limits_{ ij \in F(k)} c_{ij} (\mathbf{v}_i-\mathbf{v}_j)^{\mathsf T} \mathbf{R}_k (\widetilde{\mathbf{v}}_i-\widetilde{\mathbf{v}}_j) = \text{tr}{\left( \mathbf{V}^{\mathsf T} \mathbf{K} \mathbf{R} \right)}, $$ but how did we get here?
Let's start with the summation form. The constants of this formula are the
$c_{ij}$ terms and the$(\widetilde{\mathbf{v}}_i-\widetilde{\mathbf{v}}_j)$ terms. Since these always appear together, let us merge them into weighted edge difference vectors$c_{ij} (\widetilde{\mathbf{v}}_i-\widetilde{\mathbf{v}}_j) =: \widetilde{\mathbf{e}}_{ij} \in \mathbb{R}^{3}$ :
$$ \frac{1}{6} \sum\limits_{k=1}^n \sum\limits_{ ij \in F(k)} \underbrace{(\mathbf{v}_i-\mathbf{v}_j)^{\mathsf T} \mathbf{R}_k \widetilde{\mathbf{e}}_{ij}}_{\in \mathbb{R}}, $$ the inner term in the summation is an inner product; that is, a scalar. Let's expose this by expanding the matrix-vector products of the inner-product:
$$ \frac{1}{6} \sum\limits_{k=1}^n \sum\limits_{ ij \in F(k)} \sum\limits_{{\alpha}=1}^3 \sum\limits_{{\beta}=1}^3 (v_i^{\alpha} - v_j^{\alpha})R_k^{{\alpha}{\beta}}\widetilde{e}_{ij}^{\beta}. $$ If our mesh is stored as a vertex list and face list, it's not easy/efficient to loop over per-vertex rotations (outer sum) and then over all half-edges of incident faces (second sum). Instead, let's rearrange these sums to loop over all faces first, then the half-edges of that face, and then over all per-vertex rotations that involve this half-edge:
$$ \frac{1}{6} \sum\limits_{f=1}^m \sum\limits_{ ij \in E(f)} \quad \sum\limits_{k | ij \in F(k)} \quad \sum\limits_{{\alpha}=1}^3 \sum\limits_{{\beta}=1}^3 (v_i^{\alpha} - v_j^{\alpha})R_k^{{\alpha}{\beta}}\widetilde{e}_{ij}^{\beta}, $$ where the third sum is over all rotations
$k$ such that the half-edge$ij$ belongs to the half-edges of the faces incident on the$k$ -th vertex:$k | ij \in F(k)$ . Well, this means$k$ can either be$i$ or$j$ or the third vertex of the$f$ -th face.Now let's turn our attention back to the summand. The terms indexed by
${\alpha}$ never mix. That is, we never add/multiply$v_i^{\alpha}$ ,$v_j^{\gamma}$ , and$R_k^{{\delta}{\beta}}$ unless${\alpha}={\gamma}={\delta}$ . This implies that we can write this summation in matrix form as:
$$ \mathbf{V}_{1}^{\mathsf T} \mathbf{K}_{1} \mathbf{R}_{1} + \mathbf{V}_{2}^{\mathsf T} \mathbf{K}_{2} \mathbf{R}_{2} + \mathbf{V}_{3}^{\mathsf T} \mathbf{K}_{3} \mathbf{R}_{3}, $$ where
$\mathbf{V}_{\alpha} \in \mathbb{R}^n$ is${\alpha}$ -th column of$\mathbf{V}$ ,$\mathbf{R}_{\alpha} \in \mathbb{R}^{3n}$ is the${\alpha}$ -th column of$\mathbf{R}$ and$\mathbf{K}_{1},\mathbf{K}_{2},\mathbf{K}_{3} \in \mathbb{R}^{n \times 3n}$ are sparse matrices.Further, the constant term
$\widetilde{e}^{\beta}_{ij}$ in the summation acts the same on$(v_i^{\alpha} - v_j^{\alpha})R_k^{{\alpha}{\beta}}$ for any${\alpha}$ value. This implies that$\mathbf{K}_{1}=\mathbf{K}_{2}=\mathbf{K}_{3}$ , so we can reduce the matrix form to:
$$ \text{tr}{\left(\mathbf{V} \mathbf{K} \mathbf{R}\right)}. $$ Finally, we can answer what is in each entry
$K_{vw}$ , where$v$ chooses the row and$w=3k+{\beta}$ chooses the column of$\mathbf{K}$ . Treating our nested summation as nested for-loops, we can increment entries in$\mathbf{K}$
$$ \begin{align*} K_{i\ 3k+{\beta}} & \mathrel{+}= \widetilde{e}_{ij}^{\beta}, \\ K_{j\ 3k+{\beta}} & \mathrel{+}= -\widetilde{e}_{ij}^{\beta}, \\ \end{align*} $$ for each half-edge encountered.
Minimizing this energy with respect
where
Minimizing the energy above with respect to
where
In order to facilitate interactive deformation we would like our local and
global iterations to be computed as quickly as possible. Since the quadratic
form in the global step is the same regardless of the current rotations or
current handle positions, we can
prefactorize it (again,
as above). The matrix
Note: When constructing
$\mathbf{K}$ it's easiest to iterate over all half-edges in the mesh (by iterating over all faces and then each of the three edges). Each half-edge$ij$ contributes terms tying$\mathbf{v}_i,\mathbf{v}_j$ to each of the (three) rotations$\mathbf{R}_k$ that apply against their difference (see "Fast Automatic Skinning Transformations" [Jacobson et al. 2012]).
The as-rigid-as-possible deformation method for surfaces described above has a number of remaining problems:
- like its gradient-based energy ancestor the deformation is not smooth at constraints;
- the energy punishes bending of the surface--which is good--but does so in a way that diminishes as the mesh becomes higher and higher resolution, in otherwords, the discrete energy is mesh-resolution dependent; and
- the energy is biased by the original combinatorics of the mesh (even in flat regions).
igl::arap
igl::arap_linear_block
igl::covariance_scatter_matrix
igl::harmonic
igl::polar_svd3x3
(or your previous assignment'sclosest_rotation
)igl::min_quad_with_fixed
igl::cotmatrix_entries
igl::cotmatrix
(or your previous implementation)igl::massmatrix
(or your previous implementation)
Precompute data needed to efficiently solve for a biharmonic deformation given
a mesh with vertices V
and faces F
and a list of selected vertices as
indices b
into V
. The output should be a prefacorized system using the
data
struct employed by igl::min_quad_with_fixed
.
Given precomputation data
and a list of handle displacements determine
displacements for all vertices in the mesh.
Precompute data needed to efficiently conduct local-global iterations for an
arap deformation. This includes the data
struct employed by
igl::min_quad_with_fixed
to solve the global step" and constructing the
bilinear form K
that mixes rotation degrees of freedom with unknown
positions for preparing the covariance matrices of the local step and the
linear term of the global step.
Given precomputed data (data
and K
), handle positions bc
and current
positions of all vertices U
, conduct a single iteration of the local-global
solver for minimizing the as-rigid-as-possible energy. Output the positions
of all vertices of the mesh (by overwriting U
).