Unproject on mesh in the SLA gizmo is now performed by the MeshRaycaster class
This commit is contained in:
parent
284355d378
commit
b6292247e8
4 changed files with 137 additions and 42 deletions
|
@ -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 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))
|
if (m_model_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL))
|
||||||
{
|
{
|
||||||
|
//############################šš
|
||||||
m_AABB.deinit();
|
m_AABB.deinit();
|
||||||
m_AABB.init(
|
m_AABB.init(
|
||||||
MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
|
MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
|
||||||
MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.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();
|
m_model_object_id = m_model_object->id();
|
||||||
|
@ -389,51 +393,22 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
|
||||||
update_mesh();
|
update_mesh();
|
||||||
|
|
||||||
const Camera& camera = m_parent.get_camera();
|
const Camera& camera = m_parent.get_camera();
|
||||||
const std::array<int, 4>& 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<igl::Hit> hits;
|
|
||||||
|
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
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;
|
// The raycaster query
|
||||||
point2(2) -= m_z_shift;
|
std::vector<Vec3f> hits;
|
||||||
|
std::vector<Vec3f> normals;
|
||||||
|
m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals);
|
||||||
|
|
||||||
Transform3d inv = volume->get_instance_transformation().get_matrix().inverse();
|
// We must also take care of the clipping plane (if active)
|
||||||
|
unsigned i = 0;
|
||||||
point1 = inv * point1;
|
if (m_clipping_plane_distance != 0.f) {
|
||||||
point2 = inv * point2;
|
for (i=0; i<hits.size(); ++i)
|
||||||
|
if (! is_point_clipped(hits[i].cast<double>()))
|
||||||
if (!m_AABB.intersect_ray(
|
break;
|
||||||
MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
|
|
||||||
MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
|
|
||||||
point1.cast<float>(), (point2-point1).cast<float>(), 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; i<hits.size(); ++i) {
|
|
||||||
igl::Hit& hit = hits[i];
|
|
||||||
int fid = hit.id; // facet id
|
|
||||||
bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
|
|
||||||
a = (m_its->vertices[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<double>()))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
|
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
|
||||||
|
@ -443,7 +418,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate and return both the point and the facet normal.
|
// Calculate and return both the point and the facet normal.
|
||||||
pos_and_normal = std::make_pair(result, a.cross(b));
|
pos_and_normal = std::make_pair(hits[i], normals[i]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,6 +1080,7 @@ void GLGizmoSlaSupports::on_set_state()
|
||||||
m_its = nullptr;
|
m_its = nullptr;
|
||||||
m_object_clipper.reset();
|
m_object_clipper.reset();
|
||||||
m_supports_clipper.reset();
|
m_supports_clipper.reset();
|
||||||
|
m_mesh_raycaster.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_old_state = m_state;
|
m_old_state = m_state;
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace GUI {
|
||||||
|
|
||||||
class ClippingPlane;
|
class ClippingPlane;
|
||||||
class MeshClipper;
|
class MeshClipper;
|
||||||
|
class MeshRaycaster;
|
||||||
enum class SLAGizmoEventType : unsigned char;
|
enum class SLAGizmoEventType : unsigned char;
|
||||||
|
|
||||||
class GLGizmoSlaSupports : public GLGizmoBase
|
class GLGizmoSlaSupports : public GLGizmoBase
|
||||||
|
@ -38,6 +39,8 @@ private:
|
||||||
typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
|
typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
|
||||||
typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
|
typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
|
||||||
igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
|
igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
|
||||||
|
|
||||||
|
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
|
||||||
const TriangleMesh* m_mesh;
|
const TriangleMesh* m_mesh;
|
||||||
const indexed_triangle_set* m_its;
|
const indexed_triangle_set* m_its;
|
||||||
mutable const TriangleMesh* m_supports_mesh;
|
mutable const TriangleMesh* m_supports_mesh;
|
||||||
|
|
|
@ -3,6 +3,15 @@
|
||||||
#include "libslic3r/Tesselate.hpp"
|
#include "libslic3r/Tesselate.hpp"
|
||||||
#include "libslic3r/TriangleMesh.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 <igl/AABB.h>
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
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<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
|
||||||
|
typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
|
||||||
|
igl::AABB<MapMatrixXfUnaligned, 3> 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<Vec3f>* positions, std::vector<Vec3f>* normals) const
|
||||||
|
{
|
||||||
|
const std::array<int, 4>& 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<igl::Hit> 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<float>(), (pt2-pt1).cast<float>(), 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 GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -14,6 +14,8 @@ class TriangleMeshSlicer;
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
class Camera;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ClippingPlane
|
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<Vec3f>* positions = nullptr, std::vector<Vec3f>* 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 GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
Loading…
Reference in a new issue