Assignment 3
Mesh Deformation

Submission date: Friday, 11/14/14, 23:59

Objective:

Develop and implement a mesh deformation tool. Select a linear deformation method among those taught in class and implement a variation of it. Experiment with using a linear solver library.

Tasks:

  1. Develop a linear mesh deformation tool based on local coordinates.
  2. Use an off-the-shelf linear solver to efficiently solve the resulting linear system(s).
  3. Develop a user friendly API/visualization mechanism for your algorithm.

Instructions:

  1. 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. Start by implementing a method which does not support rotations. Then introduce a mechanism for rotation propagation throughout the region of influence (ROI).
  2. For solving the linear system you obtain you can use either the EIGEN library which comes with Cartel (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.
  3. You can limit your method to changing one anchor at a time (this way you can have a fixed rotation axis for you ROI).
  4. Bonus:
  5. Your API should support the following mesh operations, performed repeatedly and in any order (pay attention to API ease of use):
  6. To visualize the deformation process and ensure correctness you should provide the following visualization tools. You should provide an interface option (e.g. key-press) allowing the user to switch the visualization on and off.
  7. While you should work independently, it is a good idea to compare your results with other students , to verify code correctness.

Selection and Deformation:

The selection of vertices is not implemented, and will need to be done. Something like below, though you are encouraged to encapsulate it in a check to only select while the right mouse button is clicked (it will drastically slow down rendering otherwise). Also, any extra checks to avoid testing un-nessecary vertices would be ideal.

    == in ControlState.h add: ==
       std::set<size_t> selected_verts;

    == in Main.cpp: ==

    #include "Utils.h"

    ...

    /*************************************
     * Draw Selection Box
     *************************************/
    w_state->useProgram(2);
    glm::vec3 s_bl, s_tr;
    c_state.getMouseSelection(s_bl, s_tr);

    glUniform3fv(glGetUniformLocation(w_state->getCurrentProgram(),"bot_left"), 1, glm::value_ptr(s_bl));
    glUniform3fv(glGetUniformLocation(w_state->getCurrentProgram(),"top_right"), 1, glm::value_ptr(s_tr));

    //determine which vertices are in the selection box
    GLint select_viewport[4];
    glGetIntegerv(GL_VIEWPORT,select_viewport);
    glm::vec3 bl     = glm::unProject(glm::vec3(s_bl.x,s_bl.y,0), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 bl_ray = glm::unProject(glm::vec3(s_bl.x,s_bl.y,1), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 br     = glm::unProject(glm::vec3(s_tr.x,s_bl.y,0), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 br_ray = glm::unProject(glm::vec3(s_tr.x,s_bl.y,1), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 tr     = glm::unProject(glm::vec3(s_tr.x,s_tr.y,0), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 tr_ray = glm::unProject(glm::vec3(s_tr.x,s_tr.y,1), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 tl     = glm::unProject(glm::vec3(s_bl.x,s_tr.y,0), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));
    glm::vec3 tl_ray = glm::unProject(glm::vec3(s_bl.x,s_tr.y,1), w_state->view * w_state->model, w_state->projection, glm::vec4(0.0,0.0,select_viewport[2],select_viewport[3]));

    int vert_size = g_mesh->info_sizev();
    for (int i = 0; i < vert_size; i++)
    {
      Eigen::Vector3d vert = g_mesh->info_vertex(i);
      if (vert_inside_select_box(Eigen::Vector3d(bl.x,bl.y,bl.z),
                     Eigen::Vector3d(bl_ray.x,bl_ray.y,bl_ray.z),
                                   Eigen::Vector3d(br.x,br.y,br.z),
                                   Eigen::Vector3d(br_ray.x,br_ray.y,br_ray.z),
                                   Eigen::Vector3d(tr.x,tr.y,tr.z),
                                   Eigen::Vector3d(tr_ray.x,tr_ray.y,tr_ray.z),
                                   Eigen::Vector3d(tl.x,tl.y,tl.z),
                                   Eigen::Vector3d(tl_ray.x,tl_ray.y,tl_ray.z),
                     vert))
      {
        c_state.selected_verts.insert(i);
      }
    }
Similar to the above, you can calculate the direction your mouse has moved in screen coordinates. This can be used to interactively deform your mesh. Or alternatively, once selected, you can input (through the console) an amount to deform the mesh and a specific axis of deformation.

Solver:

Eigen is very easy to use, and you are already familiar with many of its types (they are used throughout Cartel). The most important thing to be aware of when solving a system 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, we recommend LDLT or LLT
  Eigen::SimplicialLDLT< Eigen::SparseMatrix<double> > solver(A);
  x = solver.solve();

  // alternatively you can pass the matrix to solve to the solve function
  // instead of initializing it.

Submission:

Send an email to Alla with the subject "DGP assign3" containing a zip file with your code. Submit your sources only.
Don't forget to include a README file explaining how to run your code.
In the email write your name and contact e-mail address.
All email should be received by Friday, 11/14/14, 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.