Assignment 3
Mesh Deformation
Submission date: Friday, 3/22/19, 23:59
Objective:
- Develop and implement a mesh deformation tool.
-
Implement the ARAP or another mesh deformation method or variation of it.
-
Experiment with a linear solver library.
Tasks:
-
Develop a linear mesh deformation tool based on local coordinates.
-
In its basic form the method should use a single linear solve, in the more advanced version use an iterative method with a rotation update mechanism.
-
Use an off-the-shelf linear solver to efficiently solve the resulting linear system/systems (using Eigen would perhaps be the easiest, since it is already being used inside minimesh).
-
Develop a user friendly API/visualization mechanism for your algorithm (the class minimesh::Mesh_viewer now has all the functionality that is needed; it is up to you to use this functionality correctly in your code).
Instructions:
-
Develop an anchor based mesh deformation tool for closed manifold meshes. You can use either an edge based
(ARAP), Laplacian (vertex based) or transformation gradient (triangle based) one (I personally recommend ARAP). Start by implementing a
method which has a single solve per anchor displacement (no rotation update). Only when this method works you can add support for iterated solver with rotation updates.
-
For solving the linear system(s) you obtain you can use either the EIGEN library which comes with minimesh (see
below) or another solver, as long as you are WELL familiar with it. Make sure the matrix you feed the
solver is full rank. Pay attention to efficiency.
-
You can limit your method to changing one anchor at a time (this way you can have a fixed rotation axis
for you ROI - think how this can simplify your updates).
-
Bonus:
-
There is a bonus for handling multiple anchors as well as for result quality and speed.
-
Note: please make sure your basic algorithm works before implementing the bonuses. There will be no bonus points given if the basic method has problems.
-
Your API should support the following mesh operations, performed repeatedly and in any order (pay
attention to API ease of use):
-
Specify an anchor vertex or triangle.
-
Specify a region of influence.
-
Perform a deformation by moving the anchor around (see "Selection and Deformation" below)
-
You can also provide a mechanism to prescribe/change anchor normals or provide a mechanism where the user specifies only anchor rotations (no translation). Note that the functionality of Minimesh::Mesh_viewer might not be enough for this task, so you would need to write some OpenGL code to read user input for changing normals.
-
To visualize the deformation process and ensure correctness you should provide a mechanism to highlight the ROI and anchor. You should provide an interface option (e.g. key-press) allowing the user to switch the
visualization on and off. Minimesh::Mesh_buffer::set_colorful_spheres() can be helpful (see below).
-
While you should work independently, it is a good idea to compare your results with other students
, to verify code correctness.
Reading User Input for Deformation and Anchor Selection:
Download minimesh version 1.6 and later. You should then have the following functionality in minimesh::Mesh_viewer:
-
The function minimesh::Mesh_viewer::get_mouse_function() allows you to change the functionality of the left mouse button in the viewer. By default, this value is changed using three radio buttons in the minimeshgui executable. You can change how the functionality is controlled for your own purposes. The provided functionality are as follows:
-
MOUSE_VIEW: in this mode, left clicking the mouse will translate the camera position.
-
MOUSE_SELECT: in this mode, the viewer will listen for the user to select vertices. After calling Mesh_viewer::mouse_pressed(), you can call Mesh_viewer::get_and_clear_vertex_selection() to see if the user clicked on a vertex, and if so, what is the number of that vertex (it also draws a red rectangle on the selected vertex for debugging). You can use this functionality to select the anchor vertices and ROI. See the function mouse_pressed() in minimeshgui for an example of using this functionality. If you want other means of selection, such as dragging the mouse, you need to add your own code for that.
-
MOUSE_MOVE_VERTEX: in this mode, the viewer will listen for the user to specify movements for a vertex. Note that the viewer does not move anything and just reports feedback through its API. After calling Mesh_viewer::mouse_moved(), you can call Mesh_viewer::get_and_clear_vertex_displacement() to see if the user attempted to move a vertex, and if so, what is the amount of movement in world coordinates, and the number of that vertex (it also draws a green rectangle on the vertex and a green line for debugging). You can use this functionality to detect how much the user wishes to move a vertex. See the function mouse_pushed() in minimeshgui for an example of using this functionality. In this demo, I just naively move the whole vertex.
-
The function Mesh_buffer::set_colorful_spheres() allows you to draw colorful rectangles (the plan was to have spheres, but they ended up to be rectangles) on top of vertices. Using this you can visualize anchor vertices for example. See the function show_spheres_pressed() in minimeshgui for an example of using this functionality.
-
The function Mesh_buffer::set_vertex_positions() is newly added. It allows you to change the vertex positions of the viewed mesh, without calling rebuild(). You might find it helpful.
-
Remember that to redraw the scene, you have to call glutPostRedisplay().
-
Not that you are not required to use the minimesh functionality to get inputs from the user. You can add your own OpenGL code, or use the keyboard to read inputs from the user.
-
For debugging purposes, you might find dumping out debugging meshes as .vtk or .obj formats and reading them using paraview or meshlab useful.
Solver:
Eigen is quite easy to use, and you are already familiar with many of its types. The most important thing to be aware of when solving a system with more than ~1000 variables is that you should be using a Sparse solver. If you are solving the system
Ax = b. You would proceed as below:
Eigen::VectorXd b;
Eigen::VectorXd x;
Eigen::SparseMatrix<double> A(m, n);
// populate b
...
// populate A
std::vector<Eigen::Triplet<double>> A_elem;
for (non-zero elements) {
A_elem.push_back( Eigen::Triplet<double>(row, column, value) );
}
A.setFromTriplets(A_elem.begin(), A_elem.end());
// solve using your prefered solver.
// For symmetric systems use LDLT or LLT
// For non-symmetric systems use PartialPivLU or FullPivLU
Eigen::SimplicialLDLT< Eigen::SparseMatrix<double> > solver;
// Call this only once for each value of A
solver.compute(A);
// Call this as many times as you want for one or different values of b,
// as long as A is not changed.
x = solver.solve(b);
// Remember that calling solver.compute() is much more expensive that solver.solve().
// Therefore, if the matrix A has not changed, be careful not to call solver.compute()
// more than required.
Submission:
Use the handin system similar to the previous assignments (this time using ``handin a3''). Submit your sources only.
Don't forget to include a README file explaining how to run your code and your name.
All assignments should be handed in by Friday, 3/22/19, at 23:59.
You can use your grace days (if you still have them). No late assignments, beyond those, will be accepted.
This assignment is 15% of your final grade.