From 2343e8ff2699cbb86e0814d10113394d6982100f Mon Sep 17 00:00:00 2001 From: sentientstardust Date: Wed, 6 May 2026 18:52:02 +0100 Subject: [PATCH] Another tweak to reduce edge artifacts (image projection) --- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 76 ++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 7 +- src/slic3r/GUI/MMUPaintedTexturePreview.cpp | 29 ++++--- src/slic3r/GUI/MMUPaintedTexturePreview.hpp | 6 +- 4 files changed, 95 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 5d9e92d14f0..9e484f2e2e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -3079,11 +3079,14 @@ struct ProjectionVisibility float top = 0.f; float scale = 1.f; std::vector depth; + std::vector local_depth_tolerance; std::vector triangle_keys; }; static constexpr float PROJECTION_VISIBILITY_DEPTH_TOLERANCE = 2e-4f; static constexpr float PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE = 2e-3f; +static constexpr float PROJECTION_VISIBILITY_PROJECTED_TRIANGLE_DEPTH_TOLERANCE = 2e-3f; +static constexpr float PROJECTION_VISIBILITY_MAX_LOCAL_DEPTH_TOLERANCE = 8e-3f; static constexpr uint64_t PROJECTION_VISIBILITY_INVALID_TRIANGLE_KEY = std::numeric_limits::max(); static uint64_t projection_visibility_triangle_key(size_t volume_idx, size_t tri_idx) @@ -3096,9 +3099,52 @@ static bool projection_visibility_valid(const ProjectionVisibility &visibility) return visibility.width > 0 && visibility.height > 0 && visibility.depth.size() == size_t(visibility.width) * size_t(visibility.height) && + visibility.local_depth_tolerance.size() == visibility.depth.size() && visibility.triangle_keys.size() == visibility.depth.size(); } +static void projection_visibility_prepare_local_depth_tolerances(ProjectionVisibility &visibility) +{ + visibility.local_depth_tolerance.assign(visibility.depth.size(), PROJECTION_VISIBILITY_DEPTH_TOLERANCE); + if (visibility.width <= 0 || visibility.height <= 0 || visibility.depth.size() != size_t(visibility.width) * size_t(visibility.height)) + return; + + for (int y = 0; y < visibility.height; ++y) { + for (int x = 0; x < visibility.width; ++x) { + const size_t center_idx = size_t(y) * size_t(visibility.width) + size_t(x); + const float center_nearest = visibility.depth[center_idx]; + if (!std::isfinite(center_nearest)) + continue; + + float tolerance = PROJECTION_VISIBILITY_DEPTH_TOLERANCE; + const int min_x = std::max(0, x - 1); + const int max_x = std::min(visibility.width - 1, x + 1); + const int min_y = std::max(0, y - 1); + const int max_y = std::min(visibility.height - 1, y + 1); + for (int sample_y = min_y; sample_y <= max_y; ++sample_y) { + for (int sample_x = min_x; sample_x <= max_x; ++sample_x) { + const size_t idx = size_t(sample_y) * size_t(visibility.width) + size_t(sample_x); + const float nearest = visibility.depth[idx]; + if (std::isfinite(nearest)) + tolerance = std::max(tolerance, std::abs(center_nearest - nearest) + PROJECTION_VISIBILITY_DEPTH_TOLERANCE); + } + } + visibility.local_depth_tolerance[center_idx] = std::min(tolerance, PROJECTION_VISIBILITY_MAX_LOCAL_DEPTH_TOLERANCE); + } + } +} + +static float projection_visibility_local_depth_tolerance(const ProjectionVisibility &visibility, int x, int y) +{ + if (x < 0 || y < 0 || x >= visibility.width || y >= visibility.height) + return PROJECTION_VISIBILITY_DEPTH_TOLERANCE; + + const size_t idx = size_t(y) * size_t(visibility.width) + size_t(x); + if (idx >= visibility.local_depth_tolerance.size()) + return PROJECTION_VISIBILITY_DEPTH_TOLERANCE; + return visibility.local_depth_tolerance[idx]; +} + static bool projection_visibility_depth_matches_sample(const ProjectionVisibility &visibility, int x, int y, @@ -3113,16 +3159,21 @@ static bool projection_visibility_depth_matches_sample(const ProjectionVisibilit if (!std::isfinite(center_nearest)) return false; + const bool has_triangle_key = triangle_key != PROJECTION_VISIBILITY_INVALID_TRIANGLE_KEY; const bool center_same_triangle = - triangle_key != PROJECTION_VISIBILITY_INVALID_TRIANGLE_KEY && - visibility.triangle_keys[center_idx] == triangle_key; - const float center_tolerance = - center_same_triangle ? PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE : PROJECTION_VISIBILITY_DEPTH_TOLERANCE; + has_triangle_key && visibility.triangle_keys[center_idx] == triangle_key; + const float local_tolerance = projection_visibility_local_depth_tolerance(visibility, x, y); + float center_tolerance = PROJECTION_VISIBILITY_DEPTH_TOLERANCE; + if (center_same_triangle) { + center_tolerance = std::max(PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE, local_tolerance); + } else if (has_triangle_key) { + center_tolerance = std::max(PROJECTION_VISIBILITY_PROJECTED_TRIANGLE_DEPTH_TOLERANCE, local_tolerance); + } if (depth <= center_nearest + center_tolerance) return true; - if (triangle_key == PROJECTION_VISIBILITY_INVALID_TRIANGLE_KEY || - depth > center_nearest + PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE) + if (!has_triangle_key || + depth > center_nearest + std::max(PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE, local_tolerance)) return false; const int min_x = std::max(0, x - 1); @@ -3139,7 +3190,10 @@ static bool projection_visibility_depth_matches_sample(const ProjectionVisibilit continue; const float nearest = visibility.depth[idx]; - if (std::isfinite(nearest) && depth <= nearest + PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE) + const float nearby_tolerance = + std::max(PROJECTION_VISIBILITY_SAME_TRIANGLE_DEPTH_TOLERANCE, + projection_visibility_local_depth_tolerance(visibility, sample_x, sample_y)); + if (std::isfinite(nearest) && depth <= nearest + nearby_tolerance) return true; } } @@ -3242,6 +3296,7 @@ static ProjectionVisibility build_projection_visibility(const ProjectionContext } } + projection_visibility_prepare_local_depth_tolerances(visibility); return visibility; } @@ -9227,9 +9282,10 @@ bool GLGizmoImageProjection::project_to_rgb_data(ModelObject *object) projected_triangles[tri_idx] = projected_triangle; if (projected_triangle) { projected_triangle_depths[tri_idx] = - texture_mapping_depth_from_span(projection_triangle_image_pixel_span(context, world_matrix, vertices), - projection_target_span, - 7); + std::max(1, + texture_mapping_depth_from_span(projection_triangle_image_pixel_span(context, world_matrix, vertices), + projection_target_span, + 7)); ++projected_triangle_count; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 5025056abe3..9cf65dca683 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1697,7 +1697,8 @@ void TriangleSelectorPatch::update_render_data() m_vertex_color_preview_models, m_vertex_color_preview_colors, m_vertex_color_preview_filament_ids, - m_texture_mapping_color_preview); + m_texture_mapping_color_preview, + reinterpret_cast(this)); } else { if (model_volume_has_texture_preview_data_for_painting(*m_model_volume)) { build_mmu_texture_preview_models(*m_model_volume, @@ -1718,7 +1719,9 @@ void TriangleSelectorPatch::update_render_data() texture_mgr, m_vertex_color_preview_models, m_vertex_color_preview_colors, - m_vertex_color_preview_filament_ids); + m_vertex_color_preview_filament_ids, + nullptr, + reinterpret_cast(this)); } } diff --git a/src/slic3r/GUI/MMUPaintedTexturePreview.cpp b/src/slic3r/GUI/MMUPaintedTexturePreview.cpp index eea67135a62..7601a23ceaf 100644 --- a/src/slic3r/GUI/MMUPaintedTexturePreview.cpp +++ b/src/slic3r/GUI/MMUPaintedTexturePreview.cpp @@ -1840,8 +1840,8 @@ bool texture_preview_simulation_is_pending_impl() } if (entry->ready_geometry.has_value()) { - pending = true; if (!entry->ready_generation_reported) { + pending = true; ++texture_preview_vertex_color_simulation_generation(); entry->ready_generation_reported = true; } @@ -2461,10 +2461,14 @@ size_t texture_preview_color_facets_source_signature(const ModelVolume return signature; } -size_t texture_preview_vertex_color_simulation_cache_key(const ModelVolume &model_volume, unsigned int filament_id, size_t source_kind) +size_t texture_preview_vertex_color_simulation_cache_key(const ModelVolume &model_volume, + unsigned int filament_id, + size_t source_kind, + size_t preview_owner_key) { size_t key = texture_preview_simulation_cache_key(model_volume, filament_id); key ^= std::hash{}(source_kind) + 0x9e3779b97f4a7c15ull + (key << 6) + (key >> 2); + key ^= std::hash{}(preview_owner_key) + 0x9e3779b97f4a7c15ull + (key << 6) + (key >> 2); return key; } @@ -2514,6 +2518,7 @@ bool build_simulated_vertex_color_preview_model_for_state( const std::vector &state_triangles, unsigned int filament_id, const TexturePreviewSimulationSettings &simulation_settings, + size_t preview_owner_key, GUI::GLModel &out_model) { if (!model_volume_has_vertex_color_preview_data(model_volume) || state_triangles.empty()) @@ -2521,7 +2526,7 @@ bool build_simulated_vertex_color_preview_model_for_state( const size_t source_signature = texture_preview_vertex_color_source_signature(model_volume, state_triangles); const size_t simulation_signature = texture_preview_simulation_signature(model_volume, source_signature, simulation_settings); - const size_t cache_key = texture_preview_vertex_color_simulation_cache_key(model_volume, filament_id, 1u); + const size_t cache_key = texture_preview_vertex_color_simulation_cache_key(model_volume, filament_id, 1u, preview_owner_key); std::shared_ptr mesh = model_volume.mesh_ptr(); std::vector vertex_colors(model_volume.imported_vertex_colors_rgba.begin(), model_volume.imported_vertex_colors_rgba.end()); std::vector triangles = state_triangles; @@ -2555,7 +2560,8 @@ bool build_simulated_texture_mapping_color_preview_model_for_state( unsigned int filament_id, const TexturePreviewSimulationSettings &simulation_settings, GUI::GLModel &out_model, - const ColorFacetsAnnotation *texture_mapping_color_facets_override = nullptr) + const ColorFacetsAnnotation *texture_mapping_color_facets_override = nullptr, + size_t preview_owner_key = 0) { const ColorFacetsAnnotation *color_source = texture_mapping_color_facets_override; if (color_source == nullptr || color_source->empty()) @@ -2565,7 +2571,7 @@ bool build_simulated_texture_mapping_color_preview_model_for_state( const size_t source_signature = texture_preview_color_facets_source_signature(model_volume, *color_source, state_triangles); const size_t simulation_signature = texture_preview_simulation_signature(model_volume, source_signature, simulation_settings); - const size_t cache_key = texture_preview_vertex_color_simulation_cache_key(model_volume, filament_id, 2u); + const size_t cache_key = texture_preview_vertex_color_simulation_cache_key(model_volume, filament_id, 2u, preview_owner_key); std::shared_ptr mesh = model_volume.mesh_ptr(); std::shared_ptr color_source_copy = ColorFacetsAnnotation::make_temporary(); color_source_copy->assign(*color_source); @@ -3195,7 +3201,8 @@ bool build_mmu_vertex_color_preview_models( std::vector &out_models, std::vector &out_colors, std::vector &out_filament_ids, - const ColorFacetsAnnotation *texture_mapping_color_facets_override) + const ColorFacetsAnnotation *texture_mapping_color_facets_override, + size_t preview_owner_key) { out_models.clear(); out_colors.clear(); @@ -3258,7 +3265,8 @@ bool build_mmu_vertex_color_preview_models( filament_id, *simulation_settings, model, - preview_override)) + preview_override, + preview_owner_key)) continue; } else { if (!build_texture_mapping_color_preview_model_for_state(model_volume, @@ -3274,6 +3282,7 @@ bool build_mmu_vertex_color_preview_models( triangles_per_type[state_id], filament_id, *simulation_settings, + preview_owner_key, model)) continue; } else { @@ -3302,7 +3311,8 @@ bool build_mmu_vertex_color_preview_models( std::vector &out_models, std::vector &out_colors, std::vector &out_filament_ids, - const ColorFacetsAnnotation *texture_mapping_color_facets_override) + const ColorFacetsAnnotation *texture_mapping_color_facets_override, + size_t preview_owner_key) { return build_mmu_vertex_color_preview_models(model_volume, triangles_per_type, @@ -3314,7 +3324,8 @@ bool build_mmu_vertex_color_preview_models( out_models, out_colors, out_filament_ids, - texture_mapping_color_facets_override); + texture_mapping_color_facets_override, + preview_owner_key); } size_t model_volume_texture_preview_signature(const ModelVolume &model_volume) diff --git a/src/slic3r/GUI/MMUPaintedTexturePreview.hpp b/src/slic3r/GUI/MMUPaintedTexturePreview.hpp index 8b05a1dd16c..359c224feba 100644 --- a/src/slic3r/GUI/MMUPaintedTexturePreview.hpp +++ b/src/slic3r/GUI/MMUPaintedTexturePreview.hpp @@ -38,7 +38,8 @@ bool build_mmu_vertex_color_preview_models( std::vector &out_models, std::vector &out_colors, std::vector &out_filament_ids, - const ColorFacetsAnnotation *texture_mapping_color_facets_override = nullptr); + const ColorFacetsAnnotation *texture_mapping_color_facets_override = nullptr, + size_t preview_owner_key = 0); bool build_mmu_vertex_color_preview_models( const ModelVolume &model_volume, @@ -50,7 +51,8 @@ bool build_mmu_vertex_color_preview_models( std::vector &out_models, std::vector &out_colors, std::vector &out_filament_ids, - const ColorFacetsAnnotation *texture_mapping_color_facets_override = nullptr); + const ColorFacetsAnnotation *texture_mapping_color_facets_override = nullptr, + size_t preview_owner_key = 0); size_t model_volume_texture_preview_signature(const ModelVolume &model_volume); size_t model_volume_texture_mapping_color_preview_signature(const ModelVolume &model_volume);