diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index de24838217..be29229b67 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -352,6 +352,8 @@ bool ToolOrdering::insert_wipe_tower_extruder() bool changed = false; const unsigned int wipe_extruder = (unsigned int)(m_print_config_ptr->wipe_tower_filament - 1); for (LayerTools < : m_layer_tools) { + if (lt.has_texture_mapping_zone && lt.extruders.size() <= 1) + continue; if (lt.wipe_tower_partitions > 0) { if (std::find(lt.extruders.begin(), lt.extruders.end(), wipe_extruder) == lt.extruders.end()) { lt.extruders.emplace_back(wipe_extruder); @@ -718,6 +720,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto // Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it. layer_tools.extruder_override = extruder_override; + auto append_layer_filament = [&layer_tools](unsigned int filament_id) { + if (layer_tools.texture_mapping_manager != nullptr && layer_tools.texture_mapping_manager->is_texture_mapping_zone_id(filament_id)) + layer_tools.has_texture_mapping_zone = true; + layer_tools.extruders.emplace_back(layer_tools.resolve_filament_id(filament_id)); + }; // What extruders are required to print this object layer? for (const LayerRegion *layerm : layer->regions()) { @@ -735,7 +742,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto if (something_nonoverriddable){ const unsigned int filament_id = (extruder_override == 0) ? region.config().wall_filament.value : extruder_override; - layer_tools.extruders.emplace_back(layer_tools.resolve_filament_id(filament_id)); + append_layer_filament(filament_id); if (layerCount == 0) { firstLayerExtruders.emplace_back(layer_tools.resolve_filament_id(filament_id)); } @@ -765,11 +772,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto if (something_nonoverriddable || !m_print_config_ptr) { if (extruder_override == 0) { if (has_solid_infill) - layer_tools.extruders.emplace_back(layer_tools.resolve_filament_id(region.config().solid_infill_filament)); + append_layer_filament(region.config().solid_infill_filament); if (has_infill) - layer_tools.extruders.emplace_back(layer_tools.resolve_filament_id(region.config().sparse_infill_filament)); + append_layer_filament(region.config().sparse_infill_filament); } else if (has_solid_infill || has_infill) - layer_tools.extruders.emplace_back(layer_tools.resolve_filament_id(extruder_override)); + append_layer_filament(extruder_override); } if (has_solid_infill || has_infill) layer_tools.has_object = true; diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 534cbc8ab2..0747ec6ae4 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -151,6 +151,7 @@ public: int layer_index = 0; size_t num_physical_filaments = 0; const TextureMappingManager *texture_mapping_manager = nullptr; + bool has_texture_mapping_zone = false; bool has_object = false; bool has_support = false; // Zero based extruder IDs, ordered to minimize tool switches. diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 2be60aa04e..57e037e43c 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -1256,6 +1256,19 @@ static float prime_tower_flow_scale_for_width(float reference_width, float targe return std::clamp(target_area / reference_area, 0.05f, 4.f); } +static void prime_tower_append_texture_tool(std::vector &tools, size_t tool, size_t tool_count) +{ + if (tool >= tool_count) + return; + if (std::find(tools.begin(), tools.end(), tool) == tools.end()) + tools.emplace_back(tool); +} + +static bool prime_tower_path_explicitly_closed(const std::vector& points) +{ + return points.size() > 2 && (points.front() - points.back()).norm() <= EPSILON; +} + struct PrimeTowerPreparedTexturePath { std::vector points; @@ -1341,9 +1354,11 @@ static float prime_tower_texture_anchor_angle(const std::vector &points, static PrimeTowerPreparedTexturePath prime_tower_prepare_texture_path(WipeTowerWriter &writer, const std::vector &points, + bool closed_path, const Vec2f ¢er, float angle_deg) { + const bool explicit_closed = prime_tower_path_explicitly_closed(points); if (points.size() < 2) { std::vector sample_points; sample_points.reserve(points.size()); @@ -1351,9 +1366,19 @@ static PrimeTowerPreparedTexturePath prime_tower_prepare_texture_path(WipeTowerW sample_points.emplace_back(writer.point_rotated(point)); return {points, sample_points, 0.f}; } + if (!closed_path && !explicit_closed) { + std::vector sample_points; + sample_points.reserve(points.size()); + for (const Vec2f &point : points) + sample_points.emplace_back(writer.point_rotated(point)); + return {points, + sample_points, + prime_tower_texture_anchor_distance( + sample_points, sample_points.size() - 1, center, prime_tower_texture_anchor_angle(sample_points, angle_deg))}; + } std::vector unique_points(points.begin(), points.end()); - if (unique_points.size() > 2 && (unique_points.front() - unique_points.back()).norm() <= EPSILON) + if (explicit_closed) unique_points.pop_back(); if (unique_points.size() < 2) { std::vector sample_points; @@ -1365,36 +1390,48 @@ static PrimeTowerPreparedTexturePath prime_tower_prepare_texture_path(WipeTowerW if (prime_tower_polygon_area(unique_points) < 0.f) std::reverse(unique_points.begin(), unique_points.end()); + std::vector ordered = std::move(unique_points); + if (!closed_path) + ordered.emplace_back(ordered.front()); + const size_t segment_count = closed_path ? ordered.size() : ordered.size() - 1; std::vector sample_points; - sample_points.reserve(unique_points.size()); - for (const Vec2f &point : unique_points) + sample_points.reserve(ordered.size()); + for (const Vec2f &point : ordered) sample_points.emplace_back(writer.point_rotated(point)); - const float anchor_distance = - prime_tower_texture_anchor_distance(sample_points, sample_points.size(), center, prime_tower_texture_anchor_angle(sample_points, angle_deg)); - return {std::move(unique_points), std::move(sample_points), anchor_distance}; + return {std::move(ordered), + std::move(sample_points), + prime_tower_texture_anchor_distance(sample_points, segment_count, center, prime_tower_texture_anchor_angle(sample_points, angle_deg))}; } -static void prime_tower_textured_closed_path(WipeTowerWriter &writer, - const PrimeTowerTextureRenderSettings &texture, - const std::vector &points, - const Vec2f &texture_center, - float feedrate, - float extrusion_flow, - float reference_width, - float layer_height, - float print_z, - size_t current_tool) +static void prime_tower_textured_path(WipeTowerWriter &writer, + const PrimeTowerTextureRenderSettings &texture, + const std::vector &points, + bool closed_path, + const Vec2f &texture_center, + float feedrate, + float extrusion_flow, + float reference_width, + float layer_height, + float print_z, + size_t current_tool, + const std::vector &normalization_tools) { if (!texture.valid() || points.size() < 2) return; const PrimeTowerPreparedTexturePath texture_path = prime_tower_prepare_texture_path( - writer, points, texture_center, std::clamp(texture.angle_offset_deg, 0.f, 360.f)); + writer, points, closed_path, texture_center, std::clamp(texture.angle_offset_deg, 0.f, 360.f)); const std::vector& texture_points = texture_path.points; const std::vector& sample_points = texture_path.sample_points; + const size_t segment_count = closed_path ? texture_points.size() : texture_points.size() - 1; + if (segment_count == 0) + return; + float total_length = 0.f; - for (size_t i = 0; i < sample_points.size(); ++i) - total_length += (sample_points[(i + 1) % sample_points.size()] - sample_points[i]).norm(); + for (size_t i = 0; i < segment_count; ++i) { + const size_t next_i = i + 1 == sample_points.size() ? 0 : i + 1; + total_length += (sample_points[next_i] - sample_points[i]).norm(); + } if (total_length <= EPSILON) return; @@ -1413,11 +1450,14 @@ static void prime_tower_textured_closed_path(WipeTowerWriter &writer, float travelled = 0.f; bool have_shifted_pos = false; Vec2f shifted_pos = writer.pos(); - for (size_t i = 0; i < texture_points.size(); ++i) { + float last_analyzer_width = reference_width; + bool analyzer_width_changed = false; + for (size_t i = 0; i < segment_count; ++i) { + const size_t next_i = i + 1 == texture_points.size() ? 0 : i + 1; const Vec2f a = texture_points[i]; - const Vec2f b = texture_points[(i + 1) % texture_points.size()]; + const Vec2f b = texture_points[next_i]; const Vec2f sample_a = sample_points[i]; - const Vec2f sample_b = sample_points[(i + 1) % sample_points.size()]; + const Vec2f sample_b = sample_points[next_i]; const Vec2f delta = b - a; const Vec2f sample_delta = sample_b - sample_a; const float len = delta.norm(); @@ -1433,7 +1473,7 @@ static void prime_tower_textured_closed_path(WipeTowerWriter &writer, const float t1 = float(step + 1) / float(steps); const float mid_distance = travelled + sample_len * (0.5f * (t0 + t1)); const float u = (mid_distance - texture_path.anchor_distance) / total_length; - const float visibility = texture.sample_tool_visibility(current_tool, u, v); + const float visibility = texture.sample_tool_visibility(current_tool, u, v, normalization_tools); const float target_width = base_width - (1.f - visibility) * width_range; const float flow_scale = prime_tower_flow_scale_for_width(reference_width, target_width, layer_height); const float centerline_shift = 0.5f * (base_width - reference_width) + 0.5f * (base_width - target_width); @@ -1444,11 +1484,72 @@ static void prime_tower_textured_closed_path(WipeTowerWriter &writer, shifted_pos = p0; have_shifted_pos = true; } + if (std::abs(target_width - last_analyzer_width) > 0.001f) { + writer.change_analyzer_line_width(target_width); + last_analyzer_width = target_width; + analyzer_width_changed = true; + } writer.extrude_explicit(p1, (p1 - p0).norm() * extrusion_flow * flow_scale, feedrate, true); shifted_pos = p1; } travelled += sample_len; } + if (analyzer_width_changed && std::abs(last_analyzer_width - reference_width) > 0.001f) + writer.change_analyzer_line_width(reference_width); +} + +static void prime_tower_textured_closed_path(WipeTowerWriter &writer, + const PrimeTowerTextureRenderSettings &texture, + const std::vector &points, + const Vec2f &texture_center, + float feedrate, + float extrusion_flow, + float reference_width, + float layer_height, + float print_z, + size_t current_tool, + const std::vector &normalization_tools) +{ + prime_tower_textured_path( + writer, + texture, + points, + true, + texture_center, + feedrate, + extrusion_flow, + reference_width, + layer_height, + print_z, + current_tool, + normalization_tools); +} + +static void prime_tower_textured_open_path(WipeTowerWriter &writer, + const PrimeTowerTextureRenderSettings &texture, + const std::vector &points, + const Vec2f &texture_center, + float feedrate, + float extrusion_flow, + float reference_width, + float layer_height, + float print_z, + size_t current_tool, + const std::vector &normalization_tools) +{ + prime_tower_textured_path( + writer, + texture, + points, + false, + texture_center, + feedrate, + extrusion_flow, + reference_width, + layer_height, + print_z, + current_tool, + normalization_tools); } static bool prime_tower_textured_rectangle(WipeTowerWriter &writer, @@ -1459,7 +1560,8 @@ static bool prime_tower_textured_rectangle(WipeTowerWriter &writer, float reference_width, float layer_height, float print_z, - size_t current_tool) + size_t current_tool, + const std::vector &normalization_tools) { if (!texture.valid()) return false; @@ -1485,7 +1587,17 @@ static bool prime_tower_textured_rectangle(WipeTowerWriter &writer, ordered.emplace_back(corners[(index_of_closest + i) % 4]); const Vec2f texture_center = writer.point_rotated(ld + Vec2f(width * 0.5f, height * 0.5f)); prime_tower_textured_closed_path( - writer, texture, ordered, texture_center, feedrate, extrusion_flow, reference_width, layer_height, print_z, current_tool); + writer, + texture, + ordered, + texture_center, + feedrate, + extrusion_flow, + reference_width, + layer_height, + print_z, + current_tool, + normalization_tools); return true; } @@ -2638,6 +2750,17 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); wt_box = align_perimeter(wt_box); + std::vector texture_normalization_tools; + if (m_prime_tower_texture.valid()) { + const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); + if (m_layer_info != m_plan.end()) { + for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); + } + } + } if (extrude_perimeter) { if (!m_prime_tower_texture.valid() || !prime_tower_textured_rectangle(writer, @@ -2648,7 +2771,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool m_perimeter_width, m_layer_height, m_z_pos, - m_current_tool)) + m_current_tool, + texture_normalization_tools)) writer.rectangle(wt_box, feedrate); } @@ -2710,13 +2834,19 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool } // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box -void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, - unsigned int new_tool, float wipe_volume, float purge_volume) +void WipeTower::plan_toolchange(float z_par, + float layer_height_par, + unsigned int old_tool, + unsigned int new_tool, + float wipe_volume, + float purge_volume, + bool texture_mapping_single_component_layer) { assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first m_plan.push_back(WipeTowerInfo(z_par, layer_height_par)); + m_plan.back().texture_mapping_single_component_layer |= texture_mapping_single_component_layer; if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool)) m_first_layer_idx = m_plan.size() - 1; @@ -4176,6 +4306,8 @@ void WipeTower::generate_new(std::vector int { if (layer.tool_changes.size() == 0) return -1; + if (m_prime_tower_texture.valid() && layer.texture_mapping_single_component_layer && layer.tool_changes.size() == 1) + return layer.tool_changes.front().new_tool; int candidate_id = -1; for (size_t idx = 0; idx < layer.tool_changes.size(); ++idx) { @@ -4582,7 +4714,55 @@ Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_ result_wall.push_back(to_polyline(wall_polygon)); insert_skip_polygon = wall_polygon; } - writer.generate_path(result_wall, feedrate, retract_length, retract_speed,m_used_fillet); + bool textured_path_written = false; + if (m_prime_tower_texture.valid() && result_wall.size() == 1 && !result_wall.front().points.empty()) { + std::vector texture_normalization_tools; + const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); + if (m_layer_info != m_plan.end()) { + for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); + } + } + const bool closed_texture_path = !rib_wall && !skip_points; + std::vector points; + points.reserve(result_wall.front().points.size()); + for (const Point &point : result_wall.front().points) + points.emplace_back(unscaled(point)); + if (closed_texture_path && points.size() > 1 && (points.front() - points.back()).norm() <= EPSILON) + points.pop_back(); + if (points.size() > 1) { + const Vec2f texture_center = writer.point_rotated((wt_box.ld + wt_box.ru) / 2.f); + if (closed_texture_path) + prime_tower_textured_closed_path(writer, + m_prime_tower_texture, + points, + texture_center, + float(feedrate), + m_extrusion_flow, + m_perimeter_width, + m_layer_height, + m_z_pos, + m_current_tool, + texture_normalization_tools); + else + prime_tower_textured_open_path(writer, + m_prime_tower_texture, + points, + texture_center, + float(feedrate), + m_extrusion_flow, + m_perimeter_width, + m_layer_height, + m_z_pos, + m_current_tool, + texture_normalization_tools); + textured_path_written = true; + } + } + if (!textured_path_written) + writer.generate_path(result_wall, feedrate, retract_length, retract_speed,m_used_fillet); if (m_cur_layer_id == 0) { BoundingBox bbox = get_extents(result_wall); m_rib_offset = Vec2f(-unscaled(bbox.min.x()), -unscaled(bbox.min.y())); diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index a4d8de988f..c334e3b17f 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -62,6 +62,27 @@ struct PrimeTowerTextureRenderSettings } float sample_tool_visibility(size_t tool, float u, float v) const + { + return sample_tool_visibility_raw(tool, u, v); + } + + float sample_tool_visibility(size_t tool, float u, float v, const std::vector &normalization_tools) const + { + const float raw_visibility = sample_tool_visibility_raw(tool, u, v); + if (normalization_tools.empty()) + return raw_visibility; + + float max_visibility = std::clamp(raw_visibility, 0.f, 1.f); + for (const size_t normalization_tool : normalization_tools) + max_visibility = std::max(max_visibility, std::clamp(sample_tool_visibility_raw(normalization_tool, u, v), 0.f, 1.f)); + + return max_visibility > 1e-6f ? + std::clamp(raw_visibility / max_visibility, 0.f, 1.f) : + std::clamp(raw_visibility, 0.f, 1.f); + } + +private: + float sample_tool_visibility_raw(size_t tool, float u, float v) const { if (!valid()) return 1.f; @@ -79,7 +100,6 @@ struct PrimeTowerTextureRenderSettings return sample_image_tool_visibility(tool, u, v, use_back); } -private: bool image_valid(bool back) const { return back ? @@ -413,7 +433,13 @@ public: // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. - void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume = 0.f, float prime_volume = 0.f); + void plan_toolchange(float z_par, + float layer_height_par, + unsigned int old_tool, + unsigned int new_tool, + float wipe_volume = 0.f, + float prime_volume = 0.f, + bool texture_mapping_single_component_layer = false); // Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result" void generate(std::vector> &result); @@ -775,6 +801,7 @@ private: float depth; // depth of the layer based on all layers above float extra_spacing; bool extruder_fill{true}; + bool texture_mapping_single_component_layer{false}; float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; } std::vector tool_changes; diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index bcc3e44763..2b50d2b803 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -1235,6 +1235,14 @@ static float prime_tower_flow_scale_for_width(float reference_width, float targe return std::clamp(target_area / reference_area, 0.05f, 4.f); } +static void prime_tower_append_texture_tool(std::vector &tools, size_t tool, size_t tool_count) +{ + if (tool >= tool_count) + return; + if (std::find(tools.begin(), tools.end(), tool) == tools.end()) + tools.emplace_back(tool); +} + static bool prime_tower_path_explicitly_closed(const std::vector& points) { return points.size() > 2 && (points.front() - points.back()).norm() <= EPSILON; @@ -1384,7 +1392,8 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, float reference_width, float layer_height, float print_z, - size_t current_tool) + size_t current_tool, + const std::vector& normalization_tools) { if (!texture.valid() || points.size() < 2) return; @@ -1420,6 +1429,8 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, float travelled = 0.f; bool have_shifted_pos = false; Vec2f shifted_pos = writer.pos(); + float last_analyzer_width = reference_width; + bool analyzer_width_changed = false; for (size_t i = 0; i < segment_count; ++i) { const size_t next_i = i + 1 == texture_points.size() ? 0 : i + 1; const Vec2f a = texture_points[i]; @@ -1441,7 +1452,7 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, const float t1 = float(step + 1) / float(steps); const float mid_distance = travelled + sample_len * (0.5f * (t0 + t1)); const float u = (mid_distance - texture_path.anchor_distance) / total_length; - const float visibility = texture.sample_tool_visibility(current_tool, u, v); + const float visibility = texture.sample_tool_visibility(current_tool, u, v, normalization_tools); const float target_width = base_width - (1.f - visibility) * width_range; const float flow_scale = prime_tower_flow_scale_for_width(reference_width, target_width, layer_height); const float centerline_shift = 0.5f * (base_width - reference_width) + 0.5f * (base_width - target_width); @@ -1452,11 +1463,18 @@ static void prime_tower_textured_path(WipeTowerWriter2& writer, shifted_pos = p0; have_shifted_pos = true; } + if (std::abs(target_width - last_analyzer_width) > 0.001f) { + writer.change_analyzer_line_width(target_width); + last_analyzer_width = target_width; + analyzer_width_changed = true; + } writer.extrude_explicit(p1, (p1 - p0).norm() * extrusion_flow * flow_scale, feedrate, true); shifted_pos = p1; } travelled += sample_len; } + if (analyzer_width_changed && std::abs(last_analyzer_width - reference_width) > 0.001f) + writer.change_analyzer_line_width(reference_width); } static void prime_tower_textured_closed_path(WipeTowerWriter2& writer, @@ -1468,10 +1486,22 @@ static void prime_tower_textured_closed_path(WipeTowerWriter2& writer, float reference_width, float layer_height, float print_z, - size_t current_tool) + size_t current_tool, + const std::vector& normalization_tools) { prime_tower_textured_path( - writer, texture, points, true, texture_center, feedrate, extrusion_flow, reference_width, layer_height, print_z, current_tool); + writer, + texture, + points, + true, + texture_center, + feedrate, + extrusion_flow, + reference_width, + layer_height, + print_z, + current_tool, + normalization_tools); } static void prime_tower_textured_open_path(WipeTowerWriter2& writer, @@ -1483,10 +1513,22 @@ static void prime_tower_textured_open_path(WipeTowerWriter2& writer, float reference_width, float layer_height, float print_z, - size_t current_tool) + size_t current_tool, + const std::vector& normalization_tools) { prime_tower_textured_path( - writer, texture, points, false, texture_center, feedrate, extrusion_flow, reference_width, layer_height, print_z, current_tool); + writer, + texture, + points, + false, + texture_center, + feedrate, + extrusion_flow, + reference_width, + layer_height, + print_z, + current_tool, + normalization_tools); } @@ -2804,6 +2846,15 @@ Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& } bool textured_path_written = false; if (m_prime_tower_texture.valid() && result_wall.size() == 1 && !result_wall.front().points.empty()) { + std::vector texture_normalization_tools; + const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); + if (m_layer_info != m_plan.end()) { + for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); + } + } const bool closed_texture_path = !rib_wall && !skip_points; std::vector points; points.reserve(result_wall.front().points.size()); @@ -2823,7 +2874,8 @@ Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& m_perimeter_width, m_layer_height, m_z_pos, - m_current_tool); + m_current_tool, + texture_normalization_tools); else prime_tower_textured_open_path(writer, m_prime_tower_texture, @@ -2834,7 +2886,8 @@ Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& m_perimeter_width, m_layer_height, m_z_pos, - m_current_tool); + m_current_tool, + texture_normalization_tools); textured_path_written = true; } } @@ -2933,6 +2986,15 @@ Polygon WipeTower2::generate_support_cone_wall( } } if (m_prime_tower_texture.valid() && polylines.empty()) { + std::vector texture_normalization_tools; + const size_t texture_tool_count = m_prime_tower_texture.filament_colours.size(); + prime_tower_append_texture_tool(texture_normalization_tools, m_current_tool, texture_tool_count); + if (m_layer_info != m_plan.end()) { + for (const WipeTowerInfo::ToolChange &tool_change : m_layer_info->tool_changes) { + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.old_tool, texture_tool_count); + prime_tower_append_texture_tool(texture_normalization_tools, tool_change.new_tool, texture_tool_count); + } + } std::vector ordered; ordered.reserve(pts.size()); for (size_t j = 0; j < pts.size(); ++j) @@ -2947,7 +3009,8 @@ Polygon WipeTower2::generate_support_cone_wall( m_perimeter_width, m_layer_height, m_z_pos, - m_current_tool); + m_current_tool, + texture_normalization_tools); return poly; } diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 0067284a82..571299b513 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1367,7 +1367,7 @@ static inline std::vector> segmentation_top_and_bottom_l unsigned(std::max(0, config.wall_filament.value)) : unsigned(color_idx); if (filament_id_uses_texture_mapping(print, queried_filament_id)) - outer_wall_line_width = std::max(0.05, config.texture_mapping_outer_wall_gradient_max_line_width.value); + outer_wall_line_width = std::max(0.05, print.config().texture_mapping_outer_wall_gradient_max_line_width.value); out.extrusion_width = std::max(out.extrusion_width, outer_wall_line_width); out.top_shell_layers = std::max(out.top_shell_layers, config.top_shell_layers); out.bottom_shell_layers = std::max(out.bottom_shell_layers, config.bottom_shell_layers); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6557a32cd5..c2346ea41c 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -50,6 +50,51 @@ using namespace nlohmann; namespace Slic3r { +static void append_used_physical_extruders_for_filament_id(const TextureMappingManager &texture_mapping_manager, + int filament_id, + size_t num_physical, + const std::vector &filament_colours, + std::vector &extruders) +{ + if (filament_id <= 0 || num_physical == 0) + return; + + auto append_physical = [num_physical, &extruders](unsigned int physical_id) { + if (physical_id >= 1 && physical_id <= num_physical) + extruders.emplace_back(physical_id - 1); + }; + + const TextureMappingZone *zone = texture_mapping_manager.zone_from_id(unsigned(filament_id)); + if (zone != nullptr) { + if (!zone->enabled || zone->deleted) + return; + + std::vector colors = filament_colours; + colors.resize(num_physical, "#FFFFFF"); + std::vector component_ids = zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, num_physical, colors) : + TextureMappingManager::selected_component_ids(*zone, num_physical); + + component_ids.erase(std::remove_if(component_ids.begin(), + component_ids.end(), + [num_physical](unsigned int id) { return id == 0 || id > num_physical; }), + component_ids.end()); + std::sort(component_ids.begin(), component_ids.end()); + component_ids.erase(std::unique(component_ids.begin(), component_ids.end()), component_ids.end()); + + if (component_ids.empty()) { + const unsigned int resolved = texture_mapping_manager.resolve_zone_component(unsigned(filament_id), num_physical, 0); + append_physical(resolved); + } else { + for (unsigned int component_id : component_ids) + append_physical(component_id); + } + return; + } + + append_physical(unsigned(filament_id)); +} + static std::array prime_tower_parse_hex_color_for_print(const std::string &hex) { auto hex_byte = [](char hi, char lo) { @@ -601,17 +646,15 @@ std::vector Print::object_extruders() const for (const PrintObject* object : m_objects) { const ModelObject* mo = object->model_object(); const size_t num_physical = m_config.filament_colour.size(); - auto resolve_filament_id = [this, num_physical](int filament_id) { - if (filament_id > 0 && m_texture_mapping_mgr.is_texture_mapping_zone_id(unsigned(filament_id))) - return int(m_texture_mapping_mgr.resolve_zone_component(unsigned(filament_id), num_physical, 0)); - return filament_id; - }; for (const ModelVolume* mv : mo->volumes) { std::vector volume_extruders = mv->get_extruders(); for (int extruder : volume_extruders) { - extruder = resolve_filament_id(extruder); assert(extruder > 0); - extruders.push_back(extruder - 1); + append_used_physical_extruders_for_filament_id(m_texture_mapping_mgr, + extruder, + num_physical, + m_config.filament_colour.values, + extruders); } } @@ -622,9 +665,11 @@ std::vector Print::object_extruders() const //Don't know why height range always save key "extruder" because of no change(should only save difference)... //Add protection here to avoid overflow auto value = layer_range.second.option("extruder")->getInt(); - value = resolve_filament_id(value); - if (value > 0) - extruders.push_back(value - 1); + append_used_physical_extruders_for_filament_id(m_texture_mapping_mgr, + value, + num_physical, + m_config.filament_colour.values, + extruders); } } } @@ -680,11 +725,11 @@ std::vector Print::extruders(bool conside_custom_gcode) const for (auto item : m_model.plates_custom_gcodes.at(m_model.curr_plate_index).gcodes) { if (item.type != CustomGCode::Type::ToolChange || item.extruder <= 0) continue; - int extruder_id = item.extruder; - if (m_texture_mapping_mgr.is_texture_mapping_zone_id(unsigned(extruder_id))) - extruder_id = int(m_texture_mapping_mgr.resolve_zone_component(unsigned(extruder_id), num_physical, 0)); - if (extruder_id > 0 && extruder_id <= int(num_physical)) - extruders.push_back((unsigned int)(extruder_id - 1)); + append_used_physical_extruders_for_filament_id(m_texture_mapping_mgr, + item.extruder, + num_physical, + m_config.filament_colour.values, + extruders); } } } @@ -3376,23 +3421,9 @@ void Print::_make_wipe_tower() texture.enabled = true; texture.generic_fallback_for_missing_channels = auto_mode; texture.angle_offset_deg = m_texture_mapping_global_settings.angle_offset_deg; - float texture_global_strength_pct = float(m_default_region_config.texture_mapping_outer_wall_gradient_global_strength.value); - float texture_max_line_width = float(m_default_region_config.texture_mapping_outer_wall_gradient_max_line_width.value); - float texture_min_line_width = float(m_default_region_config.texture_mapping_outer_wall_gradient_min_line_width.value); - for (const PrintRegion *region : m_print_regions) { - if (region == nullptr) - continue; - const PrintRegionConfig ®ion_config = region->config(); - texture_global_strength_pct = std::max(texture_global_strength_pct, - float(region_config.texture_mapping_outer_wall_gradient_global_strength.value)); - texture_max_line_width = std::max(texture_max_line_width, - float(region_config.texture_mapping_outer_wall_gradient_max_line_width.value)); - texture_min_line_width = std::min(texture_min_line_width, - float(region_config.texture_mapping_outer_wall_gradient_min_line_width.value)); - } - texture.global_strength = std::clamp(texture_global_strength_pct / 100.f, 0.f, 1.f); - texture.max_line_width = std::max(0.05f, texture_max_line_width); - texture.min_line_width = std::max(0.05f, texture_min_line_width); + texture.global_strength = std::clamp(float(m_config.texture_mapping_outer_wall_gradient_global_strength.value) / 100.f, 0.f, 1.f); + texture.max_line_width = std::max(0.05f, float(m_config.texture_mapping_outer_wall_gradient_max_line_width.value)); + texture.min_line_width = std::max(0.05f, float(m_config.texture_mapping_outer_wall_gradient_min_line_width.value)); texture.image_rgba = m_texture_mapping_prime_tower_image.rgba; texture.image_width = m_texture_mapping_prime_tower_image.width; texture.image_height = m_texture_mapping_prime_tower_image.height; @@ -3462,7 +3493,13 @@ void Print::_make_wipe_tower() for (auto& layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); - wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_filament_id, current_filament_id); + wipe_tower.plan_toolchange((float) layer_tools.print_z, + (float) layer_tools.wipe_tower_layer_height, + current_filament_id, + current_filament_id, + 0.f, + 0.f, + layer_tools.has_texture_mapping_zone && layer_tools.extruders.size() == 1); used_filament_ids.insert(layer_tools.extruders.begin(), layer_tools.extruders.end()); diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 6abe79654a..5e41f6b554 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1,9 +1,11 @@ #include "ClipperUtils.hpp" #include "Model.hpp" #include "Print.hpp" +#include "TextureMapping.hpp" #include #include +#include #include namespace Slic3r { @@ -1175,6 +1177,96 @@ static PrintObjectRegions* generate_print_object_regions( return out.release(); } +static inline void append_unique_painted_extruder(std::vector &painting_extruders, + unsigned int extruder_id, + size_t num_physical_extruders) +{ + if (extruder_id < 1 || extruder_id > num_physical_extruders) + return; + if (std::find(painting_extruders.begin(), painting_extruders.end(), extruder_id) == painting_extruders.end()) + painting_extruders.emplace_back(extruder_id); +} + +static void append_texture_mapping_component_extruders(const TextureMappingManager &texture_mgr, + unsigned int state_id, + size_t num_physical_extruders, + const std::vector &filament_colours, + std::vector &painting_extruders) +{ + const TextureMappingZone *zone = texture_mgr.zone_from_id(state_id); + if (zone == nullptr || !zone->enabled || zone->deleted) + return; + + const std::vector component_ids = zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, num_physical_extruders, filament_colours) : + TextureMappingManager::selected_component_ids(*zone, num_physical_extruders); + for (const unsigned int id : component_ids) + append_unique_painted_extruder(painting_extruders, id, num_physical_extruders); +} + +static void append_used_filament_from_config_id(const TextureMappingManager &texture_mgr, + int filament_id, + size_t num_physical_extruders, + const std::vector &filament_colours, + std::vector &used_filaments) +{ + if (filament_id <= 0 || num_physical_extruders == 0) + return; + + auto append_physical = [num_physical_extruders, &used_filaments](unsigned int physical_id) { + if (physical_id >= 1 && physical_id <= num_physical_extruders) + used_filaments.emplace_back(physical_id - 1); + }; + + const TextureMappingZone *zone = texture_mgr.zone_from_id(unsigned(filament_id)); + if (zone != nullptr) { + if (!zone->enabled || zone->deleted) + return; + + std::vector component_ids = zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, num_physical_extruders, filament_colours) : + TextureMappingManager::selected_component_ids(*zone, num_physical_extruders); + component_ids.erase(std::remove_if(component_ids.begin(), + component_ids.end(), + [num_physical_extruders](unsigned int id) { return id == 0 || id > num_physical_extruders; }), + component_ids.end()); + std::sort(component_ids.begin(), component_ids.end()); + component_ids.erase(std::unique(component_ids.begin(), component_ids.end()), component_ids.end()); + + if (component_ids.empty()) { + const unsigned int resolved = texture_mgr.resolve_zone_component(unsigned(filament_id), num_physical_extruders, 0); + append_physical(resolved); + } else { + for (unsigned int component_id : component_ids) + append_physical(component_id); + } + return; + } + + append_physical(unsigned(filament_id)); +} + +static void append_model_used_filaments_for_normalization(const Model &model, + const TextureMappingManager &texture_mgr, + size_t num_physical_extruders, + const std::vector &filament_colours, + std::vector &used_filaments) +{ + for (const ModelObject *object : model.objects) { + for (const ModelVolume *volume : object->volumes) + for (int extruder : volume->get_extruders()) + append_used_filament_from_config_id(texture_mgr, extruder, num_physical_extruders, filament_colours, used_filaments); + + for (const auto &layer_range : object->layer_config_ranges) + if (layer_range.second.has("extruder")) + append_used_filament_from_config_id(texture_mgr, + layer_range.second.option("extruder")->getInt(), + num_physical_extruders, + filament_colours, + used_filaments); + } +} + Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config) { #ifdef _DEBUG @@ -1192,6 +1284,23 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // BBS std::vector used_filaments = this->extruders(true); + std::vector normalization_filament_colours; + if (const ConfigOptionStrings *color_opt = new_full_config.option("filament_colour", false); color_opt != nullptr) + normalization_filament_colours = color_opt->values; + else + normalization_filament_colours = m_config.filament_colour.values; + if (const ConfigOptionFloats *diameter_opt = new_full_config.option("filament_diameter", false); diameter_opt != nullptr) + normalization_filament_colours.resize(std::max(normalization_filament_colours.size(), diameter_opt->values.size()), "#FFFFFF"); + + TextureMappingManager normalization_texture_mgr; + normalization_texture_mgr.load_entries(new_full_config.opt_string("texture_mapping_definitions"), normalization_filament_colours); + append_model_used_filaments_for_normalization(model, + normalization_texture_mgr, + normalization_filament_colours.size(), + normalization_filament_colours, + used_filaments); + std::sort(used_filaments.begin(), used_filaments.end()); + used_filaments.erase(std::unique(used_filaments.begin(), used_filaments.end()), used_filaments.end()); std::unordered_set used_filament_set(used_filaments.begin(), used_filaments.end()); //new_full_config.normalize_fdm(used_filaments); @@ -1252,13 +1361,16 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ //BBS: process the filament_map related logic std::unordered_set print_diff_set(print_diff.begin(), print_diff.end()); + auto erase_full_config_diff = [&full_config_diff](const char *key) { + full_config_diff.erase(std::remove(full_config_diff.begin(), full_config_diff.end(), key), full_config_diff.end()); + }; if (print_diff_set.find("filament_map_mode") == print_diff_set.end()) { FilamentMapMode map_mode = new_full_config.option>("filament_map_mode", true)->value; if (map_mode < fmmManual) { if (print_diff_set.find("filament_map") != print_diff_set.end()) { print_diff_set.erase("filament_map"); - //full_config_diff.erase("filament_map"); + erase_full_config_diff("filament_map"); ConfigOptionInts* old_opt = m_full_print_config.option("filament_map", true); ConfigOptionInts* new_opt = new_full_config.option("filament_map", true); old_opt->set(new_opt); @@ -1283,8 +1395,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ break; } } - if (same_map) + if (same_map) { print_diff_set.erase("filament_map"); + erase_full_config_diff("filament_map"); + } } } if (print_diff_set.size() != print_diff.size()) @@ -1347,6 +1461,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } } + std::vector physical_filament_colors = m_config.filament_colour.values; + physical_filament_colors.resize(num_extruders, "#FFFFFF"); + m_texture_mapping_mgr.load_entries(new_full_config.opt_string("texture_mapping_definitions"), physical_filament_colors); + const size_t num_total_filaments = m_texture_mapping_mgr.total_filaments(num_extruders); + ModelObjectStatusDB model_object_status_db; // 1) Synchronize model objects. @@ -1535,7 +1654,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ if (object_config_changed) model_object.config.assign_config(model_object_new.config); if (! object_diff.empty() || object_config_changed || num_extruders_changed ) { - PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders ); + PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_total_filaments); for (const PrintObjectStatus &print_object_status : print_object_status_db.get_range(model_object)) { t_config_option_keys diff = print_object_status.print_object->config().diff(new_config); if (! diff.empty()) { @@ -1601,10 +1720,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Generate a list of trafos and XY offsets for instances of a ModelObject // Producing the config for PrintObject on demand, caching it at print_object_last. const PrintObject *print_object_last = nullptr; - auto print_object_apply_config = [this, &print_object_last, model_object, num_extruders ](PrintObject *print_object) { + auto print_object_apply_config = [this, &print_object_last, model_object, num_total_filaments](PrintObject *print_object) { print_object->config_apply(print_object_last ? print_object_last->config() : - PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders )); + PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_total_filaments)); print_object_last = print_object; }; if (old.empty()) { @@ -1678,7 +1797,15 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } //BBS: check the config again - int new_used_filaments = this->extruders(true).size(); + std::vector new_used_filaments_values = this->extruders(true); + append_model_used_filaments_for_normalization(model, + normalization_texture_mgr, + normalization_filament_colours.size(), + normalization_filament_colours, + new_used_filaments_values); + std::sort(new_used_filaments_values.begin(), new_used_filaments_values.end()); + new_used_filaments_values.erase(std::unique(new_used_filaments_values.begin(), new_used_filaments_values.end()), new_used_filaments_values.end()); + int new_used_filaments = int(new_used_filaments_values.size()); t_config_option_keys new_changed_keys = new_full_config.normalize_fdm_2(objects().size(), new_used_filaments); if (new_changed_keys.size() > 0) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", got new_changed_keys, size=%1%")%new_changed_keys.size(); @@ -1735,7 +1862,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ std::vector painting_extruders; if (const auto &volumes = print_object.model_object()->volumes; num_extruders > 1 && - std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return ! v->mmu_segmentation_facets.empty(); }) != volumes.end()) { + std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return !v->mmu_segmentation_facets.empty(); }) != volumes.end()) { std::array(EnforcerBlockerType::ExtruderMax) + 1> used_facet_states{}; for (const ModelVolume *volume : volumes) { @@ -1747,9 +1874,17 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } for (size_t state_idx = static_cast(EnforcerBlockerType::Extruder1); state_idx < used_facet_states.size(); ++state_idx) { - if (used_facet_states[state_idx]) - painting_extruders.emplace_back(state_idx); + if (!used_facet_states[state_idx] || state_idx > num_total_filaments) + continue; + painting_extruders.emplace_back(state_idx); + append_texture_mapping_component_extruders(m_texture_mapping_mgr, + static_cast(state_idx), + num_extruders, + physical_filament_colors, + painting_extruders); } + std::sort(painting_extruders.begin(), painting_extruders.end()); + painting_extruders.erase(std::unique(painting_extruders.begin(), painting_extruders.end()), painting_extruders.end()); } if (model_object_status.print_object_regions_status == ModelObjectStatus::PrintObjectRegionsStatus::Valid) { // Verify that the trafo for regions & volume bounding boxes thus for regions is still applicable. @@ -1767,7 +1902,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ verify_update_print_object_regions( print_object.model_object()->volumes, m_default_region_config, - num_extruders, + num_total_filaments, *print_object_regions, [it_print_object, it_print_object_end, &update_apply_status](const PrintRegionConfig &old_config, const PrintRegionConfig &new_config, const t_config_option_keys &diff_keys) { for (auto it = it_print_object; it != it_print_object_end; ++it) @@ -1792,7 +1927,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ LayerRanges(print_object.model_object()->layer_config_ranges), m_default_region_config, model_object_status.print_instances.front().trafo, - num_extruders , + num_total_filaments, print_object.is_mm_painted() ? 0.f : float(print_object.config().xy_contour_compensation.value), painting_extruders, print_object.is_fuzzy_skin_painted()); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ef3ab1d19b..15079a3a04 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1118,9 +1118,6 @@ PRINT_CONFIG_CLASS_DEFINE( // Detect bridging perimeters ((ConfigOptionBool, detect_overhang_wall)) ((ConfigOptionInt, wall_filament)) - ((ConfigOptionFloat, texture_mapping_outer_wall_gradient_global_strength)) - ((ConfigOptionFloat, texture_mapping_outer_wall_gradient_max_line_width)) - ((ConfigOptionFloat, texture_mapping_outer_wall_gradient_min_line_width)) ((ConfigOptionFloatOrPercent, inner_wall_line_width)) ((ConfigOptionFloat, inner_wall_speed)) // Total number of perimeters. @@ -1493,6 +1490,9 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionBool, ooze_prevention)) ((ConfigOptionString, filename_format)) ((ConfigOptionStrings, post_process)) + ((ConfigOptionFloat, texture_mapping_outer_wall_gradient_global_strength)) + ((ConfigOptionFloat, texture_mapping_outer_wall_gradient_max_line_width)) + ((ConfigOptionFloat, texture_mapping_outer_wall_gradient_min_line_width)) ((ConfigOptionString, printer_model)) ((ConfigOptionFloat, resolution)) ((ConfigOptionFloats, retraction_minimum_travel)) diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 5d428e5835..6148533a5a 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -137,20 +137,8 @@ static std::vector collect_texture_mapping_outer_wall_gradient_line if (!has_offset_profiles) return {}; - if (print_object.num_printing_regions() == 0) - return {}; - - float max_gradient_line_width_mm = 0.f; - float min_gradient_line_width_mm = std::numeric_limits::max(); - for (size_t region_id = 0; region_id < print_object.num_printing_regions(); ++region_id) { - const PrintRegionConfig ®ion_cfg = print_object.printing_region(region_id).config(); - max_gradient_line_width_mm = std::max(max_gradient_line_width_mm, - float(region_cfg.texture_mapping_outer_wall_gradient_max_line_width.value)); - min_gradient_line_width_mm = std::min(min_gradient_line_width_mm, - float(region_cfg.texture_mapping_outer_wall_gradient_min_line_width.value)); - } - max_gradient_line_width_mm = std::max(0.f, max_gradient_line_width_mm); - min_gradient_line_width_mm = std::max(0.f, min_gradient_line_width_mm); + const float max_gradient_line_width_mm = std::max(0.f, float(print->config().texture_mapping_outer_wall_gradient_max_line_width.value)); + const float min_gradient_line_width_mm = std::max(0.f, float(print->config().texture_mapping_outer_wall_gradient_min_line_width.value)); std::vector warnings; warnings.reserve(2); diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 0bab40bb8f..3dac848218 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -2,6 +2,8 @@ #include "Print.hpp" #include "TextureMapping.hpp" +#include + namespace Slic3r { static bool filament_id_uses_texture_mapping(const Print &print, unsigned int filament_id) @@ -17,6 +19,53 @@ static bool filament_id_uses_texture_mapping(const Print &print, unsigned int fi return zone != nullptr && zone->enabled && !zone->deleted && zone->is_image_texture(); } +static void append_used_physical_extruders_for_filament_id(const Print &print, + int filament_id, + std::vector &object_extruders) +{ + if (filament_id <= 0) + return; + + const size_t num_physical = print.config().filament_colour.size(); + if (num_physical == 0) + return; + + auto append_physical = [num_physical, &object_extruders](unsigned int physical_id) { + if (physical_id >= 1 && physical_id <= num_physical) + object_extruders.emplace_back(physical_id - 1); + }; + + const TextureMappingZone *zone = print.texture_mapping_manager().zone_from_id(unsigned(filament_id)); + if (zone != nullptr) { + if (!zone->enabled || zone->deleted) + return; + + std::vector colors = print.config().filament_colour.values; + colors.resize(num_physical, "#FFFFFF"); + std::vector component_ids = zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, num_physical, colors) : + TextureMappingManager::selected_component_ids(*zone, num_physical); + + component_ids.erase(std::remove_if(component_ids.begin(), + component_ids.end(), + [num_physical](unsigned int id) { return id == 0 || id > num_physical; }), + component_ids.end()); + std::sort(component_ids.begin(), component_ids.end()); + component_ids.erase(std::unique(component_ids.begin(), component_ids.end()), component_ids.end()); + + if (component_ids.empty()) { + const unsigned int resolved = print.texture_mapping_manager().resolve_zone_component(unsigned(filament_id), num_physical, 0); + append_physical(resolved); + } else { + for (unsigned int component_id : component_ids) + append_physical(component_id); + } + return; + } + + append_physical(unsigned(filament_id)); +} + // 1-based extruder identifier for this region and role. unsigned int PrintRegion::extruder(FlowRole role) const { @@ -41,7 +90,7 @@ Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_he if (role == frExternalPerimeter && filament_id_uses_texture_mapping(*object.print(), unsigned(std::max(0, m_config.wall_filament.value)))) { config_width = ConfigOptionFloatOrPercent( - std::max(0.05, m_config.texture_mapping_outer_wall_gradient_max_line_width.value), + std::max(0.05, print_config.texture_mapping_outer_wall_gradient_max_line_width.value), false); } else if (first_layer && print_config.initial_layer_line_width.value > 0) { config_width = print_config.initial_layer_line_width; @@ -108,17 +157,12 @@ void PrintRegion::collect_object_printing_extruders(const Print &print, std::vec assert(this->config().sparse_infill_filament <= num_extruders || print.texture_mapping_manager().is_texture_mapping_zone_id(this->config().sparse_infill_filament)); assert(this->config().solid_infill_filament <= num_extruders || print.texture_mapping_manager().is_texture_mapping_zone_id(this->config().solid_infill_filament)); #endif - PrintRegionConfig config = this->config(); - const size_t num_physical = print.config().filament_colour.size(); - auto resolve_filament_id = [&print, num_physical](int filament_id) { - if (filament_id > 0 && print.texture_mapping_manager().is_texture_mapping_zone_id(unsigned(filament_id))) - return int(print.texture_mapping_manager().resolve_zone_component(unsigned(filament_id), num_physical, 0)); - return filament_id; - }; - config.wall_filament.value = resolve_filament_id(config.wall_filament.value); - config.sparse_infill_filament.value = resolve_filament_id(config.sparse_infill_filament.value); - config.solid_infill_filament.value = resolve_filament_id(config.solid_infill_filament.value); - collect_object_printing_extruders(print.config(), config, print.has_brim(), object_extruders); + if (this->config().wall_loops.value > 0 || print.has_brim()) + append_used_physical_extruders_for_filament_id(print, this->config().wall_filament.value, object_extruders); + if (this->config().sparse_infill_density.value > 0) + append_used_physical_extruders_for_filament_id(print, this->config().sparse_infill_filament.value, object_extruders); + if (this->config().top_shell_layers.value > 0 || this->config().bottom_shell_layers.value > 0) + append_used_physical_extruders_for_filament_id(print, this->config().solid_infill_filament.value, object_extruders); } } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index bb07c99172..8a1b41c8b1 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -635,7 +635,11 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size) } //BBS add render for simple case -void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors, bool ban_light) +void GLVolume::simple_render(GLShaderProgram* shader, + ModelObjectPtrs& model_objects, + std::vector& extruder_colors, + bool ban_light, + bool suppress_texture_preview_base) { if (this->is_left_handed()) glFrontFace(GL_CW); @@ -645,7 +649,9 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj ModelObject* model_object = nullptr; ModelVolume* model_volume = nullptr; unsigned int base_filament_id = 0; + bool base_uses_texture_preview = false; bool use_original_mesh_texture_preview = false; + bool texture_preview_base_suppressed = false; do { if ((!printable) || object_idx() >= model_objects.size()) break; @@ -659,7 +665,7 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj &GUI::wxGetApp().preset_bundle->texture_mapping_zones : nullptr; base_filament_id = model_volume->extruder_id() > 0 ? unsigned(model_volume->extruder_id()) : 0u; const bool has_mmu_segmentation = !model_volume->mmu_segmentation_facets.empty(); - const bool base_uses_texture_preview = filament_state_uses_texture_preview(base_filament_id, num_physical, texture_mgr); + base_uses_texture_preview = filament_state_uses_texture_preview(base_filament_id, num_physical, texture_mgr); const bool base_uses_surface_gradient_preview = filament_state_uses_surface_gradient_preview(base_filament_id, num_physical, texture_mgr); const bool base_uses_image_texture_preview = base_uses_texture_preview && !base_uses_surface_gradient_preview; @@ -765,9 +771,17 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj mmuseg_ts = model_volume->mmu_segmentation_facets.timestamp(); mmuseg_texture_preview_visual_signature = preview_visual_signature; } + texture_preview_base_suppressed = suppress_texture_preview_base && + !picking && + base_uses_texture_preview && + (use_original_mesh_texture_preview || !mmuseg_texture_preview_models.empty() || !mmuseg_vertex_color_preview_models.empty()); } while (0); - if (color_volume && !picking) { + if (texture_preview_base_suppressed) { + if (this->is_left_handed()) + glFrontFace(GL_CCW); + return; + } else if (color_volume && !picking) { // when force_transparent, we need to keep the alpha if (force_native_color && render_color.is_transparent()) { for (auto &extruder_color : extruder_colors) @@ -835,7 +849,8 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, const std::array &clipping_plane, int print_volume_type, const std::array &print_volume_xy, - const std::array &print_volume_z) + const std::array &print_volume_z, + bool opaque) { if (picking || !printable || object_idx() < 0 || volume_idx() < 0) return; @@ -923,7 +938,8 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, this->tverts_range, print_volume_type, print_volume_xy, - print_volume_z); + print_volume_z, + opaque); } else { render_model_texture_preview_models(mmuseg_texture_preview_models, adjusted_preview_colors(mmuseg_texture_preview_colors), @@ -939,7 +955,8 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, clipping_plane, print_volume_type, print_volume_xy, - print_volume_z); + print_volume_z, + opaque); } } @@ -956,7 +973,8 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, clipping_plane, print_volume_type, print_volume_xy, - print_volume_z); + print_volume_z, + opaque); } if (this->is_left_handed()) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index d49fecee2b..51ef252b71 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -358,14 +358,19 @@ public: virtual void render_with_outline(const GUI::Size& cnv_size); //BBS: add simple render function for thumbnail - void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors, bool ban_light =false); + void simple_render(GLShaderProgram* shader, + ModelObjectPtrs& model_objects, + std::vector& extruder_colors, + bool ban_light = false, + bool suppress_texture_preview_base = false); void render_mmu_texture_preview(const Transform3d &view_matrix, const Transform3d &projection_matrix, const std::array &z_range, const std::array &clipping_plane, int print_volume_type = -1, const std::array &print_volume_xy = std::array{ 0.f, 0.f, 0.f, 0.f }, - const std::array &print_volume_z = std::array{ 0.f, 0.f }); + const std::array &print_volume_z = std::array{ 0.f, 0.f }, + bool opaque = false); void invalidate_texture_mapping_preview(); void set_bounding_boxes_as_dirty() { diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index a805a5c240..6cb1244752 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -273,7 +273,7 @@ AboutDialog::AboutDialog() std::vector text_list; text_list.push_back(_L("Open-source slicing stands on a tradition of collaboration and attribution. Slic3r, created by Alessandro Ranellucci and the RepRap community, laid the foundation. PrusaSlicer by Prusa Research built on that work, Bambu Studio forked from PrusaSlicer, and SuperSlicer extended it with community-driven enhancements. Each project carried the work of its predecessors forward, crediting those who came before.")); text_list.push_back(_L("OrcaSlicer began in that same spirit, drawing from PrusaSlicer, BambuStudio, SuperSlicer, and CuraSlicer. But it has since grown far beyond its origins — introducing advanced calibration tools, precise wall and seam control and hundreds of other features.")); - text_list.push_back(_L("Orca Slicer ImageMap integrates image texture mapping changes on top of the OrcaSlicer codebase.")); + text_list.push_back(_L("OrcaSlicer ImageMap integrates image texture mapping changes into the OrcaSlicer codebase.")); text_list.push_back(_L("Today, OrcaSlicer is the most widely used and actively developed open-source slicer in the 3D printing community. Many of its innovations have been adopted by other slicers, making it a driving force for the entire industry.")); text_sizer->Add( 0, 0, 0, wxTOP, FromDIP(33)); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 678a99deb5..1a3e3c7abf 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1134,15 +1134,13 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const // release gpu memory, if used reset(); - //BBS: add mutex for protection of gcode result - wxGetApp().plater()->suppress_background_process(true); + SuppressBackgroundProcessingUpdate background_update_guard; gcode_result.lock(); //BBS: add safe check if (gcode_result.moves.size() == 0) { //result cleaned before slicing ,should return here BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": gcode result reset before, return directly!"); gcode_result.unlock(); - wxGetApp().plater()->schedule_background_process(); return; } @@ -1440,7 +1438,6 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const filament_printable_reuslt = gcode_result.filament_printable_reuslt; //BBS: add mutex for protection of gcode result gcode_result.unlock(); - wxGetApp().plater()->schedule_background_process(); } void GCodeViewer::load_as_preview(libvgcode::GCodeInputData&& data) @@ -4515,4 +4512,3 @@ void GCodeViewer::render_slider(int canvas_width, int canvas_height) { } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c850591f37..2653b9b7c1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6276,6 +6276,8 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const shader->start_using(); shader->set_uniform("emission_factor", 0.1f); shader->set_uniform("ban_light", ban_light); + const bool render_texture_previews = !ban_light && &model_objects == &GUI::wxGetApp().model().objects; + std::vector texture_preview_volumes; for (GLVolume* vol : visible_volumes) { //BBS set render color for thumbnails curr_color = vol->color; @@ -6302,10 +6304,28 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const shader->set_uniform("projection_matrix", projection_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - vol->simple_render(shader, model_objects, extruder_colors, ban_light); + const bool render_model_texture_preview = + render_texture_previews && vol->object_idx() >= 0 && vol->volume_idx() >= 0 && !vol->is_wipe_tower && + !vol->is_modifier && !vol->is_extrusion_path; + vol->simple_render(shader, model_objects, extruder_colors, ban_light, render_model_texture_preview); + if (render_model_texture_preview) + texture_preview_volumes.emplace_back(vol); vol->is_active = is_active; } shader->stop_using(); + if (!texture_preview_volumes.empty()) { + const std::array z_range = { -FLT_MAX, FLT_MAX }; + const std::array clipping_plane = { 0.f, 0.f, 0.f, 0.f }; + for (GLVolume *vol : texture_preview_volumes) + vol->render_mmu_texture_preview(view_matrix, + projection_matrix, + z_range, + clipping_plane, + -1, + { 0.f, 0.f, 0.f, 0.f }, + { 0.f, 0.f }, + true); + } } glsafe(::glDisable(GL_DEPTH_TEST)); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e67bcf7e42..f650a28f74 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10855,6 +10855,14 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice) if (!no_slice && !this->model.objects.empty() && !export_in_progress && model_fits && current_has_print_instances) { + if (current_plate->is_slice_result_valid() && this->background_process.finished()) { + if (model_fits) + this->preview->reload_print(); + else + this->update_fff_scene_only_shells(); + preview->set_as_dirty(); + return; + } //if already running in background, not relice here //BBS: add more judge for slicing if (!this->background_process.running() && !this->m_is_slicing)