diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index cc1794216..6fdad8795 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1317,6 +1317,22 @@ bool GLCanvas3D::Gizmos::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return false; } + + +std::pair GLCanvas3D::Gizmos::get_sla_clipping_plane() const +{ + if (!m_enabled) + return std::make_pair(0.f, 0.f); + + GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); + if (it != m_gizmos.end()) + return reinterpret_cast(it->second)->get_sla_clipping_plane(); + + return std::make_pair(0.f, 0.f);; +} + + + void GLCanvas3D::Gizmos::render_current_gizmo(const Selection& selection) const { if (!m_enabled) @@ -2566,7 +2582,27 @@ void GLCanvas3D::render() if (early_bed_render) _render_bed(theta); +//////////////////////// + //Eigen::Matrix stashed_projection_matrix; + //::glGetDoublev(GL_PROJECTION_MATRIX, stashed_projection_matrix.data()); + const Size& cnv_size = get_canvas_size(); + if (m_gizmos.get_current_type() == Gizmos::SlaSupports) { + std::pair clipping_limits = m_gizmos.get_sla_clipping_plane(); + set_ortho_projection((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height(), clipping_limits.first, clipping_limits.second); + } + +//////////////////// _render_objects(); +////////////////////////////////// + if (m_gizmos.get_current_type() == Gizmos::SlaSupports) { + //::glMatrixMode(GL_PROJECTION); + //::glLoadIdentity(); + //::glMultMatrixd(stashed_projection_matrix.data()); + //::glMatrixMode(GL_MODELVIEW); + _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); + } +////////////////////////////////// + _render_sla_slices(); _render_selection(); @@ -4416,29 +4452,13 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) _set_current(); ::glViewport(0, 0, w, h); - ::glMatrixMode(GL_PROJECTION); - ::glLoadIdentity(); - - const BoundingBoxf3& bbox = _max_bounding_box(); - switch (m_camera.type) { case Camera::Ortho: { - float w2 = w; - float h2 = h; - float two_zoom = 2.0f * get_camera_zoom(); - if (two_zoom != 0.0f) - { - float inv_two_zoom = 1.0f / two_zoom; - w2 *= inv_two_zoom; - h2 *= inv_two_zoom; - } - // FIXME: calculate a tighter value for depth will improve z-fighting - float depth = 5.0f * (float)bbox.max_size(); - ::glOrtho(-w2, w2, -h2, h2, -depth, depth); - + float depth = 5.0f * (float)(_max_bounding_box().max_size()); + set_ortho_projection(w, h, -depth, depth); break; } // case Camera::Perspective: @@ -4470,8 +4490,6 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) } } - ::glMatrixMode(GL_MODELVIEW); - m_dirty = false; } @@ -4685,6 +4703,23 @@ void GLCanvas3D::_render_axes() const m_bed.render_axes(); } + +void GLCanvas3D::set_ortho_projection(float w, float h, float near, float far) const +{ + float two_zoom = 2.0f * get_camera_zoom(); + if (two_zoom != 0.0f) + { + float inv_two_zoom = 1.0f / two_zoom; + w *= inv_two_zoom; + h *= inv_two_zoom; + } + ::glMatrixMode(GL_PROJECTION); + ::glLoadIdentity(); + ::glOrtho(-w, w, -h, h, near, far); + ::glMatrixMode(GL_MODELVIEW); +} + + void GLCanvas3D::_render_objects() const { if (m_volumes.empty()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7e414d52a..acaae8dbd 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -448,6 +448,7 @@ private: void set_sla_support_data(ModelObject* model_object, const Selection& selection); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false); + std::pair get_sla_clipping_plane() const; void render_current_gizmo(const Selection& selection) const; void render_current_gizmo_for_picking_pass(const Selection& selection) const; @@ -774,6 +775,9 @@ private: // Returns the view ray line, in world coordinate, at the given mouse position. Linef3 mouse_ray(const Point& mouse_pos); + // Sets current projection matrix to ortho, accounting for current camera zoom. + void set_ortho_projection(float w, float h, float near, float far) const; + void _start_timer(); void _stop_timer(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 2264c541e..e2478bc0c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -56,6 +56,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S if (model_object && selection.is_from_single_instance()) { + // Cache the bb - it's needed for dealing with the clipping plane quite often + // It could be done inside update_mesh but one has to account for scaling of the instance. + m_active_instance_bb = m_model_object->instance_bounding_box(m_active_instance); + if (is_mesh_update_necessary()) { update_mesh(); editing_mode_reload_cache(); @@ -232,6 +236,21 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) ::glPopMatrix(); } + + +bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point, const Vec3d& direction_to_camera, float z_shift) const +{ + if (m_clipping_plane_distance == 0.f) + return false; + + Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point; + transformed_point(2) += z_shift; + return direction_to_camera.dot(m_active_instance_bb.center()) + m_active_instance_bb.radius() + - m_clipping_plane_distance * 2*m_active_instance_bb.radius() < direction_to_camera.dot(transformed_point); +} + + + bool GLGizmoSlaSupports::is_mesh_update_necessary() const { return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty()) @@ -559,6 +578,69 @@ void GLGizmoSlaSupports::update_cache_entry_normal(unsigned int i) const + +std::pair GLGizmoSlaSupports::get_sla_clipping_plane() const +{ + if (!m_model_object) + return std::make_pair(0.f, 0.f);; + + Eigen::Matrix modelview_matrix; + ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); + + // clipping space origin transformed to world coords: + Vec3d clipping_origin = (modelview_matrix.inverse() * Eigen::Matrix{0, 0, 0, 1}).block<3,1>(0,0); + + // we'll recover current look direction from the modelview matrix (in world coords): + Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]); + float dist = direction_to_camera.dot(clipping_origin) - direction_to_camera.dot(m_active_instance_bb.center()); + + return std::make_pair((dist - m_active_instance_bb.radius()) + m_clipping_plane_distance * 2*m_active_instance_bb.radius(), dist + 5.f*m_active_instance_bb.radius()); +} + + +/* +void GLGizmoSlaSupports::find_intersections(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& idxs) const +{ + if (aabb->is_leaf()) { // this is a facet + // corner.dot(normal) - offset + unsigned int facet_idx = aabb->m_primitive; + + Vec3f a = m_V.row(m_F(facet_idx, 0)); + Vec3f b = m_V.row(m_F(facet_idx, 1)); + Vec3f c = m_V.row(m_F(facet_idx, 2)); + } + else { // not a leaf + using CornerType = Eigen::AlignedBox::CornerType; + bool sign = std::signbit(offset - normal.dot(aabb->m_box.corner(CornerType(0)))); + for (unsigned int i=1; i<8; ++i) + if (std::signbit(offset - normal.dot(aabb->m_box.corner(CornerType(i)))) != sign) { + find_intersections(aabb->m_left, normal, offset, idxs); + find_intersections(aabb->m_right, normal, offset, idxs); + } + } +} + +void GLGizmoSlaSupports::make_line_segments() const +{ + TriangleMeshSlicer tms(&m_model_object->volumes.front()->mesh); + Vec3f normal(0.f, 1.f, 1.f); + double d = 0.; + + std::vector lines; + find_intersections(&m_AABB, normal, d, lines); + ExPolygons expolys; + tms.make_expolygons_simple(lines, &expolys); + + SVG svg("slice_loops.svg", get_extents(expolys)); + svg.draw(expolys); + //for (const IntersectionLine &l : lines[i]) + // svg.draw(l, "red", 0); + //svg.draw_outline(expolygons, "black", "blue", 0); + svg.Close(); +} +*/ + + void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) { if (!m_model_object) @@ -676,6 +758,13 @@ RENDER_AGAIN: (m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS")))); } + + // Following is rendered in both editing and non-editing mode: + m_imgui->text("Clipping of view: "); + ImGui::SameLine(); + ImGui::PushItemWidth(150.0f); + bool value_changed = ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f"); + m_imgui->end(); if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode @@ -761,6 +850,7 @@ void GLGizmoSlaSupports::on_set_state() m_parent.toggle_model_objects_visibility(true); m_editing_mode = false; // so it is not active next time the gizmo opens m_editing_mode_cache.clear(); + m_clipping_plane_distance = 0.f; } m_old_state = m_state; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index bb3cf06ce..a5f77a21b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -22,6 +22,7 @@ private: ModelObject* m_model_object = nullptr; ModelObject* m_old_model_object = nullptr; int m_active_instance = -1; + BoundingBoxf3 m_active_instance_bb; // to cache the bb std::pair unproject_on_mesh(const Vec2d& mouse_pos); const float RenderPointScale = 1.f;