From 6c0aff0d23cb450671c41d50901707e2b7326ee5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 29 Aug 2022 12:55:34 +0200 Subject: [PATCH] Measuring: Measure gizmo features registered for raycasted picking --- src/libslic3r/Measure.hpp | 10 ++ src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/GLModel.cpp | 15 +++ src/slic3r/GUI/GLModel.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 132 ++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 16 ++- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 +- 10 files changed, 160 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 98517b991b..2f27a72598 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -49,6 +49,16 @@ public: // For anything, return an extra point that should also be considered a part of this. std::optional get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; } + bool operator == (const SurfaceFeature& other) const { + if (this->m_type != other.m_type) return false; + if (!this->m_pt1.isApprox(other.m_pt1)) return false; + if (!this->m_pt2.isApprox(other.m_pt2)) return false; + if (this->m_pt3.has_value() && !other.m_pt3.has_value()) return false; + if (!this->m_pt3.has_value() && other.m_pt3.has_value()) return false; + if (this->m_pt3.has_value() && other.m_pt3.has_value() && !(*this->m_pt3).isApprox(*other.m_pt3)) return false; + return this->m_value == other.m_value; + } + private: SurfaceFeatureType m_type = SurfaceFeatureType::Undef; Vec3d m_pt1; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4b6db1da45..baadc31bfd 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -67,7 +67,7 @@ #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) // Enable Measure Gizmo -#define ENABLE_MEASURE_GIZMO (1 && ENABLE_LEGACY_OPENGL_REMOVAL) +#define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING) // Enable debug code for Measure Gizmo #define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 04a6918711..c63b70f9ea 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2252,7 +2252,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_LEGACY_OPENGL_REMOVAL volume.model.init_from(mesh); #if ENABLE_RAYCAST_PICKING - volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); + volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); #endif // ENABLE_RAYCAST_PICKING #else volume.indexed_vertex_array.load_mesh(mesh); @@ -2272,7 +2272,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #if ENABLE_RAYCAST_PICKING const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); volume.model.init_from(new_mesh); - volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); + volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); #else volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); #endif // ENABLE_RAYCAST_PICKING diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0adf1cb26d..34c6ed4ee0 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -680,7 +680,7 @@ public: #if ENABLE_RAYCAST_PICKING std::shared_ptr add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster, - const Transform3d& trafo, bool use_back_faces = false) { + const Transform3d& trafo = Transform3d::Identity(), bool use_back_faces = false) { return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces); } void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) { diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 03d2677bea..70af07b7d7 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -257,6 +257,21 @@ void GLModel::Geometry::remove_vertex(size_t id) } } +indexed_triangle_set GLModel::Geometry::get_as_indexed_triangle_set() const +{ + indexed_triangle_set its; + its.vertices.reserve(vertices_count()); + for (size_t i = 0; i < vertices_count(); ++i) { + its.vertices.emplace_back(extract_position_3(i)); + } + its.indices.reserve(indices_count() / 3); + for (size_t i = 0; i < indices_count() / 3; ++i) { + const size_t tri_id = i * 3; + its.indices.emplace_back(extract_index(tri_id), extract_index(tri_id + 1), extract_index(tri_id + 2)); + } + return its; +} + size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index e631952a3e..2d1e352c48 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -140,6 +140,8 @@ namespace GUI { size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); } + indexed_triangle_set get_as_indexed_triangle_set() const; + static size_t vertex_stride_floats(const Format& format); static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index bbae3f2429..99769e0061 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -114,7 +114,7 @@ void GLGizmoHollow::on_register_raycasters_for_picking() if (info != nullptr && !info->model_object()->sla_drain_holes.empty()) { const sla::DrainHoles& drain_holes = info->model_object()->sla_drain_holes; for (int i = 0; i < (int)drain_holes.size(); ++i) { - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster)); } update_raycasters_for_picking_transform(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 73ee87840a..e132cf2ce1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -7,7 +7,6 @@ #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/Measure.hpp" #include "libslic3r/PresetBundle.hpp" #include @@ -20,12 +19,22 @@ namespace Slic3r { namespace GUI { static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f }; +static const int POINT_ID = 100; +static const int EDGE_ID = 200; +static const int CIRCLE_ID = 300; +static const int CIRCLE_CENTER_ID = 301; +static const int PLANE_ID = 400; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { - m_sphere.init_from(smooth_sphere(16, 7.5f)); - m_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f)); + GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); + m_sphere.mesh_raycaster = std::make_unique(std::make_shared(std::move(sphere_geometry.get_as_indexed_triangle_set()))); + m_sphere.model.init_from(std::move(sphere_geometry)); + + GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f); + m_cylinder.mesh_raycaster = std::make_unique(std::make_shared(std::move(cylinder_geometry.get_as_indexed_triangle_set()))); + m_cylinder.model.init_from(std::move(cylinder_geometry)); } bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) @@ -130,6 +139,7 @@ void GLGizmoMeasure::on_render() const Transform3d& model_matrix = selection.get_first_volume()->world_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); + const float inv_zoom = (float)camera.get_inv_zoom(); Vec3f pos; Vec3f normal; @@ -174,8 +184,70 @@ void GLGizmoMeasure::on_render() } #endif // ENABLE_MEASURE_GIZMO_DEBUG - if (features.empty()) - return; + if (m_features != features) { + GLGizmoMeasure::on_unregister_raycasters_for_picking(); + m_features = features; + if (m_features.empty()) + return; + +#if !ENABLE_MEASURE_GIZMO_DEBUG + for (const Measure::SurfaceFeature& feature : m_features) { + switch (feature.get_type()) { + case Measure::SurfaceFeatureType::Point: + { + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = feature.get_circle(); + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); + + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = feature.get_plane(); + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; + } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(init_data.get_as_indexed_triangle_set()))); + m_plane.model.init_from(std::move(init_data)); + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); + break; + } + } + } +#endif // !ENABLE_MEASURE_GIZMO_DEBUG + } GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) @@ -189,9 +261,8 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); const Transform3d& view_matrix = camera.get_view_matrix(); - const float inv_zoom = camera.get_inv_zoom(); - for (const Measure::SurfaceFeature& feature : features) { + for (const Measure::SurfaceFeature& feature : m_features) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: { @@ -201,8 +272,11 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.set_color(HOVER_COLOR); - m_sphere.render(); + m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.render(); + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); break; } case Measure::SurfaceFeatureType::Circle: @@ -214,19 +288,22 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", center_view_model_matrix); const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.set_color(HOVER_COLOR); - m_sphere.render(); - - m_circle.reset(); - m_circle.init_from(smooth_torus(64, 16, float(radius), 5.0f * inv_zoom)); + m_sphere.model.set_color(HOVER_COLOR); + m_sphere.model.render(); + auto it = m_raycasters.find(CIRCLE_CENTER_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; shader->set_uniform("view_model_matrix", circle_view_model_matrix); const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.set_color(HOVER_COLOR); - m_circle.render(); + m_circle.model.set_color(HOVER_COLOR); + m_circle.model.render(); + it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); break; } case Measure::SurfaceFeatureType::Edge: @@ -239,8 +316,11 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_model_matrix", view_model_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.set_color(HOVER_COLOR); - m_cylinder.render(); + m_cylinder.model.set_color(HOVER_COLOR); + m_cylinder.model.render(); + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); break; } case Measure::SurfaceFeatureType::Plane: @@ -253,6 +333,9 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); m_plane_models_cache[idx].set_color(HOVER_COLOR); m_plane_models_cache[idx].render(); + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); break; } } @@ -340,6 +423,19 @@ void GLGizmoMeasure::update_if_needed() } } +void GLGizmoMeasure::on_register_raycasters_for_picking() +{ + // the features are rendered on top of the scene, so the raytraced picker should take it into account + m_parent.set_raycaster_gizmos_on_top(true); +} + +void GLGizmoMeasure::on_unregister_raycasters_for_picking() +{ + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); + m_parent.set_raycaster_gizmos_on_top(false); + m_raycasters.clear(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 218b5e8757..41dc9fffba 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,6 +5,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "libslic3r/Measure.hpp" namespace Slic3r { @@ -25,10 +26,14 @@ class GLGizmoMeasure : public GLGizmoBase private: std::unique_ptr m_measuring; - GLModel m_sphere; - GLModel m_cylinder; - GLModel m_circle; + PickingModel m_sphere; + PickingModel m_cylinder; + PickingModel m_circle; + PickingModel m_plane; + std::vector m_plane_models_cache; + std::map> m_raycasters; + std::vector m_features; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -53,7 +58,7 @@ private: public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - + /// /// Apply rotation on select plane /// @@ -71,6 +76,9 @@ protected: void on_render_for_picking() override; void on_set_state() override; CommonGizmosDataID on_get_requirements() const override; + + virtual void on_register_raycasters_for_picking() override; + virtual void on_unregister_raycasters_for_picking() override; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index b562eb49a0..7be4301ad1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -148,8 +148,8 @@ void GLGizmoSlaSupports::on_register_raycasters_for_picking() if (m_editing_mode && !m_editing_cache.empty()) { for (size_t i = 0; i < m_editing_cache.size(); ++i) { - m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster, Transform3d::Identity()), - m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster, Transform3d::Identity())); + m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster), + m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster)); } update_raycasters_for_picking_transform(); }