diff --git a/src/libslic3r/ColorSolver.cpp b/src/libslic3r/ColorSolver.cpp index e02db3e28aa..4e0dea54d34 100644 --- a/src/libslic3r/ColorSolver.cpp +++ b/src/libslic3r/ColorSolver.cpp @@ -670,7 +670,7 @@ std::array mix_ordered_stack_with_buffers(const std::vector{ { 0.f, 0.f, 0.f } } : colors_with_background.back(); if (td_effective_alpha_correction) - return mix_ordered_stack_td_effective_alpha(colors_with_background, surface_to_deep, layer_opacities, surface_scatter, component_roles); + return mix_ordered_stack_td_effective_alpha(colors_with_background, surface_to_deep, layer_opacities, 0.f, component_roles); if (beer_lambert_rgb_correction) return mix_ordered_stack_beer_lambert_rgb(colors_with_background, surface_to_deep, layer_opacities, surface_scatter); @@ -1273,7 +1273,9 @@ std::string color_solver_ordered_stack_candidate_cache_key(const std::vectorsecond; } -std::vector solve_color_solver_ordered_stack_for_target( +ColorSolverOrderedStackResult solve_color_solver_ordered_stack_result_for_target( const ColorSolverOrderedStackCandidateSet &candidates, const std::array &target_rgb, ColorSolverMode solver_mode) { + ColorSolverOrderedStackResult result; + if (candidates.empty()) - return {}; + return result; const size_t candidate_count = candidates.rgbs.size() / 3; ColorSolverNearestResult nearest = @@ -1497,13 +1501,34 @@ std::vector solve_color_solver_ordered_stack_for_target( if (nearest.best_idx >= candidate_count && color_solver_mode_is_perceptual(solver_mode)) nearest = nearest_color_solver_candidates(candidates, target_rgb); if (nearest.best_idx >= candidate_count) - return {}; + return result; const size_t stack_begin = nearest.best_idx * size_t(candidates.stack_depth); if (stack_begin + size_t(candidates.stack_depth) > candidates.stacks.size()) - return {}; - return std::vector(candidates.stacks.begin() + stack_begin, - candidates.stacks.begin() + stack_begin + candidates.stack_depth); + return result; + + result.surface_to_deep = std::vector(candidates.stacks.begin() + stack_begin, + candidates.stacks.begin() + stack_begin + candidates.stack_depth); + + const size_t rgb_begin = nearest.best_idx * 3; + if (rgb_begin + 2 < candidates.rgbs.size()) { + result.rgb = { { + candidates.rgbs[rgb_begin + 0], + candidates.rgbs[rgb_begin + 1], + candidates.rgbs[rgb_begin + 2], + } }; + result.has_rgb = true; + } + + return result; +} + +std::vector solve_color_solver_ordered_stack_for_target( + const ColorSolverOrderedStackCandidateSet &candidates, + const std::array &target_rgb, + ColorSolverMode solver_mode) +{ + return solve_color_solver_ordered_stack_result_for_target(candidates, target_rgb, solver_mode).surface_to_deep; } } // namespace Slic3r diff --git a/src/libslic3r/ColorSolver.hpp b/src/libslic3r/ColorSolver.hpp index af1bcf8aec7..b5d843a01ad 100644 --- a/src/libslic3r/ColorSolver.hpp +++ b/src/libslic3r/ColorSolver.hpp @@ -102,6 +102,12 @@ struct ColorSolverOrderedStackCandidateSet { } }; +struct ColorSolverOrderedStackResult { + std::vector surface_to_deep; + std::array rgb { { 0.f, 0.f, 0.f } }; + bool has_rgb { false }; +}; + using ColorSolverOrderedStackCandidateCache = std::map; ColorSolverMixModel color_solver_mix_model_from_index(int model); @@ -185,6 +191,10 @@ const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates bool td_effective_alpha_correction = false, const std::vector &component_roles = {}, bool beam_search_stack_expansion = false); +ColorSolverOrderedStackResult solve_color_solver_ordered_stack_result_for_target( + const ColorSolverOrderedStackCandidateSet &candidates, + const std::array &target_rgb, + ColorSolverMode solver_mode); std::vector solve_color_solver_ordered_stack_for_target( const ColorSolverOrderedStackCandidateSet &candidates, const std::array &target_rgb, diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 0ca83da5026..45227fe5fdb 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -44,6 +44,7 @@ #include "libslic3r.h" #include +#include #include #include #include @@ -2004,7 +2005,14 @@ struct TopSurfaceImageContoningAnchoredSurfacePlan { std::vector regions; }; -class TopSurfaceImageContoningAnchoredDepthWork +class TopSurfaceImageContoningAnchoredWork +{ +public: + virtual ~TopSurfaceImageContoningAnchoredWork() = default; + virtual bool run_one() = 0; +}; + +class TopSurfaceImageContoningAnchoredDepthWork : public TopSurfaceImageContoningAnchoredWork { public: using BuildFn = std::function(int)>; @@ -2021,7 +2029,7 @@ public: , m_progress(std::move(progress)) {} - bool run_one() + bool run_one() override { int depth = -1; { @@ -2081,41 +2089,112 @@ private: std::exception_ptr m_error; }; +class TopSurfaceImageContoningAnchoredIndexWork : public TopSurfaceImageContoningAnchoredWork +{ +public: + using RunFn = std::function; + using ProgressFn = std::function; + + TopSurfaceImageContoningAnchoredIndexWork(size_t count, RunFn run, ProgressFn progress) + : m_count(count) + , m_run(std::move(run)) + , m_progress(std::move(progress)) + { + m_done = m_count == 0; + } + + bool run_one() override + { + size_t idx = 0; + { + std::lock_guard lock(m_mutex); + if (m_error || m_next >= m_count) + return false; + idx = m_next++; + ++m_active; + } + + std::exception_ptr error; + try { + m_run(idx); + } catch (...) { + error = std::current_exception(); + } + + size_t completed = 0; + bool done = false; + { + std::lock_guard lock(m_mutex); + if (error && !m_error) + m_error = error; + --m_active; + completed = ++m_completed; + done = (m_error || m_next >= m_count) && m_active == 0; + m_done = m_done || done; + } + if (done) + m_cv.notify_all(); + if (!error && m_progress) + m_progress(completed); + return true; + } + + void wait() + { + std::unique_lock lock(m_mutex); + m_cv.wait(lock, [this]() { return m_done; }); + if (m_error) + std::rethrow_exception(m_error); + } + +private: + std::mutex m_mutex; + std::condition_variable m_cv; + size_t m_count { 0 }; + RunFn m_run; + ProgressFn m_progress; + size_t m_next { 0 }; + int m_active { 0 }; + size_t m_completed { 0 }; + bool m_done { false }; + std::exception_ptr m_error; +}; + class TopSurfaceImageContoningAnchoredSurfaceBuildState { public: - void set_depth_work(std::shared_ptr work) + void set_work(std::shared_ptr work) { { std::lock_guard lock(m_mutex); if (!m_finished) - m_depth_work = std::move(work); + m_work = std::move(work); } m_cv.notify_all(); } - void clear_depth_work(const std::shared_ptr &work) + void clear_work(const std::shared_ptr &work) { { std::lock_guard lock(m_mutex); - if (m_depth_work == work) - m_depth_work.reset(); + if (m_work == work) + m_work.reset(); } m_cv.notify_all(); } bool help_one() { - std::shared_ptr work; + std::shared_ptr work; { std::unique_lock lock(m_mutex); - if (!m_finished && !m_depth_work) + if (!m_finished && !m_work) m_cv.wait_for(lock, std::chrono::milliseconds(2), [this]() { - return m_finished || m_depth_work != nullptr; + return m_finished || m_work != nullptr; }); - if (m_finished || !m_depth_work) + if (m_finished || !m_work) return false; - work = m_depth_work; + work = m_work; } return work->run_one(); } @@ -2125,7 +2204,7 @@ public: { std::lock_guard lock(m_mutex); m_finished = true; - m_depth_work.reset(); + m_work.reset(); } m_cv.notify_all(); } @@ -2133,7 +2212,7 @@ public: private: std::mutex m_mutex; std::condition_variable m_cv; - std::shared_ptr m_depth_work; + std::shared_ptr m_work; bool m_finished { false }; }; @@ -3995,6 +4074,53 @@ static std::optional top_surface_image_conto return out; } +static std::optional top_surface_image_contoning_label_for_stack( + const TextureMappingContoningStack &stack, + const TextureMappingContoningSolver &solver, + bool lower_surface, + int visible_layers, + std::vector &labels, + std::map, int>, int> &label_by_stack) +{ + if (stack.bottom_to_top.empty()) + return std::nullopt; + const auto label_key = std::make_pair(stack.bottom_to_top, std::max(0, visible_layers)); + auto label_it = label_by_stack.find(label_key); + int label = -1; + std::optional> stack_rgb; + if (label_it != label_by_stack.end()) { + label = label_it->second; + if (label >= 0 && label < int(labels.size())) + stack_rgb = labels[size_t(label)].rgb; + else { + label_by_stack.erase(label_it); + label = -1; + } + } + if (!stack_rgb) { + if (stack.rgb) + stack_rgb = stack.rgb; + else + stack_rgb = solver.stack_rgb(stack.bottom_to_top, lower_surface, visible_layers); + if (!stack_rgb) + return std::nullopt; + + TopSurfaceImageContoningVectorLabel label_data; + label_data.bottom_to_top = stack.bottom_to_top; + label_data.rgb = *stack_rgb; + label_data.oklab = color_solver_oklab_from_srgb(*stack_rgb); + label_data.valid_depth = std::max(visible_layers, int(stack.bottom_to_top.size())); + label_data.repeat_allowed = visible_layers > int(stack.bottom_to_top.size()); + label = int(labels.size()); + labels.emplace_back(std::move(label_data)); + label_by_stack.emplace(label_key, label); + } + TopSurfaceImageContoningSolvedLabel out; + out.label = label; + out.rgb = *stack_rgb; + return out; +} + static std::optional top_surface_image_contoning_solve_label( const std::array &rgb, int solve_layers, @@ -4005,32 +4131,7 @@ static std::optional top_surface_image_cont std::map, int>, int> &label_by_stack) { TextureMappingContoningStack stack = solver.solve(rgb, solve_layers, lower_surface, visible_layers); - if (stack.bottom_to_top.empty()) - return std::nullopt; - std::optional> stack_rgb = - solver.stack_rgb(stack.bottom_to_top, lower_surface, visible_layers); - if (!stack_rgb) - return std::nullopt; - const auto label_key = std::make_pair(stack.bottom_to_top, std::max(0, visible_layers)); - auto label_it = label_by_stack.find(label_key); - int label = -1; - if (label_it == label_by_stack.end()) { - TopSurfaceImageContoningVectorLabel label_data; - label_data.bottom_to_top = stack.bottom_to_top; - label_data.rgb = *stack_rgb; - label_data.oklab = color_solver_oklab_from_srgb(*stack_rgb); - label_data.valid_depth = std::max(visible_layers, int(stack.bottom_to_top.size())); - label_data.repeat_allowed = visible_layers > int(stack.bottom_to_top.size()); - label = int(labels.size()); - labels.emplace_back(std::move(label_data)); - label_by_stack.emplace(label_key, label); - } else { - label = label_it->second; - } - TopSurfaceImageContoningSolvedLabel out; - out.label = label; - out.rgb = *stack_rgb; - return out; + return top_surface_image_contoning_label_for_stack(stack, solver, lower_surface, visible_layers, labels, label_by_stack); } static void top_surface_image_contoning_resolve_merged_grid_regions( @@ -4263,19 +4364,20 @@ static void top_surface_image_contoning_solve_anchored_region( const int rows = std::max(0, int(std::ceil(double(bbox.max.y() - min_y) / double(step)))); if (cols <= 0 || rows <= 0) return; + const size_t grid_cells = size_t(cols) * size_t(rows); + const int sampling_progress_total = int(std::min(grid_cells, size_t(std::numeric_limits::max()))); top_surface_image_contoning_report_anchored_progress(object, source_layer, source_surface, L("sampling"), 0, - source_context.stack_layers); + sampling_progress_total); std::vector grid(size_t(cols) * size_t(rows), -1); std::vector labels; std::map, int>, int> label_by_stack; - const size_t grid_cells = size_t(cols) * size_t(rows); const int debug_stride = debug_enabled ? std::max(1, int(std::ceil(std::sqrt(double(grid_cells) / 100000.0)))) : 0; @@ -4289,16 +4391,18 @@ static void top_surface_image_contoning_solve_anchored_region( true); } - auto solve_cell = [&](int row, int col, const std::array &target_rgb, int solve_layers, int available_depth) { + const bool lower_surface = + source_surface == TopSurfaceImageSourceSurface::Bottom && + plan.contoning_td_adjustment_enabled; + + auto label_cell = [&](int row, int col, const TextureMappingContoningStack &stack, int available_depth) { std::optional solved = - top_surface_image_contoning_solve_label(target_rgb, - solve_layers, - available_depth, - solver, - source_surface == TopSurfaceImageSourceSurface::Bottom && - plan.contoning_td_adjustment_enabled, - labels, - label_by_stack); + top_surface_image_contoning_label_for_stack(stack, + solver, + lower_surface, + available_depth, + labels, + label_by_stack); if (!solved) return; grid[size_t(row * cols + col)] = solved->label; @@ -4329,42 +4433,90 @@ static void top_surface_image_contoning_solve_anchored_region( std::vector> cell_samples(grid.size()); std::vector cell_available_depths(grid.size(), 0); - size_t debug_sampled_cell_count = 0; + std::vector cell_stacks(grid.size()); + std::atomic debug_sampled_cell_count { 0 }; + std::mutex debug_sample_area_mutex; const auto debug_sampling_start = top_surface_image_debug_now(); - for (int row = 0; row < rows; ++row) { - if ((row & 15) == 0) + auto solve_sampled_cell = [&](size_t grid_idx) { + const int row = int(grid_idx / size_t(cols)); + const int col = int(grid_idx - size_t(row) * size_t(cols)); + if ((row & 15) == 0 && col == 0) check_canceled(throw_if_canceled); - for (int col = 0; col < cols; ++col) { - const std::optional sample = sample_cell(row, col); - if (!sample) - continue; - const size_t grid_idx = size_t(row * cols + col); - cell_samples[grid_idx] = sample; - cell_available_depths[grid_idx] = sample->available_depth; - ++debug_sampled_cell_count; - solve_cell(row, col, sample->rgb, sample->solve_layers, sample->available_depth); - if (debug_stride > 0 && - row % debug_stride == 0 && - col % debug_stride == 0) { - const coord_t x0 = min_x + coord_t(col) * step; - const coord_t y0 = min_y + coord_t(row) * step; - const coord_t x1 = std::min(x0 + coord_t(debug_stride) * step, bbox.max.x()); - const coord_t y1 = std::min(y0 + coord_t(debug_stride) * step, bbox.max.y()); - if (x1 > x0 && y1 > y0) { - TopSurfaceImageContoningDebugSampleArea debug_area; - debug_area.rgb = sample->rgb; - debug_area.area.emplace_back(top_surface_image_cell_expolygon(x0, y0, x1, y1)); + const std::optional sample = sample_cell(row, col); + if (!sample) + return; + cell_samples[grid_idx] = sample; + cell_available_depths[grid_idx] = sample->available_depth; + ++debug_sampled_cell_count; + cell_stacks[grid_idx] = solver.solve(sample->rgb, sample->solve_layers, lower_surface, sample->available_depth); + if (debug_stride > 0 && + row % debug_stride == 0 && + col % debug_stride == 0) { + const coord_t x0 = min_x + coord_t(col) * step; + const coord_t y0 = min_y + coord_t(row) * step; + const coord_t x1 = std::min(x0 + coord_t(debug_stride) * step, bbox.max.x()); + const coord_t y1 = std::min(y0 + coord_t(debug_stride) * step, bbox.max.y()); + if (x1 > x0 && y1 > y0) { + TopSurfaceImageContoningDebugSampleArea debug_area; + debug_area.rgb = sample->rgb; + debug_area.area.emplace_back(top_surface_image_cell_expolygon(x0, y0, x1, y1)); + if (debug_enabled) { + std::lock_guard lock(debug_sample_area_mutex); anchored_region.debug_sample_areas.emplace_back(std::move(debug_area)); } } } + }; + + auto report_sampling_progress = [&](size_t completed) { + if (completed != grid_cells && (completed & 4095) != 0) + return; + const int current = int(std::min(completed, size_t(sampling_progress_total))); + top_surface_image_contoning_report_anchored_progress(object, + source_layer, + source_surface, + L("sampling"), + current, + sampling_progress_total); + }; + + std::shared_ptr sample_work = + std::make_shared(grid_cells, + solve_sampled_cell, + report_sampling_progress); + if (build_state != nullptr) + build_state->set_work(sample_work); + try { + tbb::parallel_for(tbb::blocked_range(0, grid_cells, 32), + [&](const tbb::blocked_range &range) { + for (size_t idx = range.begin(); idx != range.end(); ++idx) + sample_work->run_one(); + }); + sample_work->wait(); + } catch (...) { + if (build_state != nullptr) + build_state->clear_work(sample_work); + throw; + } + if (build_state != nullptr) + build_state->clear_work(sample_work); + + for (int row = 0; row < rows; ++row) { + if ((row & 15) == 0) + check_canceled(throw_if_canceled); + for (int col = 0; col < cols; ++col) { + const size_t grid_idx = size_t(row * cols + col); + if (!cell_samples[grid_idx]) + continue; + label_cell(row, col, cell_stacks[grid_idx], cell_samples[grid_idx]->available_depth); + } } if (debug_enabled) { - debug_timing.sampled_cell_count = debug_sampled_cell_count; + debug_timing.sampled_cell_count = debug_sampled_cell_count.load(); top_surface_image_debug_accumulate_timing_step(debug_timing.steps, "sample_and_solve_cells", top_surface_image_debug_elapsed_ms(debug_sampling_start), - debug_sampled_cell_count, + debug_sampled_cell_count.load(), true); } @@ -4540,7 +4692,7 @@ static void top_surface_image_contoning_solve_anchored_region( build_depth_regions, store_depth_regions, report_progress); - build_state->set_depth_work(depth_work); + build_state->set_work(depth_work); try { tbb::parallel_for(tbb::blocked_range(0, active_depths.size(), 1), [&](const tbb::blocked_range &range) { @@ -4549,10 +4701,10 @@ static void top_surface_image_contoning_solve_anchored_region( }); depth_work->wait(); } catch (...) { - build_state->clear_depth_work(depth_work); + build_state->clear_work(depth_work); throw; } - build_state->clear_depth_work(depth_work); + build_state->clear_work(depth_work); } else { std::atomic completed_depths { 0 }; tbb::parallel_for(tbb::blocked_range(0, active_depths.size(), 1), @@ -6124,10 +6276,10 @@ static std::vector top_surface_image_region_plans( plan.contoning_beam_search_stack_expansion_enabled = zone->effective_top_surface_contoning_beam_search_stack_expansion_enabled(); plan.contoning_td_adjustment_enabled = zone->top_surface_contoning_td_adjustment_enabled; - plan.contoning_surface_scatter_enabled = - plan.contoning_td_adjustment_enabled && zone->top_surface_contoning_surface_scatter_enabled; plan.contoning_td_effective_alpha_correction_enabled = plan.contoning_td_adjustment_enabled && zone->top_surface_contoning_td_effective_alpha_correction_enabled; + plan.contoning_surface_scatter_enabled = + zone->effective_top_surface_contoning_surface_scatter_enabled(); plan.contoning_beer_lambert_rgb_correction_enabled = plan.contoning_td_adjustment_enabled && !plan.contoning_td_effective_alpha_correction_enabled && diff --git a/src/libslic3r/TextureMapping.cpp b/src/libslic3r/TextureMapping.cpp index 98f7ab057d4..6898953722e 100644 --- a/src/libslic3r/TextureMapping.cpp +++ b/src/libslic3r/TextureMapping.cpp @@ -1182,7 +1182,7 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const effective_top_surface_contoning_surface_anchored_stack_optimizations_enabled() == rhs.effective_top_surface_contoning_surface_anchored_stack_optimizations_enabled() && top_surface_contoning_td_adjustment_enabled == rhs.top_surface_contoning_td_adjustment_enabled && - top_surface_contoning_surface_scatter_enabled == rhs.top_surface_contoning_surface_scatter_enabled && + effective_top_surface_contoning_surface_scatter_enabled() == rhs.effective_top_surface_contoning_surface_scatter_enabled() && top_surface_contoning_beer_lambert_rgb_correction_enabled == rhs.top_surface_contoning_beer_lambert_rgb_correction_enabled && top_surface_contoning_td_effective_alpha_correction_enabled == rhs.top_surface_contoning_td_effective_alpha_correction_enabled && effective_top_surface_contoning_beam_search_stack_expansion_enabled() == rhs.effective_top_surface_contoning_beam_search_stack_expansion_enabled() && @@ -1595,7 +1595,7 @@ std::string TextureMappingManager::serialize_entries() texture["top_surface_contoning_td_adjustment_enabled"] = zone.top_surface_contoning_td_adjustment_enabled; texture["top_surface_contoning_surface_scatter_enabled"] = - zone.top_surface_contoning_surface_scatter_enabled; + zone.effective_top_surface_contoning_surface_scatter_enabled(); texture["top_surface_contoning_beer_lambert_rgb_correction_enabled"] = zone.top_surface_contoning_beer_lambert_rgb_correction_enabled; texture["top_surface_contoning_td_effective_alpha_correction_enabled"] = diff --git a/src/libslic3r/TextureMapping.hpp b/src/libslic3r/TextureMapping.hpp index 9d6365dcc70..b0aa5dad6b0 100644 --- a/src/libslic3r/TextureMapping.hpp +++ b/src/libslic3r/TextureMapping.hpp @@ -322,6 +322,13 @@ struct TextureMappingZone return ShowExperimentalTopSurfaceContoningOptions && value; } + static bool effective_top_surface_contoning_surface_scatter_enabled(bool td_adjustment, + bool surface_scatter, + bool td_effective_alpha) + { + return td_adjustment && surface_scatter && !td_effective_alpha; + } + static bool effective_top_surface_contoning_layer_phase_enabled(bool value, bool surface_anchored_stacks) { return effective_top_surface_contoning_layer_phase_enabled(value) && @@ -574,6 +581,14 @@ struct TextureMappingZone top_surface_contoning_supersampled_cells_enabled); } + bool effective_top_surface_contoning_surface_scatter_enabled() const + { + return TextureMappingZone::effective_top_surface_contoning_surface_scatter_enabled( + top_surface_contoning_td_adjustment_enabled, + top_surface_contoning_surface_scatter_enabled, + top_surface_contoning_td_effective_alpha_correction_enabled); + } + void apply_top_surface_contoning_experimental_defaults() { if (top_surface_image_printing_enabled && @@ -602,6 +617,8 @@ struct TextureMappingZone top_surface_contoning_layer_phase_enabled = false; top_surface_contoning_blue_noise_error_diffusion_enabled = false; } + if (top_surface_contoning_td_effective_alpha_correction_enabled) + top_surface_contoning_surface_scatter_enabled = false; } void apply_default_modulation_mode() diff --git a/src/libslic3r/TextureMappingContoning.cpp b/src/libslic3r/TextureMappingContoning.cpp index a154c1f0bf4..01dc1ef288c 100644 --- a/src/libslic3r/TextureMappingContoning.cpp +++ b/src/libslic3r/TextureMappingContoning.cpp @@ -417,8 +417,7 @@ TextureMappingContoningSolver::TextureMappingContoningSolver(const TextureMappin m_layer_height_mm = std::isfinite(layer_height_mm) && layer_height_mm > 0.f ? layer_height_mm : 0.2f; if (!std::isfinite(m_layer_height_mm) || m_layer_height_mm <= 0.f) m_layer_height_mm = 0.2f; - m_surface_scatter = - m_td_adjustment_enabled && zone.top_surface_contoning_surface_scatter_enabled ? CONTONING_SURFACE_SCATTER : 0.f; + m_surface_scatter = zone.effective_top_surface_contoning_surface_scatter_enabled() ? CONTONING_SURFACE_SCATTER : 0.f; component_ids.erase(std::remove_if(component_ids.begin(), component_ids.end(), [&config](unsigned int id) { return id == 0 || id > config.filament_colour.values.size(); @@ -450,6 +449,7 @@ TextureMappingContoningSolver::candidates_for_depth(int stack_layers) const const int depth = std::clamp(stack_layers, TextureMappingZone::MinTopSurfaceContoningStackLayers, TextureMappingZone::MaxTopSurfaceContoningStackLayers); + std::lock_guard lock(*m_candidate_mutex); auto found = m_candidates_by_depth.find(depth); if (found != m_candidates_by_depth.end()) return found->second; @@ -656,8 +656,9 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr m_component_roles, m_beam_search_stack_expansion_enabled); } - const std::vector surface_to_deep = - solve_color_solver_ordered_stack_for_target(*ordered_candidates, target_rgb, ColorSolverMode::OklabSoftCap4Dark4); + const ColorSolverOrderedStackResult solved = + solve_color_solver_ordered_stack_result_for_target(*ordered_candidates, target_rgb, ColorSolverMode::OklabSoftCap4Dark4); + const std::vector &surface_to_deep = solved.surface_to_deep; if (!surface_to_deep.empty()) { out.bottom_to_top.reserve(surface_to_deep.size()); auto append_component = [this, &out](uint16_t component_idx) { @@ -671,8 +672,11 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr for (auto it = surface_to_deep.rbegin(); it != surface_to_deep.rend(); ++it) append_component(*it); } - if (!out.bottom_to_top.empty()) + if (!out.bottom_to_top.empty()) { + if (solved.has_rgb) + out.rgb = solved.rgb; return out; + } } } diff --git a/src/libslic3r/TextureMappingContoning.hpp b/src/libslic3r/TextureMappingContoning.hpp index 6acc83f6c1d..c6c62790fd7 100644 --- a/src/libslic3r/TextureMappingContoning.hpp +++ b/src/libslic3r/TextureMappingContoning.hpp @@ -20,6 +20,7 @@ class PrintConfig; struct TextureMappingContoningStack { std::vector bottom_to_top; + std::optional> rgb; }; class TextureMappingContoningSolver @@ -73,6 +74,7 @@ private: bool m_beam_search_stack_expansion_enabled { false }; std::vector m_component_roles; mutable std::map> m_candidates_by_depth; + mutable std::shared_ptr m_candidate_mutex { std::make_shared() }; mutable std::shared_ptr m_ordered_candidate_cache { std::make_shared() }; mutable std::shared_ptr m_ordered_candidate_cache_mutex { std::make_shared() }; }; diff --git a/src/slic3r/GUI/MMUPaintedTexturePreview.cpp b/src/slic3r/GUI/MMUPaintedTexturePreview.cpp index 19248c12d98..22beb9f72c9 100644 --- a/src/slic3r/GUI/MMUPaintedTexturePreview.cpp +++ b/src/slic3r/GUI/MMUPaintedTexturePreview.cpp @@ -2773,8 +2773,7 @@ std::optional texture_preview_simulation_setti settings.contoning_flat_surface_beam_search_stack_expansion = zone->effective_top_surface_contoning_beam_search_stack_expansion_enabled(); settings.contoning_flat_surface_surface_scatter = - settings.contoning_flat_surface_td_adjustment && - zone->top_surface_contoning_surface_scatter_enabled ? + zone->effective_top_surface_contoning_surface_scatter_enabled() ? k_contoning_preview_surface_scatter : 0.f; } @@ -5798,7 +5797,7 @@ static size_t texture_preview_settings_signature_impl(size_t num_physical, signature_mix(std::hash{}(zone.top_surface_contoning_pattern_filaments)); signature_mix(std::hash{}(zone.top_surface_contoning_color_lower_surfaces ? 1 : 0)); signature_mix(std::hash{}(zone.top_surface_contoning_td_adjustment_enabled ? 1 : 0)); - signature_mix(std::hash{}(zone.top_surface_contoning_surface_scatter_enabled ? 1 : 0)); + signature_mix(std::hash{}(zone.effective_top_surface_contoning_surface_scatter_enabled() ? 1 : 0)); signature_mix(std::hash{}(zone.top_surface_contoning_beer_lambert_rgb_correction_enabled ? 1 : 0)); signature_mix(std::hash{}(zone.top_surface_contoning_td_effective_alpha_correction_enabled ? 1 : 0)); signature_mix(std::hash{}(zone.effective_top_surface_contoning_beam_search_stack_expansion_enabled() ? 1 : 0)); @@ -5955,7 +5954,7 @@ static void texture_preview_mix_zone_baked_model_settings(size_t &signature, signature_mix(std::hash{}(zone.top_surface_contoning_pattern_filaments)); signature_mix(std::hash{}(zone.top_surface_contoning_color_lower_surfaces ? 1 : 0)); signature_mix(std::hash{}(zone.top_surface_contoning_td_adjustment_enabled ? 1 : 0)); - signature_mix(std::hash{}(zone.top_surface_contoning_surface_scatter_enabled ? 1 : 0)); + signature_mix(std::hash{}(zone.effective_top_surface_contoning_surface_scatter_enabled() ? 1 : 0)); signature_mix(std::hash{}(zone.top_surface_contoning_beer_lambert_rgb_correction_enabled ? 1 : 0)); signature_mix(std::hash{}(zone.top_surface_contoning_td_effective_alpha_correction_enabled ? 1 : 0)); signature_mix(std::hash{}(zone.effective_top_surface_contoning_beam_search_stack_expansion_enabled() ? 1 : 0)); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8c46046bed9..373a00ec170 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2852,7 +2852,11 @@ public: gap / 2); m_top_surface_contoning_surface_scatter_checkbox = new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Surface scatter correction")); - m_top_surface_contoning_surface_scatter_checkbox->SetValue(top_surface_contoning_surface_scatter_enabled); + m_top_surface_contoning_surface_scatter_checkbox->SetValue( + TextureMappingZone::effective_top_surface_contoning_surface_scatter_enabled( + top_surface_contoning_td_adjustment_enabled, + top_surface_contoning_surface_scatter_enabled, + top_surface_contoning_td_effective_alpha_correction_enabled)); m_top_surface_contoning_surface_scatter_checkbox->SetMinSize( wxSize(-1, std::max(m_top_surface_contoning_surface_scatter_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); contoning_checkboxes_root->Add(m_top_surface_contoning_surface_scatter_checkbox, @@ -3628,9 +3632,12 @@ public: } bool top_surface_contoning_surface_scatter_enabled() const { - return m_top_surface_contoning_surface_scatter_checkbox == nullptr ? - TextureMappingZone::DefaultTopSurfaceContoningSurfaceScatterEnabled : - m_top_surface_contoning_surface_scatter_checkbox->GetValue(); + return TextureMappingZone::effective_top_surface_contoning_surface_scatter_enabled( + top_surface_contoning_td_adjustment_enabled(), + m_top_surface_contoning_surface_scatter_checkbox == nullptr ? + TextureMappingZone::DefaultTopSurfaceContoningSurfaceScatterEnabled : + m_top_surface_contoning_surface_scatter_checkbox->GetValue(), + top_surface_contoning_td_effective_alpha_correction_enabled()); } bool top_surface_contoning_beer_lambert_rgb_correction_enabled() const { @@ -4440,8 +4447,14 @@ private: contoning && m_top_surface_contoning_td_adjustment_checkbox != nullptr && m_top_surface_contoning_td_adjustment_checkbox->GetValue(); + const bool td_effective_alpha = + td_adjustment && + m_top_surface_contoning_td_effective_alpha_correction_checkbox != nullptr && + m_top_surface_contoning_td_effective_alpha_correction_checkbox->GetValue(); m_top_surface_contoning_surface_scatter_checkbox->Show(contoning); - m_top_surface_contoning_surface_scatter_checkbox->Enable(td_adjustment); + m_top_surface_contoning_surface_scatter_checkbox->Enable(td_adjustment && !td_effective_alpha); + if (td_effective_alpha && m_top_surface_contoning_surface_scatter_checkbox->GetValue()) + m_top_surface_contoning_surface_scatter_checkbox->SetValue(false); } if (m_top_surface_contoning_beer_lambert_rgb_correction_checkbox != nullptr) { const bool td_adjustment =