From 6974962dd02b5c1e5e13de3caa29749735ef0e11 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 14 Mar 2023 08:21:38 +0100 Subject: [PATCH] Avoid updating and sending to gpu sequential print clearance contours at every frame. Cache them instead and update only their transforms. Fixed conflicts after cherry-picking e99ee946afbaf6e6db9413ccacdd03233c4743d1 --- src/libslic3r/Print.cpp | 4 +- src/libslic3r/Print.hpp | 6 +- src/slic3r/GUI/GLCanvas3D.cpp | 165 +++++++++++++++++----- src/slic3r/GUI/GLCanvas3D.hpp | 32 ++++- src/slic3r/GUI/GLModel.cpp | 32 +++++ src/slic3r/GUI/GLModel.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 + src/slic3r/GUI/Plater.cpp | 10 +- 8 files changed, 200 insertions(+), 52 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4c5d7b851..7e196c85f 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -469,13 +469,13 @@ std::string Print::validate(std::string* warning) const return _u8L("The supplied settings will cause an empty print."); if (m_config.complete_objects) { - if (!sequential_print_horizontal_clearance_valid(*this, const_cast(&m_sequential_print_clearance_polygons))) + if (!sequential_print_horizontal_clearance_valid(*this, const_cast(&m_sequential_print_clearance_contours))) return _u8L("Some objects are too close; your extruder will collide with them."); if (!sequential_print_vertical_clearance_valid(*this)) return _u8L("Some objects are too tall and cannot be printed without extruder collisions."); } else - const_cast(&m_sequential_print_clearance_polygons)->clear(); + const_cast(&m_sequential_print_clearance_contours)->clear(); if (m_config.avoid_crossing_perimeters && m_config.avoid_crossing_curled_overhangs) { return _u8L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together."); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ba0a448c7..c96b0ca9a 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -609,7 +609,7 @@ public: const PrintRegion& get_print_region(size_t idx) const { return *m_print_regions[idx]; } const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; } - const Polygons& get_sequential_print_clearance_polygons() const { return m_sequential_print_clearance_polygons; } + const Polygons& get_sequential_print_clearance_contours() const { return m_sequential_print_clearance_contours; } static bool sequential_print_horizontal_clearance_valid(const Print& print, Polygons* polygons = nullptr); protected: @@ -659,8 +659,8 @@ private: // Estimated print time, filament consumed. PrintStatistics m_print_statistics; - // Cache to store sequential print clearance polygons - Polygons m_sequential_print_clearance_polygons; + // Cache to store sequential print clearance contours + Polygons m_sequential_print_clearance_contours; // To allow GCode to set the Print's GCodeExport step status. friend class GCode; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fc2e04d5a..3b1b73b81 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -880,20 +880,22 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas ImGui::PopStyleVar(2); } -void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons) +void GLCanvas3D::SequentialPrintClearance::set_contours(const ContoursList& contours) { - m_perimeter.reset(); + m_contours.clear(); + m_instances.clear(); m_fill.reset(); - if (polygons.empty()) + + if (contours.empty()) return; if (m_render_fill) { GLModel::Geometry fill_data; fill_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; - fill_data.color = { 0.3333f, 0.0f, 0.0f, 0.5f }; + fill_data.color = { 0.3333f, 0.0f, 0.0f, 0.5f }; // vertices + indices - const ExPolygons polygons_union = union_ex(polygons); + const ExPolygons polygons_union = union_ex(contours.contours); unsigned int vertices_counter = 0; for (const ExPolygon& poly : polygons_union) { const std::vector triangulation = triangulate_expolygon_3d(poly); @@ -906,17 +908,42 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons fill_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } } - m_fill.init_from(std::move(fill_data)); } - m_perimeter.init_from(polygons, 0.025f); // add a small positive z to avoid z-fighting + for (size_t i = 0; i < contours.contours.size(); ++i) { + GLModel& model = m_contours.emplace_back(GLModel()); + model.init_from(contours.contours[i], 0.025f); // add a small positive z to avoid z-fighting + } + + if (contours.trafos.has_value()) { + // create the requested instances + for (const auto& instance : contours.trafos.value()) { + m_instances.emplace_back(instance.first, instance.second); + } + } + else { + // no instances have been specified + // create one instance for every polygon + for (size_t i = 0; i < contours.contours.size(); ++i) { + m_instances.emplace_back(i, Transform3f::Identity()); + } + } +} + +void GLCanvas3D::SequentialPrintClearance::update_instances_trafos(const std::vector& trafos) +{ + assert(trafos.size() == m_instances.size()); + for (size_t i = 0; i < trafos.size(); ++i) { + m_instances[i].second = trafos[i]; + } } void GLCanvas3D::SequentialPrintClearance::render() { - const ColorRGBA FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f }; - const ColorRGBA NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f }; + const ColorRGBA FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f }; + const ColorRGBA NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f }; + const ColorRGBA NO_FILL_EVALUATING_COLOR = { 1.0f, 1.0f, 0.0f, 1.0f }; GLShaderProgram* shader = wxGetApp().get_shader("flat"); if (shader == nullptr) @@ -933,9 +960,34 @@ void GLCanvas3D::SequentialPrintClearance::render() glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - m_perimeter.set_color(m_render_fill ? FILL_COLOR : NO_FILL_COLOR); - m_perimeter.render(); - m_fill.render(); + if (m_render_fill) + m_fill.render(); + +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + + for (const auto& [id, trafo] : m_instances) { + shader->set_uniform("view_model_matrix", camera.get_view_matrix() * trafo); + assert(id < m_contours.size()); + m_contours[id].set_color(m_render_fill ? FILL_COLOR : m_evaluating ? NO_FILL_EVALUATING_COLOR : NO_FILL_COLOR); + m_contours[id].render(); + } glsafe(::glDisable(GL_BLEND)); glsafe(::glEnable(GL_CULL_FACE)); @@ -3945,7 +3997,11 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) if (wipe_tower_origin != Vec3d::Zero()) post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin))); - reset_sequential_print_clearance(); + if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects) { + m_sequential_print_clearance_first_displacement = true; + update_sequential_clearance(); + m_sequential_print_clearance.set_evaluating(true); + } m_dirty = true; } @@ -4030,6 +4086,12 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) if (!done.empty()) post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED)); + if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects) { + m_sequential_print_clearance_first_displacement = true; + update_sequential_clearance(); + m_sequential_print_clearance.set_evaluating(true); + } + m_dirty = true; } @@ -4102,6 +4164,12 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) if (!done.empty()) post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_SCALED)); + if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects) { + m_sequential_print_clearance_first_displacement = true; + update_sequential_clearance(); + m_sequential_print_clearance.set_evaluating(true); + } + m_dirty = true; } @@ -4378,7 +4446,7 @@ void GLCanvas3D::update_sequential_clearance() return; // collects instance transformations from volumes - // first define temporary cache + // first: define temporary cache unsigned int instances_count = 0; std::vector>> instance_transforms; for (size_t obj = 0; obj < m_model->objects.size(); ++obj) { @@ -4393,7 +4461,7 @@ void GLCanvas3D::update_sequential_clearance() if (instances_count == 1) return; - // second fill temporary cache with data from volumes + // second: fill temporary cache with data from volumes for (const GLVolume* v : m_volumes.volumes) { if (v->is_modifier || v->is_wipe_tower) continue; @@ -4403,14 +4471,24 @@ void GLCanvas3D::update_sequential_clearance() transform = v->get_instance_transformation(); } + // helper function to calculate the transformation to be applied to the sequential print clearance contours + auto instance_trafo = [](const Transform3d& hull_trafo, const Geometry::Transformation& inst_trafo) { + Vec3d offset = inst_trafo.get_offset() - hull_trafo.translation(); + offset.z() = 0.0; + return Geometry::translation_transform(offset) * + Geometry::rotation_transform(Geometry::rotation_diff_z(hull_trafo, inst_trafo.get_matrix()) * Vec3d::UnitZ()); + }; + + set_sequential_print_clearance_render_fill(false); + // calculates objects 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid()) // this is done only the first time this method is called while moving the mouse, // the results are then cached for following displacements if (m_sequential_print_clearance_first_displacement) { - m_sequential_print_clearance.m_hull_2d_cache.clear(); + m_sequential_print_clearance.m_hulls_2d_cache.clear(); const float shrink_factor = static_cast(scale_(0.5 * fff_print()->config().extruder_clearance_radius.value - EPSILON)); const double mitter_limit = scale_(0.1); - m_sequential_print_clearance.m_hull_2d_cache.reserve(m_model->objects.size()); + m_sequential_print_clearance.m_hulls_2d_cache.reserve(m_model->objects.size()); for (size_t i = 0; i < m_model->objects.size(); ++i) { ModelObject* model_object = m_model->objects[i]; ModelInstance* model_instance0 = model_object->instances.front(); @@ -4422,38 +4500,51 @@ void GLCanvas3D::update_sequential_clearance() shrink_factor, jtRound, mitter_limit).front(); - Pointf3s& cache_hull_2d = m_sequential_print_clearance.m_hull_2d_cache.emplace_back(Pointf3s()); - cache_hull_2d.reserve(hull_2d.points.size()); + Pointf3s& new_hull_2d = m_sequential_print_clearance.m_hulls_2d_cache.emplace_back(std::make_pair(Pointf3s(), trafo.get_matrix())).first; + new_hull_2d.reserve(hull_2d.points.size()); const Transform3d inv_trafo = trafo.get_matrix().inverse(); for (const Point& p : hull_2d.points) { - cache_hull_2d.emplace_back(inv_trafo * Vec3d(unscale(p.x()), unscale(p.y()), 0.0)); + new_hull_2d.emplace_back(Vec3d(unscale(p.x()), unscale(p.y()), 0.0)); } } + + ContoursList contours; + contours.contours.reserve(instance_transforms.size()); + contours.trafos = std::vector>(); + contours.trafos.value().reserve(instances_count); + for (size_t i = 0; i < instance_transforms.size(); ++i) { + const auto& [hull, hull_trafo] = m_sequential_print_clearance.m_hulls_2d_cache[i]; + Points hull_pts; + hull_pts.reserve(hull.size()); + for (size_t j = 0; j < hull.size(); ++j) { + hull_pts.emplace_back(scaled(hull[j].x()), scaled(hull[j].y())); + } + contours.contours.emplace_back(Geometry::convex_hull(std::move(hull_pts))); + + const auto& instances = instance_transforms[i]; + for (const auto& instance : instances) { + contours.trafos.value().emplace_back(i, instance_trafo(hull_trafo, instance.value())); + } + } + + set_sequential_print_clearance_contours(contours); m_sequential_print_clearance_first_displacement = false; } - - // calculates instances 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid()) - Polygons polygons; - polygons.reserve(instances_count); - for (size_t i = 0; i < instance_transforms.size(); ++i) { - const auto& instances = instance_transforms[i]; - for (const auto& instance : instances) { - const Transform3d& trafo = instance->get_matrix(); - const Pointf3s& hull_2d = m_sequential_print_clearance.m_hull_2d_cache[i]; - Points inst_pts; - inst_pts.reserve(hull_2d.size()); - for (size_t j = 0; j < hull_2d.size(); ++j) { - const Vec3d p = trafo * hull_2d[j]; - inst_pts.emplace_back(scaled(p.x()), scaled(p.y())); + else { + std::vector trafos; + trafos.reserve(instances_count); + for (size_t i = 0; i < instance_transforms.size(); ++i) { + const auto& [hull, hull_trafo] = m_sequential_print_clearance.m_hulls_2d_cache[i]; + const auto& instances = instance_transforms[i]; + for (const auto& instance : instances) { + trafos.emplace_back(instance_trafo(hull_trafo, instance.value())); } - polygons.emplace_back(Geometry::convex_hull(std::move(inst_pts))); } + m_sequential_print_clearance.update_instances_trafos(trafos); } // sends instances 2d hulls to be rendered set_sequential_print_clearance_visible(true); - set_sequential_print_clearance_render_fill(false); - set_sequential_print_clearance_polygons(polygons); } bool GLCanvas3D::is_object_sinking(int object_idx) const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 38dcdb8b8..f82076d57 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -618,22 +618,38 @@ public: return ret; } + struct ContoursList + { + // list of unique contours + Polygons contours; + // if defined: list of transforms to apply to contours + std::optional>> trafos; + + bool empty() const { return contours.empty(); } + }; + private: void load_arrange_settings(); class SequentialPrintClearance { GLModel m_fill; - GLModel m_perimeter; + // list of unique contours + std::vector m_contours; + // list of transforms used to render the contours + std::vector> m_instances; bool m_render_fill{ true }; bool m_visible{ false }; + bool m_evaluating{ false }; - std::vector m_hull_2d_cache; + std::vector> m_hulls_2d_cache; public: - void set_polygons(const Polygons& polygons); + void set_contours(const ContoursList& contours); + void update_instances_trafos(const std::vector& trafos); void set_render_fill(bool render_fill) { m_render_fill = render_fill; } void set_visible(bool visible) { m_visible = visible; } + void set_evaluating(bool evaluating) { m_evaluating = evaluating; } void render(); friend class GLCanvas3D; @@ -960,7 +976,7 @@ public: void reset_sequential_print_clearance() { m_sequential_print_clearance.set_visible(false); m_sequential_print_clearance.set_render_fill(false); - m_sequential_print_clearance.set_polygons(Polygons()); + m_sequential_print_clearance.set_contours(ContoursList()); } void set_sequential_print_clearance_visible(bool visible) { @@ -971,8 +987,12 @@ public: m_sequential_print_clearance.set_render_fill(render_fill); } - void set_sequential_print_clearance_polygons(const Polygons& polygons) { - m_sequential_print_clearance.set_polygons(polygons); + void set_sequential_print_clearance_contours(const ContoursList& contours) { + m_sequential_print_clearance.set_contours(contours); + } + + void set_sequential_print_clearance_evaluating(bool evaluating) { + m_sequential_print_clearance.set_evaluating(evaluating); } void update_sequential_clearance(); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 61736f9ac..3a7c00285 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -596,6 +596,38 @@ void GLModel::init_from(const indexed_triangle_set& its) } } +void GLModel::init_from(const Polygon& polygon, float z) +{ + if (is_initialized()) { + // call reset() if you want to reuse this model + assert(false); + return; + } + + Geometry& data = m_render_data.geometry; + data.format = { Geometry::EPrimitiveType::Lines, Geometry::EVertexLayout::P3 }; + + const size_t segments_count = polygon.points.size(); + data.reserve_vertices(2 * segments_count); + data.reserve_indices(2 * segments_count); + + // vertices + indices + unsigned int vertices_counter = 0; + for (size_t i = 0; i < segments_count; ++i) { + const Point& p0 = polygon.points[i]; + const Point& p1 = (i == segments_count - 1) ? polygon.points.front() : polygon.points[i + 1]; + data.add_vertex(Vec3f(unscale(p0.x()), unscale(p0.y()), z)); + data.add_vertex(Vec3f(unscale(p1.x()), unscale(p1.y()), z)); + vertices_counter += 2; + data.add_line(vertices_counter - 2, vertices_counter - 1); + } + + // update bounding box + for (size_t i = 0; i < vertices_count(); ++i) { + m_bounding_box.merge(data.extract_position_3(i).cast()); + } +} + void GLModel::init_from(const Polygons& polygons, float z) { if (is_initialized()) { diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index fbf6ed533..3d3a8aac3 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -227,6 +227,7 @@ namespace GUI { void init_from(const TriangleMesh& mesh); #endif // ENABLE_SMOOTH_NORMALS void init_from(const indexed_triangle_set& its); + void init_from(const Polygon& polygon, float z); void init_from(const Polygons& polygons, float z); bool init_from_file(const std::string& filename); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ad67b99bb..1d3cb4a6e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -984,6 +984,8 @@ bool GLGizmosManager::activate_gizmo(EType type) new_gizmo.register_raycasters_for_picking(); + m_parent.reset_sequential_print_clearance(); + // sucessful activation of gizmo return true; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 70296e137..87ce3e105 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3306,10 +3306,12 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; if (printer_technology == ptFFF) { const Print* print = background_process.fff_print(); - const Polygons polygons = print->get_sequential_print_clearance_polygons(); - view3D->get_canvas3d()->set_sequential_print_clearance_visible(!polygons.empty()); - view3D->get_canvas3d()->set_sequential_print_clearance_render_fill(!polygons.empty()); - view3D->get_canvas3d()->set_sequential_print_clearance_polygons(polygons); + GLCanvas3D::ContoursList contours; + contours.contours = print->get_sequential_print_clearance_contours(); + view3D->get_canvas3d()->set_sequential_print_clearance_visible(!contours.empty()); + view3D->get_canvas3d()->set_sequential_print_clearance_render_fill(!contours.empty()); + view3D->get_canvas3d()->set_sequential_print_clearance_contours(contours); + view3D->get_canvas3d()->set_sequential_print_clearance_evaluating(false); } } }