From e2ccc6ec0c8add5da57a038df550cc27103cbdc3 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Thu, 14 May 2020 13:42:46 +0200 Subject: [PATCH 1/4] FDM supports gizmo: trying to increase performance during painting --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index b85fe57f0..0fea328bb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -393,13 +393,13 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous for (const std::pair<Vec3f, size_t>& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) { some_mesh_was_hit = true; const TriangleMesh* mesh = &mv->mesh(); - std::vector<NeighborData>& neighbors = m_neighbors[mesh_id]; + const std::vector<NeighborData>& neighbors = m_neighbors[mesh_id]; // Calculate direction from camera to the hit (in mesh coords): Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized(); // A lambda to calculate distance from the centerline: - auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f point) -> float { + auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float { Vec3f diff = hit_and_facet.first - point; return (diff - diff.dot(dir) * dir).squaredNorm(); }; @@ -461,17 +461,10 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous { if (m_button_down == Button::None) m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); - // Force rendering. In case the user is dragging, the queue can be - // flooded by wxEVT_MOVING event and rendering would be skipped. - m_parent.render(); return true; } - if (action == SLAGizmoEventType::Dragging && m_button_down != Button::None) { - // Same as above. We don't want the cursor to freeze when we - // leave the mesh while painting. - m_parent.render(); + if (action == SLAGizmoEventType::Dragging && m_button_down != Button::None) return true; - } } if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) From e312f3be4374f4684110b0897191f2c0339e9cc4 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Fri, 15 May 2020 14:16:56 +0200 Subject: [PATCH 2/4] FDM supports gizmo: caching triangle normals in order to increase performance --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 6 ++++-- src/slic3r/GUI/MeshUtils.cpp | 15 +++++---------- src/slic3r/GUI/MeshUtils.hpp | 9 +++++++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 0fea328bb..6843bab46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -506,8 +506,10 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv, if (status != type) continue; for (int i=0; i<3; ++i) - iva.push_geometry(mesh->its.vertices[mesh->its.indices[facet_idx](i)].cast<double>(), - MeshRaycaster::get_triangle_normal(mesh->its, facet_idx).cast<double>()); + iva.push_geometry( + mesh->its.vertices[mesh->its.indices[facet_idx](i)].cast<double>(), + m_c->raycaster()->raycasters()[mesh_id]->get_triangle_normal(facet_idx).cast<double>() + ); iva.push_triangle(3*triangle_cnt, 3*triangle_cnt+1, 3*triangle_cnt+2); ++triangle_cnt; } diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 6c4f5e49d..18526d8ce 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -95,11 +95,9 @@ void MeshClipper::recalculate_triangles() } -Vec3f MeshRaycaster::get_triangle_normal(const indexed_triangle_set& its, size_t facet_idx) +Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const { - Vec3f a(its.vertices[its.indices[facet_idx](1)] - its.vertices[its.indices[facet_idx](0)]); - Vec3f b(its.vertices[its.indices[facet_idx](2)] - its.vertices[its.indices[facet_idx](0)]); - return Vec3f(a.cross(b)).normalized(); + return m_normals[facet_idx]; } void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, @@ -218,12 +216,9 @@ Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const int idx = 0; Vec3d closest_point; m_emesh.squared_distance(point.cast<double>(), idx, closest_point); - if (normal) { - auto indices = m_emesh.F().row(idx); - Vec3d a(m_emesh.V().row(indices(1)) - m_emesh.V().row(indices(0))); - Vec3d b(m_emesh.V().row(indices(2)) - m_emesh.V().row(indices(0))); - *normal = Vec3f(a.cross(b).cast<float>()); - } + if (normal) + *normal = m_normals[idx]; + return closest_point.cast<float>(); } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 92f444f55..8e321730c 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -108,7 +108,11 @@ public: // The pointer can be invalidated after constructor returns. MeshRaycaster(const TriangleMesh& mesh) : m_emesh(mesh) - {} + { + m_normals.reserve(mesh.stl.facet_start.size()); + for (const stl_facet& facet : mesh.stl.facet_start) + m_normals.push_back(facet.normal); + } void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& point, Vec3d& direction) const; @@ -140,10 +144,11 @@ public: Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; - static Vec3f get_triangle_normal(const indexed_triangle_set& its, size_t facet_idx); + Vec3f get_triangle_normal(size_t facet_idx) const; private: sla::EigenMesh3D m_emesh; + std::vector<stl_normal> m_normals; }; From ed55ebba550bb1f35ad43eab0cde5c40e5d6f486 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Fri, 15 May 2020 16:23:19 +0200 Subject: [PATCH 3/4] FDM supports gizmo: Further attempts to increase performance when painting --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 128 +++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 11 +- 2 files changed, 96 insertions(+), 43 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6843bab46..f7b55f0ab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -15,6 +15,8 @@ namespace Slic3r { namespace GUI { +static constexpr size_t MaxVertexBuffers = 50; + GLGizmoFdmSupports::GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) , m_quadric(nullptr) @@ -123,10 +125,9 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const // Now render both enforcers and blockers. for (int i=0; i<2; ++i) { - if (m_ivas[mesh_id][i].has_VBOs()) { - glsafe(::glColor4f(i ? 1.f : 0.2f, 0.2f, i ? 0.2f : 1.0f, 0.5f)); - m_ivas[mesh_id][i].render(); - } + glsafe(::glColor4f(i ? 1.f : 0.2f, 0.2f, i ? 0.2f : 1.0f, 0.5f)); + for (const GLIndexedVertexArray& iva : m_ivas[mesh_id][i]) + iva.render(); } glsafe(::glPopMatrix()); } @@ -205,8 +206,14 @@ void GLGizmoFdmSupports::update_from_model_object() ++num_of_volumes; m_selected_facets.resize(num_of_volumes); m_neighbors.resize(num_of_volumes); + m_ivas.clear(); m_ivas.resize(num_of_volumes); + for (size_t i=0; i<num_of_volumes; ++i) { + m_ivas[i][0].reserve(MaxVertexBuffers); + m_ivas[i][1].reserve(MaxVertexBuffers); + } + int volume_id = -1; for (const ModelVolume* mv : mo->volumes) { @@ -226,7 +233,8 @@ void GLGizmoFdmSupports::update_from_model_object() for (int i : list) m_selected_facets[volume_id][i] = type; } - update_vertex_buffers(mv, volume_id, true, true); + update_vertex_buffers(mv, volume_id, FacetSupportType::ENFORCER); + update_vertex_buffers(mv, volume_id, FacetSupportType::BLOCKER); m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); @@ -389,6 +397,8 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.; const float limit = pow(m_cursor_radius/avg_scaling , 2.f); + std::vector<size_t> new_facets; + // For all hits on this mesh... for (const std::pair<Vec3f, size_t>& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) { some_mesh_was_hit = true; @@ -438,23 +448,43 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous ++facet_idx; } - // Now just select all facets that passed. + //std::vector<size_t> new_facets; + //new_facets.clear(); + new_facets.reserve(facets_to_select.size()); + + // Now just select all facets that passed and remember which + // ones have really changed state. for (size_t next_facet : facets_to_select) { FacetSupportType& facet = m_selected_facets[mesh_id][next_facet]; - if (facet != new_state && facet != FacetSupportType::NONE) { - // this triangle is currently in the other VBA. - // Both VBAs need to be refreshed. - update_both = true; + if (facet != new_state) { + if (facet != FacetSupportType::NONE) { + // this triangle is currently in the other VBA. + // Both VBAs need to be refreshed. + update_both = true; + } + facet = new_state; + new_facets.push_back(next_facet); } - facet = new_state; } } - update_vertex_buffers(mv, mesh_id, - new_state == FacetSupportType::ENFORCER || update_both, - new_state == FacetSupportType::BLOCKER || update_both - ); + if (! new_facets.empty()) { + if (new_state != FacetSupportType::NONE) { + // append triangles into the respective VBA + update_vertex_buffers(mv, mesh_id, new_state, &new_facets); + if (update_both) { + auto other = new_state == FacetSupportType::ENFORCER + ? FacetSupportType::BLOCKER + : FacetSupportType::ENFORCER; + update_vertex_buffers(mv, mesh_id, other); // regenerate the other VBA + } + } + else { + update_vertex_buffers(mv, mesh_id, FacetSupportType::ENFORCER); + update_vertex_buffers(mv, mesh_id, FacetSupportType::BLOCKER); + } + } } if (some_mesh_was_hit) @@ -488,34 +518,54 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv, int mesh_id, - bool update_enforcers, - bool update_blockers) + FacetSupportType type, + const std::vector<size_t>* new_facets) { const TriangleMesh* mesh = &mv->mesh(); - for (FacetSupportType type : {FacetSupportType::ENFORCER, FacetSupportType::BLOCKER}) { - if ((type == FacetSupportType::ENFORCER && ! update_enforcers) - || (type == FacetSupportType::BLOCKER && ! update_blockers)) - continue; + std::vector<GLIndexedVertexArray>& ivas = m_ivas[mesh_id][type == FacetSupportType::ENFORCER ? 0 : 1]; - GLIndexedVertexArray& iva = m_ivas[mesh_id][type==FacetSupportType::ENFORCER ? 0 : 1]; - iva.release_geometry(); - size_t triangle_cnt=0; + // lambda to push facet into vertex buffer + auto push_facet = [this, &mesh, &mesh_id](size_t idx, GLIndexedVertexArray& iva) { + for (int i=0; i<3; ++i) + iva.push_geometry( + mesh->its.vertices[mesh->its.indices[idx](i)].cast<double>(), + m_c->raycaster()->raycasters()[mesh_id]->get_triangle_normal(idx).cast<double>() + ); + size_t num = iva.triangle_indices_size; + iva.push_triangle(num, num+1, num+2); + }; + + + if (ivas.size() == MaxVertexBuffers || ! new_facets) { + // If there are too many or they should be regenerated, make one large + // GLVertexBufferArray. + ivas.clear(); // destructors release geometry + ivas.push_back(GLIndexedVertexArray()); + + bool pushed = false; for (size_t facet_idx=0; facet_idx<m_selected_facets[mesh_id].size(); ++facet_idx) { - FacetSupportType status = m_selected_facets[mesh_id][facet_idx]; - if (status != type) - continue; - for (int i=0; i<3; ++i) - iva.push_geometry( - mesh->its.vertices[mesh->its.indices[facet_idx](i)].cast<double>(), - m_c->raycaster()->raycasters()[mesh_id]->get_triangle_normal(facet_idx).cast<double>() - ); - iva.push_triangle(3*triangle_cnt, 3*triangle_cnt+1, 3*triangle_cnt+2); - ++triangle_cnt; + if (m_selected_facets[mesh_id][facet_idx] == type) { + push_facet(facet_idx, ivas.back()); + pushed = true; + } } - if (! m_selected_facets[mesh_id].empty()) - iva.finalize_geometry(true); + if (pushed) + ivas.back().finalize_geometry(true); + else + ivas.pop_back(); + } else { + // we are only appending - let's make new vertex array and let the old ones live + ivas.push_back(GLIndexedVertexArray()); + for (size_t facet_idx : *new_facets) + push_facet(facet_idx, ivas.back()); + + if (! new_facets->empty()) + ivas.back().finalize_geometry(true); + else + ivas.pop_back(); } + } @@ -548,7 +598,8 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwr ? FacetSupportType::BLOCKER : FacetSupportType::ENFORCER; } - update_vertex_buffers(mv, mesh_id, true, true); + update_vertex_buffers(mv, mesh_id, FacetSupportType::ENFORCER); + update_vertex_buffers(mv, mesh_id, FacetSupportType::BLOCKER); } Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle") @@ -618,7 +669,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (mv->is_model_part()) { m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); mv->m_supported_facets.clear(); - update_vertex_buffers(mv, idx, true, true); + update_vertex_buffers(mv, idx, FacetSupportType::ENFORCER); + update_vertex_buffers(mv, idx, FacetSupportType::BLOCKER); m_parent.set_as_dirty(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index bed6d00a0..14b28909f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -33,14 +33,15 @@ private: // individual facets (one of the enum values above). std::vector<std::vector<FacetSupportType>> m_selected_facets; - // Store two vertex buffer arrays (for enforcers/blockers) - // for each model-part volume. - std::vector<std::array<GLIndexedVertexArray, 2>> m_ivas; + // Vertex buffer arrays for each model-part volume. There is a vector of + // arrays so that adding triangles can be done without regenerating all + // other triangles. Enforcers and blockers are of course separate. + std::vector<std::array<std::vector<GLIndexedVertexArray>, 2>> m_ivas; void update_vertex_buffers(const ModelVolume* mv, int mesh_id, - bool update_enforcers, - bool update_blockers); + FacetSupportType type, // enforcers / blockers + const std::vector<size_t>* new_facets = nullptr); // nullptr -> regenerate all public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); From 1a38d39f82818be6e71551fafe379fb4765dea01 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Fri, 15 May 2020 18:31:55 +0200 Subject: [PATCH 4/4] FDM supports gizmo: slight code refactoring --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 161 +++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 3 +- 2 files changed, 80 insertions(+), 84 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index f7b55f0ab..41361eaa9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -233,8 +233,8 @@ void GLGizmoFdmSupports::update_from_model_object() for (int i : list) m_selected_facets[volume_id][i] = type; } - update_vertex_buffers(mv, volume_id, FacetSupportType::ENFORCER); - update_vertex_buffers(mv, volume_id, FacetSupportType::BLOCKER); + update_vertex_buffers(mesh, volume_id, FacetSupportType::ENFORCER); + update_vertex_buffers(mesh, volume_id, FacetSupportType::BLOCKER); m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); @@ -333,7 +333,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous Vec3f closest_hit = Vec3f::Zero(); double closest_hit_squared_distance = std::numeric_limits<double>::max(); size_t closest_facet = 0; - size_t closest_hit_mesh_id = size_t(-1); + int closest_hit_mesh_id = -1; // Transformations of individual meshes std::vector<Transform3d> trafo_matrices; @@ -376,17 +376,22 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // We now know where the ray hit, let's save it and cast another ray if (closest_hit_mesh_id != size_t(-1)) // only if there is at least one hit - hit_positions_and_facet_ids[closest_hit_mesh_id].emplace_back(closest_hit, closest_facet); + some_mesh_was_hit = true; + if (some_mesh_was_hit) { + // Now propagate the hits + mesh_id = -1; + const TriangleMesh* mesh = nullptr; + for (const ModelVolume* mv : mo->volumes) { + if (! mv->is_model_part()) + continue; + ++mesh_id; + if (mesh_id == closest_hit_mesh_id) { + mesh = &mv->mesh(); + break; + } + } - // Now propagate the hits - mesh_id = -1; - for (const ModelVolume* mv : mo->volumes) { - - if (! mv->is_model_part()) - continue; - - ++mesh_id; bool update_both = false; const Transform3d& trafo_matrix = trafo_matrices[mesh_id]; @@ -397,98 +402,90 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.; const float limit = pow(m_cursor_radius/avg_scaling , 2.f); - std::vector<size_t> new_facets; + const std::pair<Vec3f, size_t>& hit_and_facet = { closest_hit, closest_facet }; - // For all hits on this mesh... - for (const std::pair<Vec3f, size_t>& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) { - some_mesh_was_hit = true; - const TriangleMesh* mesh = &mv->mesh(); - const std::vector<NeighborData>& neighbors = m_neighbors[mesh_id]; + const std::vector<NeighborData>& neighbors = m_neighbors[mesh_id]; - // Calculate direction from camera to the hit (in mesh coords): - Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized(); + // Calculate direction from camera to the hit (in mesh coords): + Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized(); - // A lambda to calculate distance from the centerline: - auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float { - Vec3f diff = hit_and_facet.first - point; - return (diff - diff.dot(dir) * dir).squaredNorm(); - }; + // A lambda to calculate distance from the centerline: + auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float { + Vec3f diff = hit_and_facet.first - point; + return (diff - diff.dot(dir) * dir).squaredNorm(); + }; - // A lambda to determine whether this facet is potentionally visible (still can be obscured) - auto faces_camera = [&dir](const ModelVolume* mv, const size_t& facet) -> bool { - return (mv->mesh().stl.facet_start[facet].normal.dot(dir) > 0.); - }; - // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores - // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be - // quickly found by finding a vertex in the list and read the respective facet ids. - std::vector<size_t> facets_to_select{hit_and_facet.second}; - NeighborData vertex = std::make_pair(0, 0); - std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed - size_t facet_idx = 0; // index into facets_to_select - auto it = neighbors.end(); - while (facet_idx < facets_to_select.size()) { - size_t facet = facets_to_select[facet_idx]; - if (! visited[facet]) { - // check all three vertices and in case they're close enough, find the remaining facets - // and add them to the list to be proccessed later - for (size_t i=0; i<3; ++i) { - vertex.first = mesh->its.indices[facet](i); // vertex index - float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]); - if (dist < limit) { - it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex); - while (it != neighbors.end() && it->first == vertex.first) { - if (it->second != facet && faces_camera(mv, it->second)) - facets_to_select.push_back(it->second); - ++it; - } + // A lambda to determine whether this facet is potentionally visible (still can be obscured) + auto faces_camera = [&dir, &mesh](const size_t& facet) -> bool { + return (mesh->stl.facet_start[facet].normal.dot(dir) > 0.); + }; + // Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores + // pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be + // quickly found by finding a vertex in the list and read the respective facet ids. + std::vector<size_t> facets_to_select{hit_and_facet.second}; + NeighborData vertex = std::make_pair(0, 0); + std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed + size_t facet_idx = 0; // index into facets_to_select + auto it = neighbors.end(); + while (facet_idx < facets_to_select.size()) { + size_t facet = facets_to_select[facet_idx]; + if (! visited[facet]) { + // check all three vertices and in case they're close enough, find the remaining facets + // and add them to the list to be proccessed later + for (size_t i=0; i<3; ++i) { + vertex.first = mesh->its.indices[facet](i); // vertex index + float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]); + if (dist < limit) { + it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex); + while (it != neighbors.end() && it->first == vertex.first) { + if (it->second != facet && faces_camera(it->second)) + facets_to_select.push_back(it->second); + ++it; } } - visited[facet] = true; } - ++facet_idx; + visited[facet] = true; } + ++facet_idx; + } - //std::vector<size_t> new_facets; - //new_facets.clear(); - new_facets.reserve(facets_to_select.size()); + std::vector<size_t> new_facets; + new_facets.reserve(facets_to_select.size()); - // Now just select all facets that passed and remember which - // ones have really changed state. - for (size_t next_facet : facets_to_select) { - FacetSupportType& facet = m_selected_facets[mesh_id][next_facet]; + // Now just select all facets that passed and remember which + // ones have really changed state. + for (size_t next_facet : facets_to_select) { + FacetSupportType& facet = m_selected_facets[mesh_id][next_facet]; - if (facet != new_state) { - if (facet != FacetSupportType::NONE) { - // this triangle is currently in the other VBA. - // Both VBAs need to be refreshed. - update_both = true; - } - facet = new_state; - new_facets.push_back(next_facet); + if (facet != new_state) { + if (facet != FacetSupportType::NONE) { + // this triangle is currently in the other VBA. + // Both VBAs need to be refreshed. + update_both = true; } + facet = new_state; + new_facets.push_back(next_facet); } } if (! new_facets.empty()) { if (new_state != FacetSupportType::NONE) { // append triangles into the respective VBA - update_vertex_buffers(mv, mesh_id, new_state, &new_facets); + update_vertex_buffers(mesh, mesh_id, new_state, &new_facets); if (update_both) { auto other = new_state == FacetSupportType::ENFORCER ? FacetSupportType::BLOCKER : FacetSupportType::ENFORCER; - update_vertex_buffers(mv, mesh_id, other); // regenerate the other VBA + update_vertex_buffers(mesh, mesh_id, other); // regenerate the other VBA } } else { - update_vertex_buffers(mv, mesh_id, FacetSupportType::ENFORCER); - update_vertex_buffers(mv, mesh_id, FacetSupportType::BLOCKER); + update_vertex_buffers(mesh, mesh_id, FacetSupportType::ENFORCER); + update_vertex_buffers(mesh, mesh_id, FacetSupportType::BLOCKER); } } - } - if (some_mesh_was_hit) - { + if (m_button_down == Button::None) m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); return true; @@ -516,13 +513,11 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } -void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv, +void GLGizmoFdmSupports::update_vertex_buffers(const TriangleMesh* mesh, int mesh_id, FacetSupportType type, const std::vector<size_t>* new_facets) { - const TriangleMesh* mesh = &mv->mesh(); - std::vector<GLIndexedVertexArray>& ivas = m_ivas[mesh_id][type == FacetSupportType::ENFORCER ? 0 : 1]; // lambda to push facet into vertex buffer @@ -598,8 +593,8 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwr ? FacetSupportType::BLOCKER : FacetSupportType::ENFORCER; } - update_vertex_buffers(mv, mesh_id, FacetSupportType::ENFORCER); - update_vertex_buffers(mv, mesh_id, FacetSupportType::BLOCKER); + update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::ENFORCER); + update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::BLOCKER); } Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle") @@ -669,8 +664,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (mv->is_model_part()) { m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); mv->m_supported_facets.clear(); - update_vertex_buffers(mv, idx, FacetSupportType::ENFORCER); - update_vertex_buffers(mv, idx, FacetSupportType::BLOCKER); + update_vertex_buffers(&mv->mesh(), idx, FacetSupportType::ENFORCER); + update_vertex_buffers(&mv->mesh(), idx, FacetSupportType::BLOCKER); m_parent.set_as_dirty(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index 14b28909f..e7f3a2063 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -38,11 +38,12 @@ private: // other triangles. Enforcers and blockers are of course separate. std::vector<std::array<std::vector<GLIndexedVertexArray>, 2>> m_ivas; - void update_vertex_buffers(const ModelVolume* mv, + void update_vertex_buffers(const TriangleMesh* mesh, int mesh_id, FacetSupportType type, // enforcers / blockers const std::vector<size_t>* new_facets = nullptr); // nullptr -> regenerate all + public: GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); ~GLGizmoFdmSupports() override;