From 6fda9ea1458e6180d00c99e1a00456b19809566d Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Sat, 16 Mar 2019 18:51:13 -0700 Subject: [PATCH] simplify: Reduce the number of passes in some edge cases We previously would stop the pass when we reached the error goal, computed as the 1.5 * collapse error #k where k is the number of edges we need to collapse. This heuristic was designed to provide a balance between stopping too early, when we could have collapsed more edges in a single pass, and collapsing too many edges when the next pass could have edges with smaller error (since they will become available for collapse due to not being locked anymore). On some meshes, this resulted in very large number of passes where each pass would collapse just a few edges. As an extreme example, hairball.obj had ? passes. --- src/simplifier.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/simplifier.cpp b/src/simplifier.cpp index 3e1b1e85c..9fcf5794c 100644 --- a/src/simplifier.cpp +++ b/src/simplifier.cpp @@ -770,7 +770,7 @@ static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapse } } -static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, Quadric* vertex_quadrics, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, size_t triangle_collapse_goal, float error_limit) +static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* collapse_locked, Quadric* vertex_quadrics, const Collapse* collapses, size_t collapse_count, const unsigned int* collapse_order, const unsigned int* remap, const unsigned int* wedge, const unsigned char* vertex_kind, size_t triangle_collapse_goal, float error_goal, float error_limit) { size_t edge_collapses = 0; size_t triangle_collapses = 0; @@ -782,6 +782,9 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char* if (c.error > error_limit) break; + if (c.error > error_goal && triangle_collapses > triangle_collapse_goal / 10) + break; + if (triangle_collapses >= triangle_collapse_goal) break; @@ -1151,7 +1154,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t result_count = index_count; // target_error input is linear; we need to adjust it to match quadricError units - float error_target = target_error * target_error; + float error_limit = target_error * target_error; while (result_count > target_index_count) { @@ -1179,14 +1182,13 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, const float kPassErrorBound = 1.5f; float error_goal = edge_collapse_goal < edge_collapse_count ? edge_collapses[collapse_order[edge_collapse_goal]].error * kPassErrorBound : FLT_MAX; - float error_limit = error_goal < error_target ? error_goal : error_target; for (size_t i = 0; i < vertex_count; ++i) collapse_remap[i] = unsigned(i); memset(collapse_locked, 0, vertex_count); - size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, vertex_quadrics, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, triangle_collapse_goal, error_limit); + size_t collapses = performEdgeCollapses(collapse_remap, collapse_locked, vertex_quadrics, edge_collapses, edge_collapse_count, collapse_order, remap, wedge, vertex_kind, triangle_collapse_goal, error_goal, error_limit); // no edges can be collapsed any more due to hitting the error limit or triangle collapse limit if (collapses == 0)