From b6292247e88c7ace1a7c406c0d560e954a448373 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 17 Sep 2019 09:17:53 +0200 Subject: [PATCH] Unproject on mesh in the SLA gizmo is now performed by the MeshRaycaster class --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 60 ++++--------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 3 + src/slic3r/GUI/MeshUtils.cpp | 92 ++++++++++++++++++++ src/slic3r/GUI/MeshUtils.hpp | 24 +++++ 4 files changed, 137 insertions(+), 42 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 80afb29b1..ee98ffc84 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -368,10 +368,14 @@ void GLGizmoSlaSupports::update_mesh() // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. if (m_model_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL)) { + //############################šš m_AABB.deinit(); m_AABB.init( MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3)); + //############################šš + + m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); } m_model_object_id = m_model_object->id(); @@ -389,51 +393,22 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& viewport = camera.get_viewport(); - const Transform3d& modelview_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - - Vec3d point1; - Vec3d point2; - ::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)); - - std::vector hits; - const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Geometry::Transformation trafo = volume->get_instance_transformation(); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); - point1(2) -= m_z_shift; - point2(2) -= m_z_shift; + // The raycaster query + std::vector hits; + std::vector normals; + m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals); - Transform3d inv = volume->get_instance_transformation().get_matrix().inverse(); - - point1 = inv * point1; - point2 = inv * point2; - - if (!m_AABB.intersect_ray( - MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), - MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), - point1.cast(), (point2-point1).cast(), hits)) - return false; // no intersection found - - 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; ivertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]); - b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]); - result = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)]; - if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast())) - break; + // We must also take care of the clipping plane (if active) + unsigned i = 0; + if (m_clipping_plane_distance != 0.f) { + for (i=0; i())) + break; } if (i==hits.size() || (hits.size()-i) % 2 != 0) { @@ -443,7 +418,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair> MapMatrixXfUnaligned; typedef Eigen::Map> MapMatrixXiUnaligned; igl::AABB m_AABB; + + std::unique_ptr m_mesh_raycaster; const TriangleMesh* m_mesh; const indexed_triangle_set* m_its; mutable const TriangleMesh* m_supports_mesh; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 9542f0b1f..e6af61621 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -3,6 +3,15 @@ #include "libslic3r/Tesselate.hpp" #include "libslic3r/TriangleMesh.hpp" +#include "slic3r/GUI/Camera.hpp" + +// There is an L function in igl that would be overridden by our localization macro. +#undef L +#include + +#include + + namespace Slic3r { namespace GUI { @@ -90,6 +99,89 @@ void MeshClipper::recalculate_triangles() } +class MeshRaycaster::AABBWrapper { +public: + AABBWrapper(const TriangleMesh* mesh); + ~AABBWrapper() { m_AABB.deinit(); } + + typedef Eigen::Map> MapMatrixXfUnaligned; + typedef Eigen::Map> MapMatrixXiUnaligned; + igl::AABB m_AABB; + +}; + +MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh) +{ + const indexed_triangle_set* its = &mesh->its; + m_AABB.init( + MapMatrixXfUnaligned(its->vertices.front().data(), its->vertices.size(), 3), + MapMatrixXiUnaligned(its->indices.front().data(), its->indices.size(), 3)); +} + + +MeshRaycaster::MeshRaycaster(const TriangleMesh& mesh) + : m_AABB_wrapper(new AABBWrapper(&mesh)), m_mesh(&mesh) +{ +} + +MeshRaycaster::~MeshRaycaster() +{ + delete m_AABB_wrapper; +} + + +bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, + const Camera& camera, std::vector* positions, std::vector* normals) const +{ + const std::array& viewport = camera.get_viewport(); + const Transform3d& model_mat = camera.get_view_matrix(); + const Transform3d& proj_mat = camera.get_projection_matrix(); + + Vec3d pt1; + Vec3d pt2; + ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2)); + ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2)); + + std::vector hits; + + Transform3d inv = trafo.inverse(); + + pt1 = inv * pt1; + pt2 = inv * pt2; + + if (! m_AABB_wrapper->m_AABB.intersect_ray( + AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), + AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3), + pt1.cast(), (pt2-pt1).cast(), hits)) + return false; // no intersection found + + std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); + + // Now stuff the points in the provided vector and calculate normals if asked about them: + if (positions != nullptr) { + positions->clear(); + if (normals != nullptr) + normals->clear(); + Vec3f bc; + Vec3f a; + Vec3f b; + int fid = 0; + for (const igl::Hit& hit : hits) { + fid = hit.id; + bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit + a = (m_mesh->its.vertices[m_mesh->its.indices[fid](1)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]); + b = (m_mesh->its.vertices[m_mesh->its.indices[fid](2)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]); + positions->push_back(bc(0) * m_mesh->its.vertices[m_mesh->its.indices[fid](0)] + bc(1) * m_mesh->its.vertices[m_mesh->its.indices[fid](1)] + bc(2) * m_mesh->its.vertices[m_mesh->its.indices[fid](2)]); + + if (normals != nullptr) + normals->push_back(a.cross(b)); + } + } + + return true; +} + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index f97003a91..cadc821dd 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -14,6 +14,8 @@ class TriangleMeshSlicer; namespace GUI { +class Camera; + class ClippingPlane @@ -86,6 +88,28 @@ private: }; + + +class MeshRaycaster { +public: + MeshRaycaster(const TriangleMesh& mesh); + ~MeshRaycaster(); + void set_transformation(const Geometry::Transformation& trafo); + void set_camera(const Camera& camera); + + bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + std::vector* positions = nullptr, std::vector* normals = nullptr) const; + +private: + // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here + class AABBWrapper; + AABBWrapper* m_AABB_wrapper; + + const TriangleMesh* m_mesh = nullptr; + + +}; + } // namespace GUI } // namespace Slic3r