From 6c6713c4ad97de3221cb6604e190d5e568927d4a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 10 Jun 2022 14:56:15 +0200 Subject: [PATCH] Tech ENABLE_RAYCAST_PICKING - Raytraced picking of volumes --- src/libslic3r/Model.hpp | 3 + src/slic3r/GUI/3DScene.cpp | 203 +++++++++++++++++++++++++++++- src/slic3r/GUI/3DScene.hpp | 7 ++ src/slic3r/GUI/GLCanvas3D.cpp | 24 ++++ src/slic3r/GUI/SceneRaycaster.cpp | 6 +- 5 files changed, 241 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 8283584192..0e5033475c 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -618,6 +618,9 @@ public: // The triangular model. const TriangleMesh& mesh() const { return *m_mesh.get(); } +#if ENABLE_RAYCAST_PICKING + std::shared_ptr mesh_ptr() const { return m_mesh; } +#endif // ENABLE_RAYCAST_PICKING void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared(mesh); } void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared(std::move(mesh)); } void set_mesh(const indexed_triangle_set &mesh) { m_mesh = std::make_shared(mesh); } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 074269c923..c9b3a2fddc 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -804,15 +804,24 @@ int GLVolumeCollection::load_object_volume( const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; +#if ENABLE_RAYCAST_PICKING + std::shared_ptr mesh = model_volume->mesh_ptr(); +#else const TriangleMesh &mesh = model_volume->mesh(); +#endif // ENABLE_RAYCAST_PICKING this->volumes.emplace_back(new GLVolume()); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); #if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_SMOOTH_NORMALS v.model.init_from(mesh, true); +#else +#if ENABLE_RAYCAST_PICKING + v.model.init_from(*mesh); + v.mesh_raycaster = std::make_unique(mesh); #else v.model.init_from(mesh); +#endif // ENABLE_RAYCAST_PICKING #endif // ENABLE_SMOOTH_NORMALS #else #if ENABLE_SMOOTH_NORMALS @@ -877,8 +886,11 @@ void GLVolumeCollection::load_object_auxiliary( v.model.init_from(mesh, true); #else v.model.init_from(mesh); -#endif // ENABLE_SMOOTH_NORMALS v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR); +#if ENABLE_RAYCAST_PICKING + v.mesh_raycaster = std::make_unique(std::make_shared(mesh)); +#endif // ENABLE_RAYCAST_PICKING +#endif // ENABLE_SMOOTH_NORMALS #else #if ENABLE_SMOOTH_NORMALS v.indexed_vertex_array.load_mesh(mesh, true); @@ -941,8 +953,112 @@ int GLVolumeCollection::load_wipe_tower_preview( // Too narrow tower would interfere with the teeth. The estimate is not precise anyway. depth = std::max(depth, 10.f); float min_width = 30.f; + +#if ENABLE_RAYCAST_PICKING + const float scaled_brim_height = 0.2f / height; +#endif // ENABLE_RAYCAST_PICKING + // We'll now create the box with jagged edge. y-coordinates of the pre-generated model // are shifted so that the front edge has y=0 and centerline of the back edge has y=depth: +#if ENABLE_RAYCAST_PICKING + // We split the box in three main pieces, + // the two laterals are identical and the central is the one containing the jagged geometry + + // lateral parts generator + auto generate_lateral = [&](float min_x, float max_x) { + const std::vector vertices = { + { min_x, -(depth + brim_width), 0.0f }, + { max_x, -(depth + brim_width), 0.0f }, + { min_x, -(depth + brim_width), scaled_brim_height }, + { max_x, -(depth + brim_width), scaled_brim_height }, + { min_x, -depth, scaled_brim_height }, + { max_x, -depth, scaled_brim_height }, + { min_x, -depth, 1.0f }, + { max_x, -depth, 1.0f }, + { min_x, 0.0f, 1.0f }, + { max_x, 0.0f, 1.0f }, + { min_x, 0.0f, scaled_brim_height }, + { max_x, 0.0f, scaled_brim_height }, + { min_x, brim_width, scaled_brim_height }, + { max_x, brim_width, scaled_brim_height }, + { min_x, brim_width, 0.0f }, + { max_x, brim_width, 0.0f } + }; + const std::vector triangles = { + { 0, 1, 3 }, { 0, 3, 2 }, { 2, 3, 5 }, { 2, 5, 4 }, { 4, 5, 7 }, { 4, 7, 6 }, { 6, 7, 9 }, { 6, 9, 8 }, + { 8, 9, 11 }, { 8, 11, 10 }, { 10, 11, 13 }, { 10, 13, 12 }, { 12, 13, 15 }, { 12, 15, 14 }, { 14, 15, 1 }, { 14, 1, 0 } + }; + + indexed_triangle_set its; + its.vertices.reserve(vertices.size()); + for (const Vec3f& v : vertices) { + its.vertices.emplace_back(v.x(), v.y() + depth, v.z()); + } + its.indices.reserve(triangles.size()); + for (const Vec3i& t : triangles) { + its.indices.emplace_back(t); + } + return its; + }; + + // central parts generator + auto generate_central = [&]() { + const std::vector vertices = { + { 38.453f, -(depth + brim_width), 0.0f }, + { 61.547f, -(depth + brim_width), 0.0f }, + { 38.453f, -(depth + brim_width), scaled_brim_height }, + { 61.547f, -(depth + brim_width), scaled_brim_height }, + { 38.453f, -depth, scaled_brim_height }, + { 61.547f, -depth, scaled_brim_height }, + { 38.453f, -depth, 1.0f }, + { 61.547f, -depth, 1.0f }, + { 38.453f, 0.0f, 1.0f }, + { 38.453f + 0.57735f * brim_width, brim_width, 1.0f }, + { 44.2265f, 10.0f, 1.0f }, + { 50.0f - 0.57735f * brim_width, brim_width, 1.0f }, + { 50.0f, 0.0f, 1.0f }, + { 55.7735f, -10.0f, 1.0f }, + { 61.547f, 0.0f, 1.0f }, + { 38.453f, 0.0f, scaled_brim_height }, + { 38.453f, brim_width, scaled_brim_height }, + { 38.453f + 0.57735f * brim_width, brim_width, scaled_brim_height }, + { 50.0f - 0.57735f * brim_width, brim_width, scaled_brim_height }, + { 50.0f, 0.0f, scaled_brim_height }, + { 55.7735f, -10.0f, scaled_brim_height }, + { 61.547f, 0.0f, scaled_brim_height }, + { 61.547f, brim_width, scaled_brim_height }, + { 38.453f, brim_width, 0.0f }, + { 38.453f + 0.57735f * brim_width, brim_width, 0.0f }, + { 44.2265f, 10.0f, 0.0f }, + { 50.0f - 0.57735f * brim_width, brim_width, 0.0f }, + { 61.547f, brim_width, 0.0f } + }; + + const std::vector triangles = { + { 0, 1, 3 }, { 0, 3, 2 }, { 2, 3, 5 }, { 2, 5, 4 }, { 4, 5, 7 }, { 4, 7, 6 }, { 7, 14, 13 }, { 7, 13, 6 }, + { 6, 13, 12 }, { 6, 12, 8 }, { 8, 12, 11 }, { 8, 11, 9 }, { 9, 11, 10 }, { 18, 19, 22 }, { 22, 19, 21 }, { 19, 20, 21 }, + { 15, 17, 16 }, { 17, 15, 8 }, { 17, 8, 9 }, { 21, 13, 14 }, { 21, 20, 13 }, { 20, 19, 12 }, { 20, 12, 13 }, { 19, 18, 11 }, + { 19, 11, 12 }, { 27, 26, 18 }, { 27, 18, 22 }, { 26, 25, 18 }, { 18, 25, 11 }, { 11, 25, 10 }, { 25, 24, 17 }, { 25, 17, 9 }, + { 25, 9, 10 }, { 24, 23, 16 }, { 24, 16, 17 }, { 1, 26, 27 }, { 1, 23, 26 }, { 1, 0, 23 }, { 0, 23, 24 }, { 24, 25, 26 } + }; + + indexed_triangle_set its; + its.vertices.reserve(vertices.size()); + for (const Vec3f& v : vertices) { + its.vertices.emplace_back(v.x(), v.y() + depth, v.z()); + } + its.indices.reserve(triangles.size()); + for (const Vec3i& t : triangles) { + its.indices.emplace_back(t); + } + return its; + }; + + TriangleMesh tooth_mesh; + tooth_mesh.merge(TriangleMesh(std::move(generate_lateral(0.0f, 38.453f)))); + tooth_mesh.merge(TriangleMesh(std::move(generate_central()))); + tooth_mesh.merge(TriangleMesh(std::move(generate_lateral(61.547f, 100.0f)))); +#else float out_points_idx[][3] = { { 0, -depth, 0 }, { 0, 0, 0 }, { 38.453f, 0, 0 }, { 61.547f, 0, 0 }, { 100.0f, 0, 0 }, { 100.0f, -depth, 0 }, { 55.7735f, -10.0f, 0 }, { 44.2265f, 10.0f, 0 }, { 38.453f, 0, 1 }, { 0, 0, 1 }, { 0, -depth, 1 }, { 100.0f, -depth, 1 }, { 100.0f, 0, 1 }, { 61.547f, 0, 1 }, { 55.7735f, -10.0f, 1 }, { 44.2265f, 10.0f, 1 } }; static constexpr const int out_facets_idx[][3] = { @@ -957,6 +1073,7 @@ int GLVolumeCollection::load_wipe_tower_preview( for (const int *face : out_facets_idx) its.indices.emplace_back(face); TriangleMesh tooth_mesh(std::move(its)); +#endif // ENABLE_RAYCAST_PICKING // We have the mesh ready. It has one tooth and width of min_width. We will now // append several of these together until we are close to the required width @@ -964,24 +1081,108 @@ int GLVolumeCollection::load_wipe_tower_preview( size_t n = std::max(1, int(width / min_width)); // How many shall be merged? for (size_t i = 0; i < n; ++i) { mesh.merge(tooth_mesh); +#if ENABLE_RAYCAST_PICKING + tooth_mesh.translate(100.0f, 0.0f, 0.0f); +#else tooth_mesh.translate(min_width, 0.f, 0.f); +#endif // ENABLE_RAYCAST_PICKING } +#if ENABLE_RAYCAST_PICKING + // Now we add the caps along the X axis + const float scaled_brim_width_x = brim_width * n * width / min_width; + auto generate_negx_cap = [&]() { + const std::vector vertices = { + { -scaled_brim_width_x, -(depth + brim_width), 0.0f }, + { 0.0f, -(depth + brim_width), 0.0f }, + { -scaled_brim_width_x, -(depth + brim_width), scaled_brim_height }, + { 0.0f, -(depth + brim_width), scaled_brim_height }, + { 0.0f, -depth, scaled_brim_height }, + { 0.0f, -depth, 1.0f }, + { 0.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, scaled_brim_height }, + { 0.0f, brim_width, scaled_brim_height }, + { -scaled_brim_width_x, brim_width, scaled_brim_height }, + { 0.0f, brim_width, 0.0f }, + { -scaled_brim_width_x, brim_width, 0.0f } + }; + + const std::vector triangles = { + { 0, 1, 3 }, { 0, 3, 2 }, { 2, 3, 4 }, { 2, 4, 9 }, { 9, 4, 7 }, { 9, 7, 8 }, { 9, 8, 10 }, { 9, 10, 11 }, + { 11, 10, 1 }, { 11, 1, 0 }, { 11, 0, 2 }, { 11, 2, 9 }, { 7, 4, 5 }, { 7, 5, 6 } + }; + + indexed_triangle_set its; + its.vertices.reserve(vertices.size()); + for (const Vec3f& v : vertices) { + its.vertices.emplace_back(v.x(), v.y() + depth, v.z()); + } + its.indices.reserve(triangles.size()); + for (const Vec3i& t : triangles) { + its.indices.emplace_back(t); + } + return its; + }; + + auto generate_posx_cap = [&]() { + const float posx_cap_x = n * 100.0f; + const std::vector vertices = { + { posx_cap_x, -(depth + brim_width), 0.0f }, + { posx_cap_x + scaled_brim_width_x, -(depth + brim_width), 0.0f }, + { posx_cap_x, -(depth + brim_width), scaled_brim_height }, + { posx_cap_x + scaled_brim_width_x, -(depth + brim_width), scaled_brim_height }, + { posx_cap_x, -depth, scaled_brim_height }, + { posx_cap_x, -depth, 1.0f }, + { posx_cap_x, 0.0f, 1.0f }, + { posx_cap_x, 0.0f, scaled_brim_height }, + { posx_cap_x, brim_width, scaled_brim_height }, + { posx_cap_x + scaled_brim_width_x, brim_width, scaled_brim_height }, + { posx_cap_x, brim_width, 0.0f }, + { posx_cap_x + scaled_brim_width_x, brim_width, 0.0f } + }; + + const std::vector triangles = { + { 0, 1, 3 }, { 0, 3, 2 }, { 2, 3, 4 }, { 4, 3, 9 }, { 4, 9, 7 }, { 7, 9, 8 }, { 8, 9, 11 }, { 8, 11, 10 }, + { 10, 11, 1 }, { 10, 1, 0 }, { 1, 11, 9 }, { 1, 9, 3 }, { 4, 7, 6 }, { 4, 6, 5 } + }; + + indexed_triangle_set its; + its.vertices.reserve(vertices.size()); + for (const Vec3f& v : vertices) { + its.vertices.emplace_back(v.x(), v.y() + depth, v.z()); + } + its.indices.reserve(triangles.size()); + for (const Vec3i& t : triangles) { + its.indices.emplace_back(t); + } + return its; + }; + + mesh.merge(TriangleMesh(std::move(generate_negx_cap()))); + mesh.merge(TriangleMesh(std::move(generate_posx_cap()))); + mesh.scale(Vec3f(width / (n * 100.0f), 1.0f, height)); // Scaling to proper width +#else mesh.scale(Vec3f(width / (n * min_width), 1.f, height)); // Scaling to proper width +#endif // ENABLE_RAYCAST_PICKING } else mesh = make_cube(width, depth, height); +#if !ENABLE_RAYCAST_PICKING // We'll make another mesh to show the brim (fixed layer height): TriangleMesh brim_mesh = make_cube(width + 2.f * brim_width, depth + 2.f * brim_width, 0.2f); brim_mesh.translate(-brim_width, -brim_width, 0.f); mesh.merge(brim_mesh); +#endif // !ENABLE_RAYCAST_PICKING volumes.emplace_back(new GLVolume(color)); GLVolume& v = *volumes.back(); #if ENABLE_LEGACY_OPENGL_REMOVAL v.model.init_from(mesh); v.model.set_color(color); +#if ENABLE_RAYCAST_PICKING + v.mesh_raycaster = std::make_unique(std::make_shared(mesh)); +#endif // ENABLE_RAYCAST_PICKING #else v.indexed_vertex_array.load_mesh(mesh); #endif // ENABLE_LEGACY_OPENGL_REMOVAL diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 237d19405d..a47c8d05d0 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -10,6 +10,9 @@ #include "libslic3r/Color.hpp" #include "GLModel.hpp" +#if ENABLE_RAYCAST_PICKING +#include "MeshUtils.hpp" +#endif // ENABLE_RAYCAST_PICKING #include #include @@ -392,6 +395,10 @@ public: #if ENABLE_LEGACY_OPENGL_REMOVAL GUI::GLModel model; +#if ENABLE_RAYCAST_PICKING + // raycaster used for picking + std::unique_ptr mesh_raycaster; +#endif // ENABLE_RAYCAST_PICKING #else // Interleaved triangles & normals with indexed triangles & quads. GLIndexedVertexArray indexed_vertex_array; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 27540b4546..ed291fdf6a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2229,6 +2229,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #else #if ENABLE_LEGACY_OPENGL_REMOVAL volume.model.init_from(mesh); +#if ENABLE_RAYCAST_PICKING + volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); +#endif // ENABLE_RAYCAST_PICKING #else volume.indexed_vertex_array.load_mesh(mesh); #endif // ENABLE_LEGACY_OPENGL_REMOVAL @@ -2244,7 +2247,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re #endif // ENABLE_LEGACY_OPENGL_REMOVAL #else #if ENABLE_LEGACY_OPENGL_REMOVAL +#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)); +#else volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); +#endif // ENABLE_RAYCAST_PICKING #else volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); #endif // ENABLE_LEGACY_OPENGL_REMOVAL @@ -2392,6 +2401,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re manip->set_dirty(); } +#if ENABLE_RAYCAST_PICKING + // refresh volume raycasters for picking + m_scene_raycaster.reset(SceneRaycaster::EType::Volume); + for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { + assert(m_volumes.volumes[i]->mesh_raycaster != nullptr); + add_raycaster_for_picking(SceneRaycaster::EType::Volume, i, *m_volumes.volumes[i]->mesh_raycaster, m_volumes.volumes[i]->world_matrix()); + } +#endif // ENABLE_RAYCAST_PICKING + // and force this canvas to be redrawn. m_dirty = true; } @@ -3658,6 +3676,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) { +#if ENABLE_RAYCAST_PICKING + m_mouse.position = pos.cast(); +#endif // ENABLE_RAYCAST_PICKING + if (m_layers_editing.state != LayersEditing::Unknown) { m_layers_editing.state = LayersEditing::Unknown; _stop_timer(); @@ -3682,7 +3704,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) deselect_all(); } else if (evt.RightUp()) { +#if !ENABLE_RAYCAST_PICKING m_mouse.position = pos.cast(); +#endif // !ENABLE_RAYCAST_PICKING // forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while // the context menu is already shown render(); diff --git a/src/slic3r/GUI/SceneRaycaster.cpp b/src/slic3r/GUI/SceneRaycaster.cpp index f9e0e0bb5a..8db41aef2f 100644 --- a/src/slic3r/GUI/SceneRaycaster.cpp +++ b/src/slic3r/GUI/SceneRaycaster.cpp @@ -112,7 +112,9 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came return ret; }; +#if ENABLE_RAYCAST_PICKING_DEBUG m_last_hit.reset(); +#endif // ENABLE_RAYCAST_PICKING_DEBUG HitResult ret; @@ -148,7 +150,9 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came if (ret.is_valid()) ret.raycaster_id = decode_id(ret.type, ret.raycaster_id); +#if ENABLE_RAYCAST_PICKING_DEBUG m_last_hit = ret; +#endif // ENABLE_RAYCAST_PICKING_DEBUG return ret; } @@ -172,7 +176,7 @@ void SceneRaycaster::render_hit(const Camera& camera) Transform3d m = Transform3d::Identity(); m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(Vec3d::UnitZ(), m_last_hit.value().normal.cast()).toRotationMatrix(); - const Transform3d line_view_model_matrix = sphere_view_model_matrix * m * Geometry::scale_transform(6.25); + const Transform3d line_view_model_matrix = sphere_view_model_matrix * m * Geometry::scale_transform(10.0); shader->set_uniform("view_model_matrix", line_view_model_matrix); m_line.render();