Cloth Simulator Improvement Final Report

Implementing adaptive remeshing involved many different steps. To break it down to the simplest form, "sizing" for the vertices is determined which determines the "sizing" of the edge, this is then used to either split the edge, collapse the edge or flip the edge.

What has been done:

The remeshing step is performed every frame. It starts by creating an equivalent triangulated BMesh of the cloth if it does not already exist from the previous frame. After this, the vertex sizing is determined. This is done by first finding face sizing and then the area weighted average is taken to find the vertex sizing. Face sizing is found via the various different parameters. For the obstacle parameter, planes to the nearest collision meshes are determined, this is done using BVH trees. The curvature parameter is found by taking the curvature of the positions of the vertices. The velocity parameter is found by taking the derivative of the velocities of the vertices. Finally the compression parameter is found by taking the derivative of the positions of the vertices. These different parameters are then summed to get the initial sizing field. The eigendecomposition of the initial sizing field is done so that some clamping measures can be added to prevent extremely small or extremely large triangles. Now that the vertex sizing has been found, the actual mesh can now be changed. As mentioned previously, there are 3 main functions on the edges (splitting, collapsing, flipping).

Split Edges: First, the "bad edges" are found, this is done by finding the edge size - if the edge size exceeds 1, then it is termed as a bad edge and must be split. The BMesh API has a function for this, BM_edge_split(), the problem is that the mesh would now be non-triangular, so a specialized function is written to ensure the mesh remains triangulated even the edge is split. After each of the edge splits, edges near the newly created vertex are tried for flip edges. The newly created vertex should also be added to the cloth's vertices. This is done by taking the average of different parameters of the vertices of the edge that is split. A special case exists for sewing which is explained later.

Collapse Edges: All the faces of the mesh are considered to be "active faces". For each "active face", its edges are iterated through and an attempt to collapse the edge (vertex 1 into vertex 2 and vice versa) is made. If neither is possible, the face is removed from "active faces". Similar to split edges, edges near the edge that is collapsed are tried for flip edges. An edge can be collapsed if the vertex that will be killed was not part of the original user-defined mesh, either both vertices are on a seam or boundary or neither of the vertices are, the aspect ratio of the newly created faces is with the user-defined aspect ratio and the size of the newly created edges doesn't not exceed 1 minus a small hysteresis parameter. If all these parameters are met, then the edge is collapsed. The vertex that is killed is removed from the cloth's vertices as well.

Flip Edges: First, all the edges that can be flipped are found. This is done by iterating over the edges of each face part of the "active faces" and checking if these edges are flippable. An edge is considered flippable if it doesn't lie on a seam or boundary, and it meets an anisotropic parameter. After this, an independent set of these edges is found. This set of edges is now flipped using BM_edge_rotate(). Since this doesn't change the number of vertices, the cloth's vertices don't need to be updated.

Sewing: If an edge in between 2 sewing edges is split, a new sewing edge (loose edge) must be added to ensure the user-defined sewing is maintained. This is done by finding the edge on the opposite side of the sewing edges and then checking if that particular edge can be split. If it can be, a new edge is created between the newly created vertices of these 2 edges when split, otherwise a vertex on the opposite side edge is arbitrarily chosen and is joined with the newly created vertex of this edge when split.

Pinning: Pinning has been implemented through vertex groups, this means there are CustomData layers for each vertex which stores the pin weight of the vertex. Since the newly created vertices must not have interpolated values for its pin weights (users would not have their creative control otherwise), the weight is set to 0 for the newly created vertices.

After all these steps, a new Mesh must be made from the BMesh and passed along in the simulation. After the new Mesh is made, the springs must be updated along with BVH tree and some other useful information. Since the cloth simulation can now change the number of vertices of the mesh, the modifier is now an applyModifier() based modifier instead of a deformModifier() based modifier, along with this the necessary changes needed are also done.

To Do:

Despite my best efforts to make the remeshing step stable and highly optimized, there are some known bugs to be fixed.

  • Mesh looping changes unpredictably after some BMesh operation: It is unknown to me after which BMesh operation the mesh looping changes so significantly (some vertices and edges seem to swap) that the entire cloth becomes severely unstable.
  • Collapse Edges doesn't run expected number of times: Not all the edges that need to be collapsed during a certain remeshing step are collapsed, this means that there are more vertices than required to give the same visual information, leading to slowdowns.

There is one feature that don't work well yet with the remeshing step,

  • Caching: The current approach towards caching involves running the remeshing step before checking if the number of points in the current mesh match the number of points stored in the cache file. This works when the playback is started again from the first frame, otherwise it fails leading to crashes.


GSoC branch: [1]

Complete diff: [2]

Proposal: [3]

Weekly Reports: [4]

User Documentation: [5]

Examples: [6]