4

Recently I am implementing the QEM mesh simplification algorithm, which was originally from Michael Garland and Paul S. Heckbert's paper Surface Simplification Using Quadric Error Metrics.

According to the algorithm, we should compute a contraction cost for each edge, and put all the edges into a minimal heap, so that every time we pick up an edge with the minimal cost to contract. However, the contraction may cause the incident triangles fold over, i.e. the norm changes over 90 degrees before and after the contraction. The fold-over phenomenon can be visualized by the following example:

Suppose the edge with the minimal cost we pick up is V1V2, and we are about to contract it. We foresee the contraction will cause V1 and V2 merge together as the figure shows. More importantly, if we define the norm of the triangle Tri(ABV2) as cross_product(V2A, V2B), we can find this norm changes its direction from pointing outwards to inwards. This is not what we want. The paper says if encounter this situation, we should "penalize" this operation, i.e. adding a large number to V1V2's cost so that V1V2 becomes non-top of the heap, which means it will not be picked up at this moment. Instead, we will pick up the next edge with the minimal cost.

The algorithm can be written with the following pseudo code:

while (number_of_left_edges > Pre_defined_number)
{
    Edge e = EdgeHeap.top();
    if (Check_edge_will_cause_foldover(e))
    {
         e.cost += A_VERY_LARGE_NUMBER;
         EdgeHeap.update();
    }
    else
    {
         e.Contract();
         Do_something_on_incident_triangles(e.Triangles);
         EdgeHeap.pop();
    }
}

However, I found a very tough problem. As mentioned, when I found the contraction of an edge E1 may cause fold-over of some triangles, I enlarged its cost and threw it back to the heap, then I picked another edge E2, and still found it would cause fold-over. So and so forth. I didn't find an edge could be contracted any more, so that the loop infinitely continued, and actually no edge be simplified.

Is there any one who can give me any hint about the algorithm, so that to solve the problem? Thank you so much!

enter image description here

C. Wang
  • 2,516
  • 5
  • 29
  • 46
  • 1
    I know this question is old, but did you ever find a solution? I am also wondering about this problem. In the example shown, one solution might be to delete the edge from B to V1V2 and add a new edge to fill in the resulting hole involving A – jms Nov 23 '20 at 17:06

1 Answers1

0

A good solution here is to check for possible normal inversion (fold-over) just after the edge is extracted from minimal heap and before it is contracted. If the check fails, then the edge is not penalized anyhow, but just skipped for now, and it can appear in the minimal heap later after contraction of one of its neighbors.

The check can be implemented in pseudocode as follows:

//average normal of the mesh region around the edge being checked before contraction
Vector3 beforeNormal = ...
// now check all triangles to appear after contraction
for ( afterTri : ... )
   if ( dot( norm(afterTri), beforeNormal ) < 0 )
       return //check failed
return //check passed

This approach is implemented MeshLib having fast and high quality mesh simplification module based on the same paper. The corresponding code in MRMeshDecimate.cpp is

auto n = Vector3f{ sumDblArea_.normalized() };
for ( const auto da : triDblAreas_ )
    if ( dot( da, n ) < 0 )
        return {};
Fedor
  • 17,146
  • 13
  • 40
  • 131