mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-23 17:02:39 +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.
|
||||
const size_t target = settings.max_triangles + preserved;
|
||||
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
|
||||
// followed by the T-junction repair, and putting an under-budget bake through both changed the
|
||||
// sliced result by a fifth even with the collapse tolerance at zero, i.e. with nothing
|
||||
// collapsed. Harvesting flat faces on a mesh that already fits needs that path to leave the
|
||||
// geometry alone first.
|
||||
if (over_budget) {
|
||||
// Flat faces are harvested whether or not the budget bites. Refinement is driven by the target
|
||||
// edge length alone, so it leaves as fine a mesh over the flat parts of a texture as over its
|
||||
// detail, and nothing else removes those: under its budget a bake kept every redundant triangle
|
||||
// unless the budget was lowered until decimation had to run. Only collapses costing less than
|
||||
// harvest_tol are taken, so this does not reach the relief.
|
||||
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
|
||||
// respects. Excluded (unpainted) faces take no colour.
|
||||
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();
|
||||
DecimateResult dec = decimate(displaced, target, settings.harvest_flat,
|
||||
DecimateResult dec = decimate(displaced, over_budget ? target : before, settings.harvest_flat,
|
||||
settings.harvest_tol, locked,
|
||||
[&](double f) { return report("decimate", f); }, face_color);
|
||||
result.locked_over_budget = dec.locked_over_budget;
|
||||
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()
|
||||
<< " (budget " << target << ")";
|
||||
<< (over_budget ? " (budget " : " (flat harvest, budget ") << target << ")";
|
||||
parent.clear(); // no longer meaningful
|
||||
}
|
||||
result.triangles_refined = displaced_before_decimate;
|
||||
result.triangles_budget = target;
|
||||
result.budget_limited = over_budget;
|
||||
result.simplified = over_budget;
|
||||
if (!report("decimate", 1.0)) {
|
||||
result.canceled = true;
|
||||
return result;
|
||||
|
||||
@@ -115,6 +115,12 @@ struct PipelineResult
|
||||
size_t triangles_refined = 0;
|
||||
size_t triangles_budget = 0;
|
||||
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
|
||||
|
||||
@@ -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"
|
||||
<< (auto_edge ? " (auto)" : "") << ", budget " << settings.max_triangles / 1000 << " k"
|
||||
<< (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;
|
||||
// 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
|
||||
@@ -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
|
||||
// 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.
|
||||
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);
|
||||
merge_small_color_regions(out, palette, color->min_color_region_mm2);
|
||||
for (size_t i = 0; i < out.indices.size(); ++i) {
|
||||
|
||||
Reference in New Issue
Block a user