From bc9164e40ca11f8b42e4421b3207f58ac044b1ee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 20 Mar 2019 08:48:42 +0100 Subject: [PATCH] SLA gizmo now respects the clipping plane when rendering points and raycasting mouse onto mesh --- src/slic3r/GUI/GLCanvas3D.cpp | 50 ++++++++++++-------- src/slic3r/GUI/GLCanvas3D.hpp | 3 ++ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 47 +++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 + 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6fdad8795..6f55e4059 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2582,27 +2582,7 @@ 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(); @@ -4720,6 +4700,28 @@ void GLCanvas3D::set_ortho_projection(float w, float h, float near, float far) c } +void GLCanvas3D::set_sla_clipping(bool enable) const +{ + if (m_gizmos.get_current_type() != Gizmos::SlaSupports) + return; + + if (enable) { + ::glMatrixMode(GL_PROJECTION); + ::glPushMatrix(); + ::glMatrixMode(GL_MODELVIEW); + const Size& cnv_size = get_canvas_size(); + 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); + } + else { + ::glMatrixMode(GL_PROJECTION); + ::glPopMatrix(); + ::glMatrixMode(GL_MODELVIEW); + ::glClear(GL_DEPTH_BUFFER_BIT); + } +} + + void GLCanvas3D::_render_objects() const { if (m_volumes.empty()) @@ -4728,6 +4730,8 @@ void GLCanvas3D::_render_objects() const ::glEnable(GL_LIGHTING); ::glEnable(GL_DEPTH_TEST); + set_sla_clipping(true); + if (m_use_VBOs) { if (m_picking_enabled) @@ -4789,6 +4793,8 @@ void GLCanvas3D::_render_objects() const } } + set_sla_clipping(false); + ::glDisable(GL_LIGHTING); } @@ -4831,6 +4837,8 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const if (!fake_colors) ::glEnable(GL_LIGHTING); + set_sla_clipping(true); + // do not cull backfaces to show broken geometry, if any ::glDisable(GL_CULL_FACE); @@ -4869,6 +4877,8 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const ::glEnable(GL_CULL_FACE); + set_sla_clipping(false); + if (!fake_colors) ::glDisable(GL_LIGHTING); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index acaae8dbd..44c43a1e3 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -778,6 +778,9 @@ private: // Sets current projection matrix to ortho, accounting for current camera zoom. void set_ortho_projection(float w, float h, float near, float far) const; + // Set/unset near clipping plane according to SLA gizmo requirements. + void set_sla_clipping(bool enable) const; + void _start_timer(); void _stop_timer(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index e2478bc0c..07eec27e2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -157,6 +157,11 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); + // we'll recover current look direction from the modelview matrix (in world coords): + Eigen::Matrix modelview_matrix; + ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); + Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]); + ::glPushMatrix(); ::glTranslated(0.0, 0.0, z_shift); ::glMultMatrixd(instance_matrix.data()); @@ -167,6 +172,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const sla::SupportPoint& support_point = m_editing_mode_cache[i].support_point; const bool& point_selected = m_editing_mode_cache[i].selected; + if (is_point_clipped(support_point.pos.cast(), direction_to_camera, z_shift)) + continue; + // First decide about the color of the point. if (picking) { std::array color = picking_color_component(i); @@ -285,6 +293,8 @@ void GLGizmoSlaSupports::update_mesh() m_AABB.init(m_V, m_F); } +// Unprojects the mouse position on the mesh and return the hit point and normal of the facet. +// The function throws if no intersection if found. std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: @@ -303,12 +313,15 @@ std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse ::gluUnProject(mouse_pos(0), viewport(3)-mouse_pos(1), 0.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point1(0), &point1(1), &point1(2)); ::gluUnProject(mouse_pos(0), viewport(3)-mouse_pos(1), 1.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point2(0), &point2(1), &point2(2)); - igl::Hit hit; + std::vector hits; const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); double z_offset = volume->get_sla_shift_z(); + // 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]); + point1(2) -= z_offset; point2(2) -= z_offset; @@ -317,17 +330,37 @@ std::pair GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse point1 = inv * point1; point2 = inv * point2; - if (!m_AABB.intersect_ray(m_V, m_F, point1.cast(), (point2-point1).cast(), hit)) + if (!m_AABB.intersect_ray(m_V, m_F, point1.cast(), (point2-point1).cast(), hits)) throw std::invalid_argument("unproject_on_mesh(): No intersection found."); - int fid = hit.id; // facet id - Vec3f bc(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit - Vec3f a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0))); - Vec3f b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0))); + std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); + + // Now let's iterate through the points and find the first that is not clipped: + unsigned int i=0; + Vec3f bc; + Vec3f a; + Vec3f b; + Vec3f result; + for (i=0; i(), direction_to_camera, z_offset)) + break; + } + + if (i==hits.size() || (hits.size()-i) % 2 != 0) { + // All hits are either clipped, or there is an odd number of unclipped + // hits - meaning the nearest must be from inside the mesh. + throw std::invalid_argument("unproject_on_mesh(): No intersection found."); + } // Calculate and return both the point and the facet normal. return std::make_pair( - bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)), + result, a.cross(b) ); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index a5f77a21b..872e3541f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -86,6 +86,7 @@ private: int m_canvas_height; std::vector get_config_options(const std::vector& keys) const; + bool is_point_clipped(const Vec3d& point, const Vec3d& direction_to_camera, float z_shift) const; // Methods that do the model_object and editing cache synchronization, // editing mode selection, etc: