diff --git a/src/libslic3r/ColorSolver.cpp b/src/libslic3r/ColorSolver.cpp index 4e0dea54d34..21b2bca50cf 100644 --- a/src/libslic3r/ColorSolver.cpp +++ b/src/libslic3r/ColorSolver.cpp @@ -553,10 +553,28 @@ std::array td_effective_alpha_transmission(const std::array return transmission_from_density_bias(td_effective_alpha_density_bias(srgb_color, role), scalar_transmission); } +float ordered_stack_layer_opacity(const std::vector &layer_opacities, + const std::vector &layer_opacities_by_depth, + size_t component_count, + size_t depth_idx, + uint16_t component_idx) +{ + const size_t component = size_t(component_idx); + const size_t depth_opacity_idx = depth_idx * component_count + component; + if (component_count > 0 && + depth_opacity_idx < layer_opacities_by_depth.size() && + std::isfinite(layer_opacities_by_depth[depth_opacity_idx])) + return std::clamp(layer_opacities_by_depth[depth_opacity_idx], 1e-4f, 0.9999f); + return component < layer_opacities.size() && std::isfinite(layer_opacities[component]) ? + std::clamp(layer_opacities[component], 1e-4f, 0.9999f) : + 0.5f; +} + std::array mix_ordered_stack_beer_lambert_rgb(const std::vector> &colors_with_background, const std::vector &surface_to_deep, const std::vector &layer_opacities, - float surface_scatter) + float surface_scatter, + const std::vector &layer_opacities_by_depth) { if (colors_with_background.empty() || surface_to_deep.empty()) return colors_with_background.empty() ? std::array{ { 0.f, 0.f, 0.f } } : colors_with_background.back(); @@ -567,13 +585,15 @@ std::array mix_ordered_stack_beer_lambert_rgb(const std::vector= component_count) continue; - const float opacity = - size_t(component_idx) < layer_opacities.size() && std::isfinite(layer_opacities[size_t(component_idx)]) ? - std::clamp(layer_opacities[size_t(component_idx)], 1e-4f, 0.9999f) : - 0.5f; + const float opacity = ordered_stack_layer_opacity(layer_opacities, + layer_opacities_by_depth, + component_count, + depth_idx, + component_idx); std::array transmission = beer_lambert_rgb_transmission(colors_with_background[size_t(component_idx)], 1.f - opacity); if (surface_layer) { @@ -606,7 +626,8 @@ std::array mix_ordered_stack_td_effective_alpha( const std::vector &surface_to_deep, const std::vector &layer_opacities, float surface_scatter, - const std::vector &component_roles) + const std::vector &component_roles, + const std::vector &layer_opacities_by_depth) { if (colors_with_background.empty() || surface_to_deep.empty()) return colors_with_background.empty() ? std::array{ { 0.f, 0.f, 0.f } } : colors_with_background.back(); @@ -617,13 +638,15 @@ std::array mix_ordered_stack_td_effective_alpha( bool surface_layer = true; const float safe_surface_scatter = std::clamp(std::isfinite(surface_scatter) ? surface_scatter : 0.f, 0.f, 0.5f); - for (uint16_t component_idx : surface_to_deep) { + for (size_t depth_idx = 0; depth_idx < surface_to_deep.size(); ++depth_idx) { + const uint16_t component_idx = surface_to_deep[depth_idx]; if (size_t(component_idx) >= component_count) continue; - const float opacity = - size_t(component_idx) < layer_opacities.size() && std::isfinite(layer_opacities[size_t(component_idx)]) ? - std::clamp(layer_opacities[size_t(component_idx)], 1e-4f, 0.9999f) : - 0.5f; + const float opacity = ordered_stack_layer_opacity(layer_opacities, + layer_opacities_by_depth, + component_count, + depth_idx, + component_idx); const float scalar_transmission = std::pow(1.f - opacity, TD_EFFECTIVE_ALPHA_DENSITY_SCALE); const ColorSolverStackComponentRole role = size_t(component_idx) < component_roles.size() ? @@ -664,15 +687,16 @@ std::array mix_ordered_stack_with_buffers(const std::vector &component_roles) + const std::vector &component_roles, + const std::vector &layer_opacities_by_depth) { if (colors_with_background.empty() || surface_to_deep.empty()) return colors_with_background.empty() ? std::array{ { 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, 0.f, component_roles); + return mix_ordered_stack_td_effective_alpha(colors_with_background, surface_to_deep, layer_opacities, 0.f, component_roles, layer_opacities_by_depth); if (beer_lambert_rgb_correction) - return mix_ordered_stack_beer_lambert_rgb(colors_with_background, surface_to_deep, layer_opacities, surface_scatter); + return mix_ordered_stack_beer_lambert_rgb(colors_with_background, surface_to_deep, layer_opacities, surface_scatter, layer_opacities_by_depth); const size_t component_count = colors_with_background.size() - 1; weights.assign(colors_with_background.size(), 0.f); @@ -680,13 +704,15 @@ std::array mix_ordered_stack_with_buffers(const std::vector= component_count) continue; - float opacity = - size_t(component_idx) < layer_opacities.size() && std::isfinite(layer_opacities[size_t(component_idx)]) ? - std::clamp(layer_opacities[size_t(component_idx)], 1e-4f, 0.9999f) : - 0.5f; + float opacity = ordered_stack_layer_opacity(layer_opacities, + layer_opacities_by_depth, + component_count, + depth_idx, + component_idx); if (surface_layer) { opacity = std::clamp(safe_surface_scatter + (1.f - safe_surface_scatter) * opacity, 1e-4f, 0.9999f); surface_layer = false; @@ -1014,7 +1040,8 @@ void append_ordered_stack_candidate(ColorSolverOrderedStackCandidateSet &c float surface_scatter, bool beer_lambert_rgb_correction, bool td_effective_alpha_correction, - const std::vector &component_roles) + const std::vector &component_roles, + const std::vector &layer_opacities_by_depth) { std::vector simulated_surface_to_deep; const std::vector *mix_stack = &surface_to_deep; @@ -1031,7 +1058,8 @@ void append_ordered_stack_candidate(ColorSolverOrderedStackCandidateSet &c surface_scatter, beer_lambert_rgb_correction, td_effective_alpha_correction, - component_roles); + component_roles, + layer_opacities_by_depth); const std::array perceptual = oklab_from_srgb(mixed); candidates.rgbs.emplace_back(mixed[0]); candidates.rgbs.emplace_back(mixed[1]); @@ -1109,7 +1137,8 @@ std::array mix_color_solver_ordered_stack(const std::vector &component_roles) + const std::vector &component_roles, + const std::vector &layer_opacities_by_depth) { if (component_colors.empty() || surface_to_deep.empty()) return background_rgb; @@ -1125,7 +1154,8 @@ std::array mix_color_solver_ordered_stack(const std::vector color_solver_oklab_from_srgb(const std::array &rgb) @@ -1263,7 +1293,8 @@ std::string color_solver_ordered_stack_candidate_cache_key(const std::vector &component_roles, - bool beam_search_stack_expansion) + bool beam_search_stack_expansion, + const std::vector &layer_opacities_by_depth) { std::ostringstream key; key << component_colors.size(); @@ -1306,6 +1337,15 @@ std::string color_solver_ordered_stack_candidate_cache_key(const std::vector &component_roles, - bool beam_search_stack_expansion) + bool beam_search_stack_expansion, + const std::vector &layer_opacities_by_depth) { ColorSolverOrderedStackCandidateSet candidates; int simulated_depth = simulated_stack_depth > 0 ? simulated_stack_depth : stack_depth; @@ -1363,7 +1404,8 @@ ColorSolverOrderedStackCandidateSet build_color_solver_ordered_stack_candidates( surface_scatter, beer_lambert_rgb_correction, td_effective_alpha_correction, - component_roles); + component_roles, + layer_opacities_by_depth); return; } @@ -1416,7 +1458,8 @@ ColorSolverOrderedStackCandidateSet build_color_solver_ordered_stack_candidates( surface_scatter, beer_lambert_rgb_correction, td_effective_alpha_correction, - component_roles); + component_roles, + layer_opacities_by_depth); } return; } @@ -1447,7 +1490,8 @@ const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates bool beer_lambert_rgb_correction, bool td_effective_alpha_correction, const std::vector &component_roles, - bool beam_search_stack_expansion) + bool beam_search_stack_expansion, + const std::vector &layer_opacities_by_depth) { const std::string key = color_solver_ordered_stack_candidate_cache_key(component_colors, @@ -1462,7 +1506,8 @@ const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates beer_lambert_rgb_correction, td_effective_alpha_correction, component_roles, - beam_search_stack_expansion); + beam_search_stack_expansion, + layer_opacities_by_depth); auto it = cache.find(key); if (it != cache.end()) return it->second; @@ -1480,7 +1525,8 @@ const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates beer_lambert_rgb_correction, td_effective_alpha_correction, component_roles, - beam_search_stack_expansion)).first->second; + beam_search_stack_expansion, + layer_opacities_by_depth)).first->second; } ColorSolverOrderedStackResult solve_color_solver_ordered_stack_result_for_target( diff --git a/src/libslic3r/ColorSolver.hpp b/src/libslic3r/ColorSolver.hpp index b5d843a01ad..5d4646dbdb9 100644 --- a/src/libslic3r/ColorSolver.hpp +++ b/src/libslic3r/ColorSolver.hpp @@ -131,7 +131,8 @@ std::array mix_color_solver_ordered_stack(const std::vector &component_roles = {}); + const std::vector &component_roles = {}, + const std::vector &layer_opacities_by_depth = {}); std::array color_solver_oklab_from_srgb(const std::array &rgb); std::array color_solver_srgb_from_oklab(const std::array &oklab); @@ -161,7 +162,8 @@ std::string color_solver_ordered_stack_candidate_cache_key(const std::vector &component_roles = {}, - bool beam_search_stack_expansion = false); + bool beam_search_stack_expansion = false, + const std::vector &layer_opacities_by_depth = {}); ColorSolverOrderedStackCandidateSet build_color_solver_ordered_stack_candidates( const std::vector> &component_colors, const std::vector &layer_opacities, @@ -175,7 +177,8 @@ ColorSolverOrderedStackCandidateSet build_color_solver_ordered_stack_candidates( bool beer_lambert_rgb_correction = false, bool td_effective_alpha_correction = false, const std::vector &component_roles = {}, - bool beam_search_stack_expansion = false); + bool beam_search_stack_expansion = false, + const std::vector &layer_opacities_by_depth = {}); const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates( ColorSolverOrderedStackCandidateCache &cache, const std::vector> &component_colors, @@ -190,7 +193,8 @@ const ColorSolverOrderedStackCandidateSet &color_solver_ordered_stack_candidates bool beer_lambert_rgb_correction = false, bool td_effective_alpha_correction = false, const std::vector &component_roles = {}, - bool beam_search_stack_expansion = false); + bool beam_search_stack_expansion = false, + const std::vector &layer_opacities_by_depth = {}); ColorSolverOrderedStackResult solve_color_solver_ordered_stack_result_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 45227fe5fdb..f8b54909375 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -518,6 +518,7 @@ struct TopSurfaceImageRegionPlan { bool contoning_surface_scatter_enabled = TextureMappingZone::DefaultTopSurfaceContoningSurfaceScatterEnabled; bool contoning_beer_lambert_rgb_correction_enabled = TextureMappingZone::DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled; bool contoning_td_effective_alpha_correction_enabled = TextureMappingZone::DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled; + bool contoning_variable_layer_height_compensation_enabled = TextureMappingZone::DefaultTopSurfaceContoningVariableLayerHeightCompensationEnabled; bool contoning_beam_search_stack_expansion_enabled = TextureMappingZone::DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled; int contoning_generic_solver_mix_model = TextureMappingZone::DefaultGenericSolverMixModel; int contoning_flat_surface_infill_mode = TextureMappingZone::SlicerDefaultTopSurfaceContoningFlatSurfaceInfillMode; @@ -1649,6 +1650,24 @@ static std::vector top_surface_image_contoning_stack_areas(const Lay return out; } +static std::vector top_surface_image_contoning_surface_to_deep_layer_heights( + const Layer &source_layer, + int stack_layers, + TopSurfaceImageSourceSurface source_surface) +{ + std::vector out; + out.reserve(size_t(std::max(0, stack_layers))); + const Layer *stack_layer = &source_layer; + for (int depth = 0; depth < stack_layers && stack_layer != nullptr; ++depth) { + const float height = float(stack_layer->height); + out.emplace_back(std::isfinite(height) && height > 0.f ? height : 0.f); + stack_layer = source_surface == TopSurfaceImageSourceSurface::Top ? + stack_layer->lower_layer : + stack_layer->upper_layer; + } + return out; +} + static double top_surface_image_scaled_area_mm2(double scaled_area) { return std::abs(scaled_area) * SCALING_FACTOR * SCALING_FACTOR; @@ -2219,6 +2238,7 @@ private: struct TopSurfaceImageContoningSourceContext { TextureMappingOffsetContext offset_context; std::vector stack_areas; + std::vector surface_to_deep_layer_heights_mm; ExPolygons normal_filter_bypass_area; float threshold_deg { 0.f }; int stack_layers { 0 }; @@ -2263,6 +2283,7 @@ struct TopSurfaceImageContoningStackPlanKey { bool surface_scatter { false }; bool beer_lambert_rgb_correction { false }; bool td_effective_alpha_correction { false }; + bool variable_layer_height_compensation { false }; bool beam_search_stack_expansion { false }; int mix_model { TextureMappingZone::DefaultGenericSolverMixModel }; @@ -2298,6 +2319,7 @@ struct TopSurfaceImageContoningStackPlanKey { surface_scatter, beer_lambert_rgb_correction, td_effective_alpha_correction, + variable_layer_height_compensation, beam_search_stack_expansion, mix_model) < std::tie(rhs.source_layer, @@ -2330,6 +2352,7 @@ struct TopSurfaceImageContoningStackPlanKey { rhs.surface_scatter, rhs.beer_lambert_rgb_correction, rhs.td_effective_alpha_correction, + rhs.variable_layer_height_compensation, rhs.beam_search_stack_expansion, rhs.mix_model); } @@ -4079,6 +4102,7 @@ static std::optional top_surface_image_cont const TextureMappingContoningSolver &solver, bool lower_surface, int visible_layers, + const std::vector &surface_to_deep_layer_heights_mm, std::vector &labels, std::map, int>, int> &label_by_stack) { @@ -4101,7 +4125,10 @@ static std::optional top_surface_image_cont if (stack.rgb) stack_rgb = stack.rgb; else - stack_rgb = solver.stack_rgb(stack.bottom_to_top, lower_surface, visible_layers); + stack_rgb = solver.stack_rgb(stack.bottom_to_top, + lower_surface, + visible_layers, + surface_to_deep_layer_heights_mm); if (!stack_rgb) return std::nullopt; @@ -4127,11 +4154,22 @@ static std::optional top_surface_image_cont int visible_layers, const TextureMappingContoningSolver &solver, bool lower_surface, + const std::vector &surface_to_deep_layer_heights_mm, std::vector &labels, std::map, int>, int> &label_by_stack) { - TextureMappingContoningStack stack = solver.solve(rgb, solve_layers, lower_surface, visible_layers); - return top_surface_image_contoning_label_for_stack(stack, solver, lower_surface, visible_layers, labels, label_by_stack); + TextureMappingContoningStack stack = solver.solve(rgb, + solve_layers, + lower_surface, + visible_layers, + surface_to_deep_layer_heights_mm); + return top_surface_image_contoning_label_for_stack(stack, + solver, + lower_surface, + visible_layers, + surface_to_deep_layer_heights_mm, + labels, + label_by_stack); } static void top_surface_image_contoning_resolve_merged_grid_regions( @@ -4145,6 +4183,7 @@ static void top_surface_image_contoning_resolve_merged_grid_regions( int stack_layers, int pattern_filaments, bool lower_surface, + const std::vector &surface_to_deep_layer_heights_mm, const ThrowIfCanceled *throw_if_canceled) { if (grid.empty() || labels.empty() || cols <= 0 || rows <= 0 || @@ -4243,6 +4282,7 @@ static void top_surface_image_contoning_resolve_merged_grid_regions( visible_layers, solver, lower_surface, + surface_to_deep_layer_heights_mm, resolved_labels, label_by_stack); if (solved) @@ -4313,6 +4353,9 @@ static std::optional top_surface_image_co top_surface_image_contoning_pattern_filaments(out.stack_layers, plan.contoning_pattern_filaments); out.stack_areas = top_surface_image_contoning_stack_areas(source_layer, plan.zone_id, out.stack_layers, source_surface, throw_if_canceled); + if (plan.contoning_variable_layer_height_compensation_enabled) + out.surface_to_deep_layer_heights_mm = + top_surface_image_contoning_surface_to_deep_layer_heights(source_layer, out.stack_layers, source_surface); if (stack_area_extensions != nullptr) { const size_t count = std::min(out.stack_areas.size(), stack_area_extensions->size()); for (size_t idx = 0; idx < count; ++idx) { @@ -4401,6 +4444,7 @@ static void top_surface_image_contoning_solve_anchored_region( solver, lower_surface, available_depth, + source_context.surface_to_deep_layer_heights_mm, labels, label_by_stack); if (!solved) @@ -4448,7 +4492,11 @@ static void top_surface_image_contoning_solve_anchored_region( 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); + cell_stacks[grid_idx] = solver.solve(sample->rgb, + sample->solve_layers, + lower_surface, + sample->available_depth, + source_context.surface_to_deep_layer_heights_mm); if (debug_stride > 0 && row % debug_stride == 0 && col % debug_stride == 0) { @@ -4550,6 +4598,7 @@ static void top_surface_image_contoning_solve_anchored_region( source_context.stack_layers, source_context.pattern_filaments, source_surface == TopSurfaceImageSourceSurface::Bottom, + source_context.surface_to_deep_layer_heights_mm, throw_if_canceled); if (debug_enabled) top_surface_image_debug_accumulate_timing_step(debug_timing.steps, @@ -5049,6 +5098,7 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_anchored key.surface_scatter = plan.contoning_surface_scatter_enabled; key.beer_lambert_rgb_correction = plan.contoning_beer_lambert_rgb_correction_enabled; key.td_effective_alpha_correction = plan.contoning_td_effective_alpha_correction_enabled; + key.variable_layer_height_compensation = plan.contoning_variable_layer_height_compensation_enabled; key.beam_search_stack_expansion = plan.contoning_beam_search_stack_expansion_enabled; key.mix_model = plan.contoning_generic_solver_mix_model; return key; @@ -5184,6 +5234,7 @@ static std::vector top_surface_image_conto solver, source_surface == TopSurfaceImageSourceSurface::Bottom && plan.contoning_td_adjustment_enabled, + source->surface_to_deep_layer_heights_mm, labels, label_by_stack); if (!solved) @@ -5310,6 +5361,7 @@ static std::vector top_surface_image_conto source->stack_layers, source->pattern_filaments, source_surface == TopSurfaceImageSourceSurface::Bottom, + source->surface_to_deep_layer_heights_mm, throw_if_canceled); } check_canceled(throw_if_canceled); @@ -5396,6 +5448,7 @@ static std::shared_ptr top_surface_imag solver, source_surface == TopSurfaceImageSourceSurface::Bottom && plan.contoning_td_adjustment_enabled, + source_context->surface_to_deep_layer_heights_mm, out->labels, label_by_stack); if (!solved) @@ -5527,6 +5580,7 @@ static std::shared_ptr top_surface_imag source_context->stack_layers, source_context->pattern_filaments, source_surface == TopSurfaceImageSourceSurface::Bottom, + source_context->surface_to_deep_layer_heights_mm, throw_if_canceled); } for (size_t idx = 0; idx < out->cells.size(); ++idx) @@ -5586,6 +5640,7 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_stack_pl key.surface_scatter = plan.contoning_surface_scatter_enabled; key.beer_lambert_rgb_correction = plan.contoning_beer_lambert_rgb_correction_enabled; key.td_effective_alpha_correction = plan.contoning_td_effective_alpha_correction_enabled; + key.variable_layer_height_compensation = plan.contoning_variable_layer_height_compensation_enabled; key.beam_search_stack_expansion = plan.contoning_beam_search_stack_expansion_enabled; key.mix_model = plan.contoning_generic_solver_mix_model; return key; @@ -6284,6 +6339,8 @@ static std::vector top_surface_image_region_plans( plan.contoning_td_adjustment_enabled && !plan.contoning_td_effective_alpha_correction_enabled && zone->top_surface_contoning_beer_lambert_rgb_correction_enabled; + plan.contoning_variable_layer_height_compensation_enabled = + zone->top_surface_contoning_variable_layer_height_compensation_enabled; plan.contoning_generic_solver_mix_model = std::clamp(zone->generic_solver_mix_model, int(TextureMappingZone::GenericSolverPigmentPainter), diff --git a/src/libslic3r/TextureMapping.cpp b/src/libslic3r/TextureMapping.cpp index 6898953722e..1a575a95287 100644 --- a/src/libslic3r/TextureMapping.cpp +++ b/src/libslic3r/TextureMapping.cpp @@ -729,6 +729,28 @@ static int top_surface_contoning_flat_surface_infill_mode_from_name(const std::s return int(TextureMappingZone::ContoningFlatSurfaceInfillDefault); } +static std::string top_surface_contoning_color_prediction_mode_name(int mode) +{ + if (mode == int(TextureMappingZone::ContoningColorPredictionTdEffectiveAlpha)) + return "td_effective_alpha"; + if (mode == int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb)) + return "rgb_beer_lambert"; + return "default"; +} + +static int top_surface_contoning_color_prediction_mode_from_name(std::string name) +{ + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { + const char lowered = char(std::tolower(c)); + return lowered == '-' || lowered == ' ' ? '_' : lowered; + }); + if (name == "td_effective_alpha" || name == "effective_alpha") + return int(TextureMappingZone::ContoningColorPredictionTdEffectiveAlpha); + if (name == "rgb_beer_lambert" || name == "beer_lambert_rgb" || name == "beer_lambert") + return int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb); + return TextureMappingZone::DefaultTopSurfaceContoningColorPredictionMode; +} + static std::string top_visible_recolor_aggressiveness_name(int mode) { switch (clamp_int(mode, @@ -1183,8 +1205,10 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const rhs.effective_top_surface_contoning_surface_anchored_stack_optimizations_enabled() && top_surface_contoning_td_adjustment_enabled == rhs.top_surface_contoning_td_adjustment_enabled && effective_top_surface_contoning_surface_scatter_enabled() == rhs.effective_top_surface_contoning_surface_scatter_enabled() && + top_surface_contoning_color_prediction_mode == rhs.top_surface_contoning_color_prediction_mode && 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 && + top_surface_contoning_variable_layer_height_compensation_enabled == rhs.top_surface_contoning_variable_layer_height_compensation_enabled && effective_top_surface_contoning_beam_search_stack_expansion_enabled() == rhs.effective_top_surface_contoning_beam_search_stack_expansion_enabled() && compact_offset_mode == rhs.compact_offset_mode && use_legacy_fixed_color_mode == rhs.use_legacy_fixed_color_mode && @@ -1596,10 +1620,14 @@ std::string TextureMappingManager::serialize_entries() zone.top_surface_contoning_td_adjustment_enabled; texture["top_surface_contoning_surface_scatter_enabled"] = zone.effective_top_surface_contoning_surface_scatter_enabled(); + texture["top_surface_contoning_color_prediction_mode"] = + top_surface_contoning_color_prediction_mode_name(zone.top_surface_contoning_color_prediction_mode); 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"] = zone.top_surface_contoning_td_effective_alpha_correction_enabled; + texture["top_surface_contoning_variable_layer_height_compensation_enabled"] = + zone.top_surface_contoning_variable_layer_height_compensation_enabled; texture["top_surface_contoning_beam_search_stack_expansion_enabled"] = zone.effective_top_surface_contoning_beam_search_stack_expansion_enabled(); texture["compact_offset_mode"] = zone.compact_offset_mode; @@ -1913,12 +1941,22 @@ void TextureMappingManager::load_entries(const std::string &serialized, zone.top_surface_contoning_surface_scatter_enabled = texture.value("top_surface_contoning_surface_scatter_enabled", TextureMappingZone::DefaultTopSurfaceContoningSurfaceScatterEnabled); + auto color_prediction_mode_it = texture.find("top_surface_contoning_color_prediction_mode"); + zone.top_surface_contoning_color_prediction_mode = + color_prediction_mode_it != texture.end() && color_prediction_mode_it->is_string() ? + top_surface_contoning_color_prediction_mode_from_name(color_prediction_mode_it->get()) : + clamp_int(color_prediction_mode_it != texture.end() && color_prediction_mode_it->is_number_integer() ? + color_prediction_mode_it->get() : + TextureMappingZone::DefaultTopSurfaceContoningColorPredictionMode, + int(TextureMappingZone::ContoningColorPredictionDefault), + int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb)); zone.top_surface_contoning_beer_lambert_rgb_correction_enabled = - texture.value("top_surface_contoning_beer_lambert_rgb_correction_enabled", - TextureMappingZone::DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled); + TextureMappingZone::DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled; zone.top_surface_contoning_td_effective_alpha_correction_enabled = - texture.value("top_surface_contoning_td_effective_alpha_correction_enabled", - TextureMappingZone::DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled); + TextureMappingZone::DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled; + zone.top_surface_contoning_variable_layer_height_compensation_enabled = + texture.value("top_surface_contoning_variable_layer_height_compensation_enabled", + TextureMappingZone::DefaultTopSurfaceContoningVariableLayerHeightCompensationEnabled); zone.top_surface_contoning_beam_search_stack_expansion_enabled = texture.value("top_surface_contoning_beam_search_stack_expansion_enabled", TextureMappingZone::DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled); diff --git a/src/libslic3r/TextureMapping.hpp b/src/libslic3r/TextureMapping.hpp index b0aa5dad6b0..091ed409566 100644 --- a/src/libslic3r/TextureMapping.hpp +++ b/src/libslic3r/TextureMapping.hpp @@ -89,6 +89,12 @@ struct TextureMappingZone ContoningFlatSurfaceInfillRectilinearWithBoundary = 7 }; + enum TopSurfaceContoningColorPredictionMode : uint8_t { + ContoningColorPredictionDefault = 0, + ContoningColorPredictionTdEffectiveAlpha = 1, + ContoningColorPredictionBeerLambertRgb = 2 + }; + enum FilamentColorMode : uint8_t { FilamentColorAny = 0, FilamentColorRGB = 1, @@ -207,8 +213,13 @@ struct TextureMappingZone static constexpr bool DefaultTopSurfaceContoningSurfaceAnchoredStackOptimizationsEnabled = true; static constexpr bool DefaultTopSurfaceContoningTdAdjustmentEnabled = true; static constexpr bool DefaultTopSurfaceContoningSurfaceScatterEnabled = false; - static constexpr bool DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled = false; - static constexpr bool DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled = true; + static constexpr int DefaultTopSurfaceContoningColorPredictionMode = int(ContoningColorPredictionDefault); + static constexpr int SlicerDefaultTopSurfaceContoningColorPredictionMode = int(ContoningColorPredictionTdEffectiveAlpha); + static constexpr bool DefaultTopSurfaceContoningVariableLayerHeightCompensationEnabled = true; + static constexpr bool DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled = + SlicerDefaultTopSurfaceContoningColorPredictionMode == int(ContoningColorPredictionBeerLambertRgb); + static constexpr bool DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled = + SlicerDefaultTopSurfaceContoningColorPredictionMode == int(ContoningColorPredictionTdEffectiveAlpha); static constexpr bool DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled = true; static constexpr bool DefaultCompactOffsetMode = true; static constexpr bool DefaultUseLegacyFixedColorMode = false; @@ -329,6 +340,15 @@ struct TextureMappingZone return td_adjustment && surface_scatter && !td_effective_alpha; } + static int effective_top_surface_contoning_color_prediction_mode(int mode) + { + if (mode == int(ContoningColorPredictionDefault)) + return SlicerDefaultTopSurfaceContoningColorPredictionMode; + return std::clamp(mode, + int(ContoningColorPredictionTdEffectiveAlpha), + int(ContoningColorPredictionBeerLambertRgb)); + } + static bool effective_top_surface_contoning_layer_phase_enabled(bool value, bool surface_anchored_stacks) { return effective_top_surface_contoning_layer_phase_enabled(value) && @@ -343,7 +363,7 @@ struct TextureMappingZone static constexpr int normalize_top_surface_contoning_polygonize_resolution(int value) { - return value <= 1 ? 1 : (value >= 8 ? 8 : (value >= 4 ? 4 : 2)); + return value <= 1 ? 1 : (value >= 8 ? 8 : (value >= 4 ? 4 : (value >= 3 ? 3 : 2))); } struct LinearGradientAnchor { @@ -431,6 +451,8 @@ struct TextureMappingZone bool top_surface_contoning_surface_scatter_enabled = DefaultTopSurfaceContoningSurfaceScatterEnabled; bool top_surface_contoning_beer_lambert_rgb_correction_enabled = DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled; bool top_surface_contoning_td_effective_alpha_correction_enabled = DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled; + int top_surface_contoning_color_prediction_mode = DefaultTopSurfaceContoningColorPredictionMode; + bool top_surface_contoning_variable_layer_height_compensation_enabled = DefaultTopSurfaceContoningVariableLayerHeightCompensationEnabled; bool top_surface_contoning_beam_search_stack_expansion_enabled = DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled; bool compact_offset_mode = DefaultCompactOffsetMode; bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode; @@ -589,6 +611,20 @@ struct TextureMappingZone top_surface_contoning_td_effective_alpha_correction_enabled); } + int effective_top_surface_contoning_color_prediction_mode() const + { + return TextureMappingZone::effective_top_surface_contoning_color_prediction_mode( + top_surface_contoning_color_prediction_mode); + } + + void normalize_top_surface_contoning_td_correction() + { + const bool beer_lambert_rgb = + effective_top_surface_contoning_color_prediction_mode() == int(ContoningColorPredictionBeerLambertRgb); + top_surface_contoning_beer_lambert_rgb_correction_enabled = beer_lambert_rgb; + top_surface_contoning_td_effective_alpha_correction_enabled = !beer_lambert_rgb; + } + void apply_top_surface_contoning_experimental_defaults() { if (top_surface_image_printing_enabled && @@ -617,6 +653,8 @@ struct TextureMappingZone top_surface_contoning_layer_phase_enabled = false; top_surface_contoning_blue_noise_error_diffusion_enabled = false; } + top_surface_contoning_td_adjustment_enabled = true; + normalize_top_surface_contoning_td_correction(); if (top_surface_contoning_td_effective_alpha_correction_enabled) top_surface_contoning_surface_scatter_enabled = false; } @@ -687,6 +725,8 @@ struct TextureMappingZone top_surface_contoning_surface_scatter_enabled = DefaultTopSurfaceContoningSurfaceScatterEnabled; top_surface_contoning_beer_lambert_rgb_correction_enabled = DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled; top_surface_contoning_td_effective_alpha_correction_enabled = DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled; + top_surface_contoning_color_prediction_mode = DefaultTopSurfaceContoningColorPredictionMode; + top_surface_contoning_variable_layer_height_compensation_enabled = DefaultTopSurfaceContoningVariableLayerHeightCompensationEnabled; top_surface_contoning_beam_search_stack_expansion_enabled = DefaultTopSurfaceContoningBeamSearchStackExpansionEnabled; compact_offset_mode = DefaultCompactOffsetMode; use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode; diff --git a/src/libslic3r/TextureMappingContoning.cpp b/src/libslic3r/TextureMappingContoning.cpp index 01dc1ef288c..11353776b6e 100644 --- a/src/libslic3r/TextureMappingContoning.cpp +++ b/src/libslic3r/TextureMappingContoning.cpp @@ -413,6 +413,8 @@ TextureMappingContoningSolver::TextureMappingContoningSolver(const TextureMappin m_td_adjustment_enabled && !m_td_effective_alpha_correction_enabled && zone.top_surface_contoning_beer_lambert_rgb_correction_enabled; + m_variable_layer_height_compensation_enabled = + m_td_adjustment_enabled && zone.top_surface_contoning_variable_layer_height_compensation_enabled; m_beam_search_stack_expansion_enabled = zone.effective_top_surface_contoning_beam_search_stack_expansion_enabled(); 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) @@ -490,7 +492,8 @@ std::optional TextureMappingContoningSolver::component_index(unsigned in std::optional> TextureMappingContoningSolver::stack_rgb( const std::vector &bottom_to_top, bool lower_surface, - int visible_stack_layers) const + int visible_stack_layers, + const std::vector &surface_to_deep_layer_heights_mm) const { if (bottom_to_top.empty() || !valid()) return std::nullopt; @@ -542,6 +545,8 @@ std::optional> TextureMappingContoningSolver::stack_rgb( surface_to_deep = std::move(repeated); } + const std::vector depth_layer_opacities = + layer_opacities_by_depth(surface_to_deep_layer_heights_mm, visible_depth); return mix_color_solver_ordered_stack(m_component_colors, surface_to_deep, m_component_layer_opacity, @@ -550,7 +555,34 @@ std::optional> TextureMappingContoningSolver::stack_rgb( m_surface_scatter, m_beer_lambert_rgb_correction_enabled, m_td_effective_alpha_correction_enabled, - m_component_roles); + m_component_roles, + depth_layer_opacities); +} + +std::vector TextureMappingContoningSolver::layer_opacities_by_depth( + const std::vector &surface_to_deep_layer_heights_mm, + int visible_depth) const +{ + if (!m_variable_layer_height_compensation_enabled || + surface_to_deep_layer_heights_mm.empty() || + visible_depth <= 0 || + m_effective_transmission_distances_mm.empty()) + return {}; + + const int depth = std::min(visible_depth, TextureMappingZone::MaxTopSurfaceContoningStackLayers); + std::vector out; + out.reserve(size_t(depth) * m_effective_transmission_distances_mm.size()); + for (int depth_idx = 0; depth_idx < depth; ++depth_idx) { + float layer_height_mm = + depth_idx < int(surface_to_deep_layer_heights_mm.size()) ? + surface_to_deep_layer_heights_mm[size_t(depth_idx)] : + m_layer_height_mm; + if (!std::isfinite(layer_height_mm) || layer_height_mm <= 0.f) + layer_height_mm = m_layer_height_mm; + for (float td_mm : m_effective_transmission_distances_mm) + out.emplace_back(layer_opacity_from_td(td_mm > 0.f ? td_mm : 3.f, layer_height_mm)); + } + return out; } void TextureMappingContoningSolver::arrange_stack_for_light_path(std::vector &bottom_to_top, @@ -621,7 +653,8 @@ void TextureMappingContoningSolver::arrange_stack_for_light_path(std::vector &target_rgb, int stack_layers, bool lower_surface, - int visible_stack_layers) const + int visible_stack_layers, + const std::vector &surface_to_deep_layer_heights_mm) const { TextureMappingContoningStack out; if (!valid()) @@ -637,6 +670,8 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr requested_depth; const int depth = std::min(requested_depth, visible_depth); if (m_td_adjustment_enabled) { + const std::vector depth_layer_opacities = + layer_opacities_by_depth(surface_to_deep_layer_heights_mm, visible_depth); const ColorSolverOrderedStackCandidateSet *ordered_candidates = nullptr; { std::lock_guard lock(*m_ordered_candidate_cache_mutex); @@ -654,7 +689,8 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr m_beer_lambert_rgb_correction_enabled, m_td_effective_alpha_correction_enabled, m_component_roles, - m_beam_search_stack_expansion_enabled); + m_beam_search_stack_expansion_enabled, + depth_layer_opacities); } const ColorSolverOrderedStackResult solved = solve_color_solver_ordered_stack_result_for_target(*ordered_candidates, target_rgb, ColorSolverMode::OklabSoftCap4Dark4); diff --git a/src/libslic3r/TextureMappingContoning.hpp b/src/libslic3r/TextureMappingContoning.hpp index c6c62790fd7..bd3d2f56149 100644 --- a/src/libslic3r/TextureMappingContoning.hpp +++ b/src/libslic3r/TextureMappingContoning.hpp @@ -39,11 +39,13 @@ public: TextureMappingContoningStack solve(const std::array &target_rgb, int stack_layers, bool lower_surface = false, - int visible_stack_layers = 0) const; + int visible_stack_layers = 0, + const std::vector &surface_to_deep_layer_heights_mm = {}) const; unsigned int component_for_depth(const std::array &target_rgb, int stack_layers, int depth_from_top, bool lower_surface = false) const; std::optional> stack_rgb(const std::vector &bottom_to_top, bool lower_surface = false, - int visible_stack_layers = 0) const; + int visible_stack_layers = 0, + const std::vector &surface_to_deep_layer_heights_mm = {}) const; private: struct Candidate { @@ -57,6 +59,8 @@ private: void arrange_stack_for_light_path(std::vector &bottom_to_top, const std::array &target_rgb) const; std::optional component_index(unsigned int component_id) const; + std::vector layer_opacities_by_depth(const std::vector &surface_to_deep_layer_heights_mm, + int visible_depth) const; std::vector m_component_ids; std::vector m_components_bottom_to_top; @@ -71,6 +75,7 @@ private: bool m_td_adjustment_enabled { false }; bool m_beer_lambert_rgb_correction_enabled { false }; bool m_td_effective_alpha_correction_enabled { false }; + bool m_variable_layer_height_compensation_enabled { false }; bool m_beam_search_stack_expansion_enabled { false }; std::vector m_component_roles; mutable std::map> m_candidates_by_depth; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 373a00ec170..cce33c68067 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2094,6 +2094,50 @@ static int texture_mapping_generic_solver_mode_from_choice_selection(int selecti } } +static wxString texture_mapping_contoning_color_prediction_mode_label(int mode) +{ + switch (TextureMappingZone::effective_top_surface_contoning_color_prediction_mode(mode)) { + case int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb): + return _L("RGB Beer-Lambert - not recommended"); + default: + return _L("TD Effective Alpha"); + } +} + +static wxString texture_mapping_contoning_color_prediction_default_label() +{ + wxString label = _L("Default"); + label += " ("; + label += texture_mapping_contoning_color_prediction_mode_label( + TextureMappingZone::SlicerDefaultTopSurfaceContoningColorPredictionMode); + label += ")"; + return label; +} + +static int texture_mapping_contoning_color_prediction_mode_choice_selection(int mode) +{ + if (mode == int(TextureMappingZone::ContoningColorPredictionDefault)) + return 0; + switch (TextureMappingZone::effective_top_surface_contoning_color_prediction_mode(mode)) { + case int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb): + return 2; + default: + return 1; + } +} + +static int texture_mapping_contoning_color_prediction_mode_from_choice_selection(int selection) +{ + switch (selection) { + case 1: + return int(TextureMappingZone::ContoningColorPredictionTdEffectiveAlpha); + case 2: + return int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb); + default: + return TextureMappingZone::DefaultTopSurfaceContoningColorPredictionMode; + } +} + class TextureMappingAdvancedOptionsDialog : public wxDialog { public: @@ -2159,8 +2203,10 @@ public: bool top_surface_contoning_beam_search_stack_expansion_enabled, bool top_surface_contoning_td_adjustment_enabled, bool top_surface_contoning_surface_scatter_enabled, + int top_surface_contoning_color_prediction_mode, bool top_surface_contoning_beer_lambert_rgb_correction_enabled, bool top_surface_contoning_td_effective_alpha_correction_enabled, + bool top_surface_contoning_variable_layer_height_compensation_enabled, const TextureMappingZoneShellUsageSummary &top_surface_contoning_shell_usage, const TextureMappingManager &texture_mapping_zones, const TextureMappingGlobalSettings &global_settings, @@ -2175,6 +2221,9 @@ public: { (void) reduce_outer_surface_texture; (void) top_surface_contoning_min_feature_mm; + (void) top_surface_contoning_td_adjustment_enabled; + (void) top_surface_contoning_beer_lambert_rgb_correction_enabled; + (void) top_surface_contoning_td_effective_alpha_correction_enabled; m_modulation_mode_manually_changed = modulation_mode_manually_changed; m_strength_offsets_expanded = initial_strength_offsets_expanded; m_top_surface_contoning_shell_usage = top_surface_contoning_shell_usage; @@ -2841,43 +2890,43 @@ public: 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); - m_top_surface_contoning_td_adjustment_checkbox = - new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("TD adjustment")); - m_top_surface_contoning_td_adjustment_checkbox->SetValue(top_surface_contoning_td_adjustment_enabled); - m_top_surface_contoning_td_adjustment_checkbox->SetMinSize( - wxSize(-1, std::max(m_top_surface_contoning_td_adjustment_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); - contoning_checkboxes_root->Add(m_top_surface_contoning_td_adjustment_checkbox, - 0, - wxEXPAND | wxTOP | wxBOTTOM, - gap / 2); + const bool top_surface_contoning_td_effective_alpha_correction_selected = + TextureMappingZone::effective_top_surface_contoning_color_prediction_mode(top_surface_contoning_color_prediction_mode) == + int(TextureMappingZone::ContoningColorPredictionTdEffectiveAlpha); 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( TextureMappingZone::effective_top_surface_contoning_surface_scatter_enabled( - top_surface_contoning_td_adjustment_enabled, + true, top_surface_contoning_surface_scatter_enabled, - top_surface_contoning_td_effective_alpha_correction_enabled)); + top_surface_contoning_td_effective_alpha_correction_selected)); 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, 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); - m_top_surface_contoning_td_effective_alpha_correction_checkbox = - new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("TD Effective Alpha correction")); - m_top_surface_contoning_td_effective_alpha_correction_checkbox->SetValue(top_surface_contoning_td_effective_alpha_correction_enabled); - m_top_surface_contoning_td_effective_alpha_correction_checkbox->SetMinSize( - wxSize(-1, std::max(m_top_surface_contoning_td_effective_alpha_correction_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); - contoning_checkboxes_root->Add(m_top_surface_contoning_td_effective_alpha_correction_checkbox, - 0, - wxEXPAND | wxTOP | wxBOTTOM, - gap / 2); - m_top_surface_contoning_beer_lambert_rgb_correction_checkbox = - new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("RGB Beer-Lambert correction")); - m_top_surface_contoning_beer_lambert_rgb_correction_checkbox->SetValue(top_surface_contoning_beer_lambert_rgb_correction_enabled); - m_top_surface_contoning_beer_lambert_rgb_correction_checkbox->SetMinSize( - wxSize(-1, std::max(m_top_surface_contoning_beer_lambert_rgb_correction_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); - contoning_checkboxes_root->Add(m_top_surface_contoning_beer_lambert_rgb_correction_checkbox, + auto *contoning_td_correction_row = new wxBoxSizer(wxHORIZONTAL); + contoning_td_correction_row->Add(new wxStaticText(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Color prediction mode")), + 0, + wxALIGN_CENTER_VERTICAL | wxRIGHT, + gap); + wxArrayString contoning_td_correction_choices; + contoning_td_correction_choices.Add(texture_mapping_contoning_color_prediction_default_label()); + contoning_td_correction_choices.Add(texture_mapping_contoning_color_prediction_mode_label(int(TextureMappingZone::ContoningColorPredictionTdEffectiveAlpha))); + contoning_td_correction_choices.Add(texture_mapping_contoning_color_prediction_mode_label(int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb))); + m_top_surface_contoning_td_correction_choice = + new wxChoice(m_top_surface_contoning_checkboxes_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, contoning_td_correction_choices); + m_top_surface_contoning_td_correction_choice->SetSelection( + texture_mapping_contoning_color_prediction_mode_choice_selection(top_surface_contoning_color_prediction_mode)); + contoning_td_correction_row->Add(m_top_surface_contoning_td_correction_choice, 1, wxALIGN_CENTER_VERTICAL); + contoning_checkboxes_root->Add(contoning_td_correction_row, 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); + m_top_surface_contoning_variable_layer_height_compensation_checkbox = + new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Variable layer height compensation")); + m_top_surface_contoning_variable_layer_height_compensation_checkbox->SetValue(top_surface_contoning_variable_layer_height_compensation_enabled); + m_top_surface_contoning_variable_layer_height_compensation_checkbox->SetMinSize( + wxSize(-1, std::max(m_top_surface_contoning_variable_layer_height_compensation_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); + contoning_checkboxes_root->Add(m_top_surface_contoning_variable_layer_height_compensation_checkbox, 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); @@ -2992,15 +3041,6 @@ public: 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); - m_top_surface_contoning_fast_mode_checkbox = - new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Fast mode")); - m_top_surface_contoning_fast_mode_checkbox->SetValue(top_surface_contoning_fast_mode_enabled); - m_top_surface_contoning_fast_mode_checkbox->SetMinSize( - wxSize(-1, std::max(m_top_surface_contoning_fast_mode_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); - contoning_checkboxes_root->Add(m_top_surface_contoning_fast_mode_checkbox, - 0, - wxEXPAND | wxTOP | wxBOTTOM, - gap / 2); m_top_surface_contoning_polygonize_resolution_panel = new wxPanel(m_top_surface_contoning_checkboxes_panel, wxID_ANY); auto *contoning_polygonize_resolution_row = new wxBoxSizer(wxHORIZONTAL); m_top_surface_contoning_polygonize_resolution_panel->SetSizer(contoning_polygonize_resolution_row); @@ -3011,6 +3051,7 @@ public: wxArrayString contoning_polygonize_resolution_choices; contoning_polygonize_resolution_choices.Add(_L("1x")); contoning_polygonize_resolution_choices.Add(_L("2x")); + contoning_polygonize_resolution_choices.Add(_L("3x")); contoning_polygonize_resolution_choices.Add(_L("4x")); contoning_polygonize_resolution_choices.Add(_L("8x (slow)")); m_top_surface_contoning_polygonize_resolution_choice = @@ -3018,12 +3059,21 @@ public: const int polygonize_resolution = TextureMappingZone::normalize_top_surface_contoning_polygonize_resolution(top_surface_contoning_polygonize_resolution); m_top_surface_contoning_polygonize_resolution_choice->SetSelection( polygonize_resolution == 1 ? 0 : - (polygonize_resolution == 2 ? 1 : (polygonize_resolution == 4 ? 2 : 3))); + (polygonize_resolution == 2 ? 1 : (polygonize_resolution == 3 ? 2 : (polygonize_resolution == 4 ? 3 : 4)))); contoning_polygonize_resolution_row->Add(m_top_surface_contoning_polygonize_resolution_choice, 1, wxEXPAND); contoning_checkboxes_root->Add(m_top_surface_contoning_polygonize_resolution_panel, 0, wxEXPAND | wxTOP | wxBOTTOM, gap / 2); + m_top_surface_contoning_fast_mode_checkbox = + new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Fast mode")); + m_top_surface_contoning_fast_mode_checkbox->SetValue(top_surface_contoning_fast_mode_enabled); + m_top_surface_contoning_fast_mode_checkbox->SetMinSize( + wxSize(-1, std::max(m_top_surface_contoning_fast_mode_checkbox->GetBestSize().GetHeight(), FromDIP(24)))); + contoning_checkboxes_root->Add(m_top_surface_contoning_fast_mode_checkbox, + 0, + wxEXPAND | wxTOP | wxBOTTOM, + gap / 2); if (TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions) { m_top_surface_contoning_surface_anchored_stacks_checkbox = new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Surface-anchored stacks")); @@ -3085,25 +3135,19 @@ public: update_top_surface_image_options_visibility(true); }); } - if (m_top_surface_contoning_td_adjustment_checkbox != nullptr) { - m_top_surface_contoning_td_adjustment_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { - update_top_surface_image_options_visibility(false); - queue_top_surface_contoning_message_update(true); - }); - } if (m_top_surface_contoning_surface_scatter_checkbox != nullptr) { m_top_surface_contoning_surface_scatter_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { queue_top_surface_contoning_message_update(true); }); } - if (m_top_surface_contoning_td_effective_alpha_correction_checkbox != nullptr) { - m_top_surface_contoning_td_effective_alpha_correction_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { + if (m_top_surface_contoning_td_correction_choice != nullptr) { + m_top_surface_contoning_td_correction_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &) { update_top_surface_image_options_visibility(false); queue_top_surface_contoning_message_update(true); }); } - if (m_top_surface_contoning_beer_lambert_rgb_correction_checkbox != nullptr) { - m_top_surface_contoning_beer_lambert_rgb_correction_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { + if (m_top_surface_contoning_variable_layer_height_compensation_checkbox != nullptr) { + m_top_surface_contoning_variable_layer_height_compensation_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { queue_top_surface_contoning_message_update(true); }); } @@ -3595,8 +3639,9 @@ public: switch (selection) { case 0: return 1; case 1: return 2; - case 2: return 4; - case 3: return 8; + case 2: return 3; + case 3: return 4; + case 4: return 8; default: return TextureMappingZone::DefaultTopSurfaceContoningPolygonizeResolution; } } @@ -3626,9 +3671,20 @@ public: } bool top_surface_contoning_td_adjustment_enabled() const { - return m_top_surface_contoning_td_adjustment_checkbox == nullptr ? - TextureMappingZone::DefaultTopSurfaceContoningTdAdjustmentEnabled : - m_top_surface_contoning_td_adjustment_checkbox->GetValue(); + return true; + } + int top_surface_contoning_color_prediction_mode() const + { + return m_top_surface_contoning_td_correction_choice == nullptr ? + TextureMappingZone::DefaultTopSurfaceContoningColorPredictionMode : + texture_mapping_contoning_color_prediction_mode_from_choice_selection( + m_top_surface_contoning_td_correction_choice->GetSelection()); + } + bool top_surface_contoning_td_effective_alpha_correction_selected() const + { + return TextureMappingZone::effective_top_surface_contoning_color_prediction_mode( + top_surface_contoning_color_prediction_mode()) == + int(TextureMappingZone::ContoningColorPredictionTdEffectiveAlpha); } bool top_surface_contoning_surface_scatter_enabled() const { @@ -3642,17 +3698,20 @@ public: bool top_surface_contoning_beer_lambert_rgb_correction_enabled() const { return top_surface_contoning_td_adjustment_enabled() && - !top_surface_contoning_td_effective_alpha_correction_enabled() && - (m_top_surface_contoning_beer_lambert_rgb_correction_checkbox == nullptr ? - TextureMappingZone::DefaultTopSurfaceContoningBeerLambertRgbCorrectionEnabled : - m_top_surface_contoning_beer_lambert_rgb_correction_checkbox->GetValue()); + TextureMappingZone::effective_top_surface_contoning_color_prediction_mode( + top_surface_contoning_color_prediction_mode()) == + int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb); } bool top_surface_contoning_td_effective_alpha_correction_enabled() const { return top_surface_contoning_td_adjustment_enabled() && - (m_top_surface_contoning_td_effective_alpha_correction_checkbox == nullptr ? - TextureMappingZone::DefaultTopSurfaceContoningTdEffectiveAlphaCorrectionEnabled : - m_top_surface_contoning_td_effective_alpha_correction_checkbox->GetValue()); + top_surface_contoning_td_effective_alpha_correction_selected(); + } + bool top_surface_contoning_variable_layer_height_compensation_enabled() const + { + return m_top_surface_contoning_variable_layer_height_compensation_checkbox == nullptr ? + TextureMappingZone::DefaultTopSurfaceContoningVariableLayerHeightCompensationEnabled : + m_top_surface_contoning_variable_layer_height_compensation_checkbox->GetValue(); } bool minimum_visibility_offset_enabled() const { @@ -4438,43 +4497,23 @@ private: m_top_surface_contoning_color_lower_surfaces_checkbox->Show(contoning); m_top_surface_contoning_color_lower_surfaces_checkbox->Enable(contoning); } - if (m_top_surface_contoning_td_adjustment_checkbox != nullptr) { - m_top_surface_contoning_td_adjustment_checkbox->Show(contoning); - m_top_surface_contoning_td_adjustment_checkbox->Enable(contoning); - } if (m_top_surface_contoning_surface_scatter_checkbox != nullptr) { - const bool td_adjustment = - contoning && - m_top_surface_contoning_td_adjustment_checkbox != nullptr && - m_top_surface_contoning_td_adjustment_checkbox->GetValue(); + const bool td_adjustment = contoning; 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(); + top_surface_contoning_td_effective_alpha_correction_selected(); m_top_surface_contoning_surface_scatter_checkbox->Show(contoning); 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 = - 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_beer_lambert_rgb_correction_checkbox->Show(contoning); - m_top_surface_contoning_beer_lambert_rgb_correction_checkbox->Enable(td_adjustment && !td_effective_alpha); + if (m_top_surface_contoning_td_correction_choice != nullptr) { + m_top_surface_contoning_td_correction_choice->Show(contoning); + m_top_surface_contoning_td_correction_choice->Enable(contoning); } - if (m_top_surface_contoning_td_effective_alpha_correction_checkbox != nullptr) { - const bool td_adjustment = - contoning && - m_top_surface_contoning_td_adjustment_checkbox != nullptr && - m_top_surface_contoning_td_adjustment_checkbox->GetValue(); - m_top_surface_contoning_td_effective_alpha_correction_checkbox->Show(contoning); - m_top_surface_contoning_td_effective_alpha_correction_checkbox->Enable(td_adjustment); + if (m_top_surface_contoning_variable_layer_height_compensation_checkbox != nullptr) { + m_top_surface_contoning_variable_layer_height_compensation_checkbox->Show(contoning); + m_top_surface_contoning_variable_layer_height_compensation_checkbox->Enable(contoning); } if (m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox != nullptr) { m_top_surface_contoning_only_one_perimeter_around_shell_infill_checkbox->Show(contoning); @@ -4646,10 +4685,9 @@ private: wxCheckBox *m_top_surface_contoning_surface_anchored_stacks_checkbox {nullptr}; wxCheckBox *m_top_surface_contoning_surface_anchored_stack_optimizations_checkbox {nullptr}; wxCheckBox *m_top_surface_contoning_beam_search_stack_expansion_checkbox {nullptr}; - wxCheckBox *m_top_surface_contoning_td_adjustment_checkbox {nullptr}; wxCheckBox *m_top_surface_contoning_surface_scatter_checkbox {nullptr}; - wxCheckBox *m_top_surface_contoning_beer_lambert_rgb_correction_checkbox {nullptr}; - wxCheckBox *m_top_surface_contoning_td_effective_alpha_correction_checkbox {nullptr}; + wxChoice *m_top_surface_contoning_td_correction_choice {nullptr}; + wxCheckBox *m_top_surface_contoning_variable_layer_height_compensation_checkbox {nullptr}; wxCheckBox *m_use_legacy_fixed_color_mode_checkbox {nullptr}; wxCheckBox *m_minimum_visibility_offset_checkbox {nullptr}; wxSpinCtrl *m_minimum_visibility_offset_spin {nullptr}; @@ -9684,8 +9722,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) updated.top_surface_contoning_beam_search_stack_expansion_enabled, updated.top_surface_contoning_td_adjustment_enabled, updated.top_surface_contoning_surface_scatter_enabled, + updated.top_surface_contoning_color_prediction_mode, updated.top_surface_contoning_beer_lambert_rgb_correction_enabled, updated.top_surface_contoning_td_effective_alpha_correction_enabled, + updated.top_surface_contoning_variable_layer_height_compensation_enabled, shell_usage, bundle->texture_mapping_zones, bundle->texture_mapping_global_settings, @@ -9772,10 +9812,14 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) dlg.top_surface_contoning_td_adjustment_enabled(); updated.top_surface_contoning_surface_scatter_enabled = dlg.top_surface_contoning_surface_scatter_enabled(); + updated.top_surface_contoning_color_prediction_mode = + dlg.top_surface_contoning_color_prediction_mode(); updated.top_surface_contoning_beer_lambert_rgb_correction_enabled = dlg.top_surface_contoning_beer_lambert_rgb_correction_enabled(); updated.top_surface_contoning_td_effective_alpha_correction_enabled = dlg.top_surface_contoning_td_effective_alpha_correction_enabled(); + updated.top_surface_contoning_variable_layer_height_compensation_enabled = + dlg.top_surface_contoning_variable_layer_height_compensation_enabled(); if (updated.top_surface_image_printing_enabled && updated.top_surface_image_printing_method == int(TextureMappingZone::TopSurfaceImageContoning)) { updated.modulation_mode = int(TextureMappingZone::ModulationPerimeterPathV2);