mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 03:11:47 +00:00
Simplify flat faces even when a bake fits its budget
Nothing removed the even mesh over a texture's flat parts unless the budget was lowered until simplification had to run. Collapses stay under a thirty-second of the resolution: on the test map 387584 -> 369876 triangles, with the print unchanged (0.02% of the extrusion). An earlier attempt was reverted for a 21% heavier result. That was the colour despeckle switching itself off, not the collapsing: it keyed off the face parent map, which any collapse empties.
This commit is contained in:
@@ -310,12 +310,13 @@ PipelineResult run_pipeline(const TriSoup &input, const HeightSampleFn &sample,
|
|||||||
// triangles to fit, so every bake after the first came out coarser than the one before.
|
// triangles to fit, so every bake after the first came out coarser than the one before.
|
||||||
const size_t target = settings.max_triangles + preserved;
|
const size_t target = settings.max_triangles + preserved;
|
||||||
const bool over_budget = displaced.triangle_count() > target;
|
const bool over_budget = displaced.triangle_count() > target;
|
||||||
// Only when the mesh is actually over budget: the decimation pass also welds the soup and is
|
// Flat faces are harvested whether or not the budget bites. Refinement is driven by the target
|
||||||
// followed by the T-junction repair, and putting an under-budget bake through both changed the
|
// edge length alone, so it leaves as fine a mesh over the flat parts of a texture as over its
|
||||||
// sliced result by a fifth even with the collapse tolerance at zero, i.e. with nothing
|
// detail, and nothing else removes those: under its budget a bake kept every redundant triangle
|
||||||
// collapsed. Harvesting flat faces on a mesh that already fits needs that path to leave the
|
// unless the budget was lowered until decimation had to run. Only collapses costing less than
|
||||||
// geometry alone first.
|
// harvest_tol are taken, so this does not reach the relief.
|
||||||
if (over_budget) {
|
const bool harvest_only = !over_budget && settings.harvest_flat && displaced.triangle_count() > 0;
|
||||||
|
if (over_budget || harvest_only) {
|
||||||
// Colour per face on the fine mesh, so colour boundaries become creases the collapse
|
// Colour per face on the fine mesh, so colour boundaries become creases the collapse
|
||||||
// respects. Excluded (unpainted) faces take no colour.
|
// respects. Excluded (unpainted) faces take no colour.
|
||||||
std::vector<int> face_color;
|
std::vector<int> face_color;
|
||||||
@@ -333,20 +334,23 @@ PipelineResult run_pipeline(const TriSoup &input, const HeightSampleFn &sample,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Harvesting alone is asked for by handing it the count it already has: nothing is then
|
||||||
|
// over the target, so the loop only ever pops collapses under the tolerance.
|
||||||
const size_t before = displaced.triangle_count();
|
const size_t before = displaced.triangle_count();
|
||||||
DecimateResult dec = decimate(displaced, target, settings.harvest_flat,
|
DecimateResult dec = decimate(displaced, over_budget ? target : before, settings.harvest_flat,
|
||||||
settings.harvest_tol, locked,
|
settings.harvest_tol, locked,
|
||||||
[&](double f) { return report("decimate", f); }, face_color);
|
[&](double f) { return report("decimate", f); }, face_color);
|
||||||
result.locked_over_budget = dec.locked_over_budget;
|
result.locked_over_budget = dec.locked_over_budget;
|
||||||
displaced = std::move(dec.geometry);
|
displaced = std::move(dec.geometry);
|
||||||
lap("decimate", displaced, "over budget, simplified");
|
lap("decimate", displaced, over_budget ? "over budget, simplified" : "flat faces harvested");
|
||||||
BOOST_LOG_TRIVIAL(info) << "TextureBake decimate: " << before << " -> " << displaced.triangle_count()
|
BOOST_LOG_TRIVIAL(info) << "TextureBake decimate: " << before << " -> " << displaced.triangle_count()
|
||||||
<< " (budget " << target << ")";
|
<< (over_budget ? " (budget " : " (flat harvest, budget ") << target << ")";
|
||||||
parent.clear(); // no longer meaningful
|
parent.clear(); // no longer meaningful
|
||||||
}
|
}
|
||||||
result.triangles_refined = displaced_before_decimate;
|
result.triangles_refined = displaced_before_decimate;
|
||||||
result.triangles_budget = target;
|
result.triangles_budget = target;
|
||||||
result.budget_limited = over_budget;
|
result.budget_limited = over_budget;
|
||||||
|
result.simplified = over_budget;
|
||||||
if (!report("decimate", 1.0)) {
|
if (!report("decimate", 1.0)) {
|
||||||
result.canceled = true;
|
result.canceled = true;
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ struct PipelineResult
|
|||||||
size_t triangles_refined = 0;
|
size_t triangles_refined = 0;
|
||||||
size_t triangles_budget = 0;
|
size_t triangles_budget = 0;
|
||||||
bool budget_limited = false;
|
bool budget_limited = false;
|
||||||
|
// The budget coarsened the mesh, so its triangles are no longer the fine, even ones the refinement
|
||||||
|
// laid down - they can be as large as the features on them, which a caller that post-processes per
|
||||||
|
// triangle (the colour despeckle) has to know. Harvesting flat faces does not count: what it
|
||||||
|
// removes carried nothing. Not the same question as "did a collapse run", which is why
|
||||||
|
// face_parent_id being empty is no longer used to answer it.
|
||||||
|
bool simplified = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// `debug`, when given and enabled, receives the mesh after every stage that ran - which is the only
|
// `debug`, when given and enabled, receives the mesh after every stage that ran - which is the only
|
||||||
|
|||||||
@@ -2178,6 +2178,12 @@ indexed_triangle_set build_texture_displacement_v2(const indexed_triangle_set
|
|||||||
BOOST_LOG_TRIVIAL(info) << "TextureBake resolution: " << settings.refine_length << " mm"
|
BOOST_LOG_TRIVIAL(info) << "TextureBake resolution: " << settings.refine_length << " mm"
|
||||||
<< (auto_edge ? " (auto)" : "") << ", budget " << settings.max_triangles / 1000 << " k"
|
<< (auto_edge ? " (auto)" : "") << ", budget " << settings.max_triangles / 1000 << " k"
|
||||||
<< (auto_budget ? " (auto)" : "");
|
<< (auto_budget ? " (auto)" : "");
|
||||||
|
// How far a flat-face harvest may move the surface, tied to the resolution: what a bake refined to
|
||||||
|
// 1.4 mm edges can merge flat is not what one refined to 0.1 mm may touch. A thirty-second of the
|
||||||
|
// edge is well under a layer either way - at the default resolution it sheds about 5% of the
|
||||||
|
// triangles on a relief that covers the whole surface, and far more of one with flat ground in it -
|
||||||
|
// and the floor keeps a very fine resolution from spending the pass for nothing.
|
||||||
|
settings.harvest_tol = std::clamp(settings.refine_length / 32.0, 0.005, 0.05);
|
||||||
settings.preserve_untextured = true;
|
settings.preserve_untextured = true;
|
||||||
// Always on: relief driven under the plate is unprintable whichever pipeline produced it, so this
|
// Always on: relief driven under the plate is unprintable whichever pipeline produced it, so this
|
||||||
// is no longer a choice the user has to make. Only geometry that ends up below the model's own
|
// is no longer a choice the user has to make. Only geometry that ends up below the model's own
|
||||||
@@ -2335,7 +2341,9 @@ indexed_triangle_set build_texture_displacement_v2(const indexed_triangle_set
|
|||||||
// noise. A simplified mesh is neither: its triangles are as large as the colour regions
|
// noise. A simplified mesh is neither: its triangles are as large as the colour regions
|
||||||
// themselves and already end on the colour boundaries, so a majority vote among three
|
// themselves and already end on the colour boundaries, so a majority vote among three
|
||||||
// neighbours would repaint whole features. Bake mode (no simplification) keeps it.
|
// neighbours would repaint whole features. Bake mode (no simplification) keeps it.
|
||||||
const bool simplified = result.face_parent_id.empty();
|
// Not "did a collapse run": a flat-face harvest leaves the mesh as fine as it was, and
|
||||||
|
// reading it as simplified switched the despeckle off for every bake that harvested.
|
||||||
|
const bool simplified = result.simplified;
|
||||||
despeckle_triangle_colors(out, palette, simplified ? 0 : color->despeckle_passes);
|
despeckle_triangle_colors(out, palette, simplified ? 0 : color->despeckle_passes);
|
||||||
merge_small_color_regions(out, palette, color->min_color_region_mm2);
|
merge_small_color_regions(out, palette, color->min_color_region_mm2);
|
||||||
for (size_t i = 0; i < out.indices.size(); ++i) {
|
for (size_t i = 0; i < out.indices.size(); ++i) {
|
||||||
|
|||||||
Reference in New Issue
Block a user