From ccbece58d89871aed7b7c19de4bcdf70a81228a8 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 27 Aug 2025 08:51:21 -0700 Subject: [PATCH] Enable component pruning during simplification In addition to the regular edge collapse, we now allow the simplifier to remove small isolated components. Components that are removed are below the error threshold in size and as such should not noticeably contribute to the overall rendering of the object. This helps simplify topologically complex but small parts of larger meshes and more comfortably reach the LOD targets. In some cases, pruning can cause the last LOD to shrink to 0 triangles which may prevent a slightly larger LOD from being used at the maximum distance; in this case we retry simplification without pruning once. --- scene/resources/3d/importer_mesh.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scene/resources/3d/importer_mesh.cpp b/scene/resources/3d/importer_mesh.cpp index 8121866f839..43e72777f9c 100644 --- a/scene/resources/3d/importer_mesh.cpp +++ b/scene/resources/3d/importer_mesh.cpp @@ -480,6 +480,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf LocalVector current_indices = merged_indices; float current_error = 0.0f; + bool allow_prune = true; while (current_indices.size() > min_target_indices * 2) { unsigned int current_index_count = current_indices.size(); @@ -493,6 +494,11 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf // Lock geometric boundary in case the mesh is composed of multiple material subsets. simplify_options |= SurfaceTool::SIMPLIFY_LOCK_BORDER; + if (allow_prune) { + // Remove small disconnected components. + simplify_options |= SurfaceTool::SIMPLIFY_PRUNE; + } + if (deformable) { // Improves appearance of deformable objects after deformation by using more regular tessellation. simplify_options |= SurfaceTool::SIMPLIFY_REGULARIZE; @@ -513,6 +519,15 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, Array p_bone_transf simplify_options, &step_error); + if (new_index_count == 0 && allow_prune) { + // If the best result the simplifier could arrive at with pruning enabled is 0 triangles, there might still be an opportunity + // to reduce the number of triangles further *without* completely decimating the mesh. It will be impossible to reach the target + // this way - if the target was reachable without going down to 0, the simplifier would have done it! - but we might still be able + // to get one more slightly lower level if we retry without pruning. + allow_prune = false; + continue; + } + // Accumulate error over iterations. Usually, it's correct to use step_error as is; however, on coarse LODs, we may start // getting *smaller* relative error compared to the previous LOD. To make sure the error is monotonic and strictly increasing, // and to limit the switching (pop) distance, we ensure the error grows by an arbitrary factor each iteration.