diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 716029257b..c3b90b1928 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1056,6 +1056,23 @@ const TriangleMesh& SLAPrintObject::pad_mesh() const return EMPTY_MESH; } +const TriangleMesh &SLAPrintObject::get_mesh_to_print() const { + const TriangleMesh *ret = nullptr; + + int s = SLAPrintObjectStep::slaposCount; + + while (s > 0 && !ret) { + --s; + if (is_step_done(SLAPrintObjectStep(s)) && !m_preview_meshes[s].empty()) + ret = &m_preview_meshes[s]; + } + + if (!ret) + ret = &m_transformed_rmesh; + + return *ret; +} + //const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const //{ // if (m_hollowing_data && m_hollowing_data->interior && diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index a021645084..084c78024a 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -45,6 +45,24 @@ using _SLAPrintObjectBase = enum SliceOrigin { soSupport, soModel }; +} // namespace Slic3r + +namespace std { + +template<> struct hash { + size_t operator() (const Slic3r::csg::VoxelizeParams &p) const { + std::string str = Slic3r::float_to_string_decimal_point(p.voxel_scale()); + str += Slic3r::float_to_string_decimal_point(p.exterior_bandwidth()); + str += Slic3r::float_to_string_decimal_point(p.interior_bandwidth()); + + return std::hash{}(str); + } +}; + +} // namespace std + +namespace Slic3r { + // Each sla object step can hold a collection of csg operations on the // sla model to be sliced. Currently, Assembly step adds negative and positive // volumes, hollowing adds the negative interior, drilling adds the hole cylinders. @@ -54,7 +72,7 @@ enum SliceOrigin { soSupport, soModel }; struct CSGPartForStep : public csg::CSGPart { SLAPrintObjectStep key; - mutable struct { VoxelGridPtr gridptr; csg::VoxelizeParams params; } cache; + mutable std::unordered_map gridcache; CSGPartForStep(SLAPrintObjectStep k, CSGPart &&p = {}) : key{k}, CSGPart{std::move(p)} @@ -64,6 +82,7 @@ struct CSGPartForStep : public csg::CSGPart { this->its_ptr = std::move(part.its_ptr); this->operation = part.operation; + return *this; } @@ -72,23 +91,27 @@ struct CSGPartForStep : public csg::CSGPart namespace csg { -//inline VoxelGridPtr get_voxelgrid(const CSGPartForStep &part, -// const VoxelizeParams &p) -//{ -// if (!part.cache.gridptr || get_voxel_scale(*part.cache.gridptr) < p.voxel_scale()) { -// part.cache.gridptr = mesh_to_grid(*csg::get_mesh(part), p.voxel_scale(), -// p.exterior_bandwidth(), -// p.interior_bandwidth()); +inline bool operator==(const VoxelizeParams &a, const VoxelizeParams &b) +{ + std::hash h; + return h(a) == h(b); +} -// } /*else { -// float vscale = p.voxel_scale(); -// float oscale = get_voxel_scale(*part.cache.gridptr); +inline VoxelGridPtr get_voxelgrid(const CSGPartForStep &part, + const VoxelizeParams &p) +{ + VoxelGridPtr &ret = part.gridcache[p]; -// rescale_grid(*part.cache.gridptr, oscale/vscale); -// }*/ + if (!ret) { + ret = mesh_to_grid(*csg::get_mesh(part), + csg::get_transform(part), + p.voxel_scale(), + p.exterior_bandwidth(), + p.interior_bandwidth()); + } -// return clone(*part.cache.gridptr); -//} + return clone(*ret); +} } // namespace csg @@ -134,9 +157,7 @@ public: // Get the mesh that is going to be printed with all the modifications // like hollowing and drilled holes. - const TriangleMesh & get_mesh_to_print() const { - return !m_mesh_from_slices.empty() ? m_mesh_from_slices : m_transformed_rmesh; - } + const TriangleMesh & get_mesh_to_print() const; // // This will return the transformed mesh which is cached // const TriangleMesh& transformed_mesh() const; @@ -379,9 +400,16 @@ private: }; std::unique_ptr m_supportdata; - TriangleMesh m_mesh_from_slices; + + // Holds CSG operations for the printed object, prioritized by print steps. std::multiset m_mesh_to_slice; + // Holds the preview of the object to be printed (as it will look like with + // all its holes and cavities, negatives and positive volumes unified. + // Essentially this should be a m_mesh_to_slice after the CSG operations + // or an approximation of that. + std::array m_preview_meshes; + class HollowingData { public: diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index a024a799c0..b0efa31fa2 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include @@ -128,6 +128,54 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin } } + +void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep step) +{ + Benchmark bench; + + bench.start(); + // update preview mesh + double vscale = 1. / (2. * po.m_config.layer_height.getFloat()); + auto voxparams = csg::VoxelizeParams{} + .voxel_scale(vscale) + .exterior_bandwidth(1.f) + .interior_bandwidth(1.f); + auto grid = csg::voxelize_csgmesh(range(po.m_mesh_to_slice), voxparams); + + indexed_triangle_set m = grid_to_mesh(*grid); + +// if (!m.empty()) { +// // simplify mesh lossless + +// std::cout << "simplify started" << std::endl; +// int expected_cnt = m.indices.size() * 0.8; //std::pow(po.m_transformed_rmesh.volume() / std::pow(1./vscale, 3), 2./3.); +// std::cout << "expected triangles " << expected_cnt << std::endl; +// float err = std::pow(vscale, 3); +// its_quadric_edge_collapse(m, 0U, &err); +// std::cout << "simplify ended " << m.indices.size() << " triangles" << std::endl; + +// std::cout << "cleanup started" << std::endl; +// its_compactify_vertices(m); +// its_merge_vertices(m); +// std::cout << "cleanup ended" << std::endl; +// } + + po.m_preview_meshes[step] = TriangleMesh{std::move(m)}; + + for (size_t i = size_t(step) + 1; i < slaposCount; ++i) + { + po.m_preview_meshes[i] = {}; + } + + bench.stop(); + + std::cout << "Preview gen took: " << bench.getElapsedSec() << std::endl; + using namespace std::string_literals; + + report_status(-2, "Reload preview from step "s + std::to_string(int(step)), SlicingStatus::RELOAD_SLA_PREVIEW); +} + +static inline void clear_csg(std::multiset &s, SLAPrintObjectStep step) { auto r = s.equal_range(step); @@ -153,6 +201,8 @@ void SLAPrint::Steps::mesh_assembly(SLAPrintObject &po) csg::model_to_csgmesh(*po.model_object(), po.trafo(), csg_inserter{po.m_mesh_to_slice, slaposAssembly}, csg::mpartsPositive | csg::mpartsNegative); + + generate_preview(po, slaposAssembly); } void SLAPrint::Steps::hollow_model(SLAPrintObject &po) @@ -185,11 +235,24 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); po.m_hollowing_data->interior = std::move(interior); + indexed_triangle_set &m = sla::get_mesh(*po.m_hollowing_data->interior); + + if (!m.empty()) { + // simplify mesh lossless + float loss_less_max_error = 2*std::numeric_limits::epsilon(); + its_quadric_edge_collapse(m, 0U, &loss_less_max_error); + + its_compactify_vertices(m); + its_merge_vertices(m); + } + // Put the interior into the target mesh as a negative po.m_mesh_to_slice .emplace(slaposHollowing, csg::CSGPart{&sla::get_mesh(*po.m_hollowing_data->interior), csg::CSGType::Difference}); + + generate_preview(po, slaposHollowing); } } @@ -203,14 +266,7 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po) csg::mpartsDrillHoles); // update preview mesh - double vscale = 1. / 0.05; - auto voxparams = csg::VoxelizeParams{} - .voxel_scale(vscale) - .exterior_bandwidth(1.f) - .interior_bandwidth(1.f); - auto grid = csg::voxelize_csgmesh(range(po.m_mesh_to_slice), voxparams); - indexed_triangle_set mesh_from_slices = grid_to_mesh(*grid); - po.m_mesh_from_slices = TriangleMesh{mesh_from_slices}; + generate_preview(po, slaposDrillHoles); } template @@ -331,38 +387,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) // We apply the printer correction offset here. apply_printer_corrections(po, soModel); -// auto simpl_slices = reserve_vector(po.m_model_slices.size()); -// for (const ExPolygons &slice : po.m_model_slices) { -// simpl_slices.emplace_back(expolygons_simplify(slice, scaled(1e-2))); -// } - -// po.m_mesh_from_slices = TriangleMesh{ -// slices_to_mesh(simpl_slices, slice_grid.front(), lhd, ilhd)}; - - double vscale = 1. / lhd; - auto voxparams = csg::VoxelizeParams{} - .voxel_scale(vscale) - .exterior_bandwidth(1.f) - .interior_bandwidth(1.f); - auto grid = csg::voxelize_csgmesh(range(po.m_mesh_to_slice), voxparams); - - assert(grid); - -// size_t max_face_cnt = 0; -// for (const CSGMesh &part : po.m_mesh_to_slice) -// max_face_cnt += part.its_ptr->indices.size(); - - indexed_triangle_set mesh_from_slices = grid_to_mesh(*grid); - -// its_quadric_edge_collapse(mesh_from_slices, vscale * max_face_cnt); - -// its_compactify_vertices(mesh_from_slices); -// its_merge_vertices(mesh_from_slices); - - po.m_mesh_from_slices = TriangleMesh{mesh_from_slices}; - -// po.m_mesh_from_slices = TriangleMesh{sla::get_mesh(*po.m_hollowing_data->interior)}; - + generate_preview(po, slaposObjectSlice); } static void filter_support_points_by_modifiers( @@ -421,7 +446,10 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po) if(!po.m_config.supports_enable.getBool()) return; if (!po.m_supportdata) - po.m_supportdata.reset(new SLAPrintObject::SupportData(po.m_mesh_from_slices)); + po.m_supportdata = + std::make_unique( + po.m_preview_meshes[slaposObjectSlice] + ); po.m_supportdata->input.zoffset = csgmesh_positive_bb(po.m_mesh_to_slice) .min.z(); diff --git a/src/libslic3r/SLAPrintSteps.hpp b/src/libslic3r/SLAPrintSteps.hpp index 1a1900153d..30dff8628e 100644 --- a/src/libslic3r/SLAPrintSteps.hpp +++ b/src/libslic3r/SLAPrintSteps.hpp @@ -44,6 +44,8 @@ private: void initialize_printer_input(); void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o); + + void generate_preview(SLAPrintObject &po, SLAPrintObjectStep step); public: explicit Steps(SLAPrint *print); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index e65a321f1d..103ab339c2 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -852,73 +852,73 @@ int GLVolumeCollection::load_object_volume( return int(this->volumes.size() - 1); } -// Load SLA auxiliary GLVolumes (for support trees or pad). -// This function produces volumes for multiple instances in a single shot, -// as some object specific mesh conversions may be expensive. -#if ENABLE_LEGACY_OPENGL_REMOVAL -void GLVolumeCollection::load_object_auxiliary( - const SLAPrintObject* print_object, - int obj_idx, - // pairs of - const std::vector>& instances, - SLAPrintObjectStep milestone, - // Timestamp of the last change of the milestone - size_t timestamp) -#else -void GLVolumeCollection::load_object_auxiliary( - const SLAPrintObject *print_object, - int obj_idx, - // pairs of - const std::vector>& instances, - SLAPrintObjectStep milestone, - // Timestamp of the last change of the milestone - size_t timestamp, - bool opengl_initialized) -#endif // ENABLE_LEGACY_OPENGL_REMOVAL -{ - assert(print_object->is_step_done(milestone)); - Transform3d mesh_trafo_inv = print_object->trafo().inverse(); - // Get the support mesh. - TriangleMesh mesh = print_object->get_mesh(milestone); - mesh.transform(mesh_trafo_inv); - // Convex hull is required for out of print bed detection. - TriangleMesh convex_hull = mesh.convex_hull_3d(); - for (const std::pair& instance_idx : instances) { - const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; - this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); - GLVolume& v = *this->volumes.back(); -#if ENABLE_LEGACY_OPENGL_REMOVAL -#if ENABLE_SMOOTH_NORMALS - v.model.init_from(mesh, true); -#else - v.model.init_from(mesh); - 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); -#else - v.indexed_vertex_array.load_mesh(mesh); -#endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(opengl_initialized); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); - v.geometry_id = std::pair(timestamp, model_instance.id().id); - // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. - if (&instance_idx == &instances.back()) - v.set_convex_hull(std::move(convex_hull)); - else - v.set_convex_hull(convex_hull); - v.is_modifier = false; - v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree); - v.set_instance_transformation(model_instance.get_transformation()); - // Leave the volume transformation at identity. - // v.set_volume_transformation(model_volume->get_transformation()); - } -} +//// Load SLA auxiliary GLVolumes (for support trees or pad). +//// This function produces volumes for multiple instances in a single shot, +//// as some object specific mesh conversions may be expensive. +//#if ENABLE_LEGACY_OPENGL_REMOVAL +//void GLVolumeCollection::load_object_auxiliary( +// const SLAPrintObject* print_object, +// int obj_idx, +// // pairs of +// const std::vector>& instances, +// SLAPrintObjectStep milestone, +// // Timestamp of the last change of the milestone +// size_t timestamp) +//#else +//void GLVolumeCollection::load_object_auxiliary( +// const SLAPrintObject *print_object, +// int obj_idx, +// // pairs of +// const std::vector>& instances, +// SLAPrintObjectStep milestone, +// // Timestamp of the last change of the milestone +// size_t timestamp, +// bool opengl_initialized) +//#endif // ENABLE_LEGACY_OPENGL_REMOVAL +//{ +// assert(print_object->is_step_done(milestone)); +// Transform3d mesh_trafo_inv = print_object->trafo().inverse(); +// // Get the support mesh. +// TriangleMesh mesh = print_object->get_mesh(milestone); +// mesh.transform(mesh_trafo_inv); +// // Convex hull is required for out of print bed detection. +// TriangleMesh convex_hull = mesh.convex_hull_3d(); +// for (const std::pair& instance_idx : instances) { +// const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; +// this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); +// GLVolume& v = *this->volumes.back(); +//#if ENABLE_LEGACY_OPENGL_REMOVAL +//#if ENABLE_SMOOTH_NORMALS +// v.model.init_from(mesh, true); +//#else +// v.model.init_from(mesh); +// 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); +//#else +// v.indexed_vertex_array.load_mesh(mesh); +//#endif // ENABLE_SMOOTH_NORMALS +// v.indexed_vertex_array.finalize_geometry(opengl_initialized); +//#endif // ENABLE_LEGACY_OPENGL_REMOVAL +// v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); +// v.geometry_id = std::pair(timestamp, model_instance.id().id); +// // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. +// if (&instance_idx == &instances.back()) +// v.set_convex_hull(std::move(convex_hull)); +// else +// v.set_convex_hull(convex_hull); +// v.is_modifier = false; +// v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree); +// v.set_instance_transformation(model_instance.get_transformation()); +// // Leave the volume transformation at identity. +// // v.set_volume_transformation(model_volume->get_transformation()); +// } +//} #if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_OPENGL_ES diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 1e8897c4e0..e63f095e47 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -659,14 +659,14 @@ public: int instance_idx); // Load SLA auxiliary GLVolumes (for support trees or pad). - void load_object_auxiliary( - const SLAPrintObject* print_object, - int obj_idx, - // pairs of - const std::vector>& instances, - SLAPrintObjectStep milestone, - // Timestamp of the last change of the milestone - size_t timestamp); +// void load_object_auxiliary( +// const SLAPrintObject* print_object, +// int obj_idx, +// // pairs of +// const std::vector>& instances, +// SLAPrintObjectStep milestone, +// // Timestamp of the last change of the milestone +// size_t timestamp); #if ENABLE_OPENGL_ES int load_wipe_tower_preview( diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8c98c603d5..d20e53643c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2189,143 +2189,146 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } } if (printer_technology == ptSLA) { - size_t idx = 0; - const SLAPrint *sla_print = this->sla_print(); - std::vector shift_zs(m_model->objects.size(), 0); - double relative_correction_z = sla_print->relative_correction().z(); - if (relative_correction_z <= EPSILON) - relative_correction_z = 1.; - for (const SLAPrintObject *print_object : sla_print->objects()) { - SLASupportState &state = sla_support_state[idx ++]; - const ModelObject *model_object = print_object->model_object(); - // Find an index of the ModelObject - int object_idx; - // There may be new SLA volumes added to the scene for this print_object. - // Find the object index of this print_object in the Model::objects list. - auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object); - assert(it != sla_print->model().objects.end()); - object_idx = it - sla_print->model().objects.begin(); - // Cache the Z offset to be applied to all volumes with this object_idx. - shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z; - // Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene. - // pairs of - std::vector> instances[std::tuple_size::value]; - for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) { - const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx]; - // Find index of ModelInstance corresponding to this SLAPrintObject::Instance. - auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), - [&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; }); - assert(it != model_object->instances.end()); - int instance_idx = it - model_object->instances.begin(); - for (size_t istep = 0; istep < sla_steps.size(); ++ istep) - if (sla_steps[istep] == slaposDrillHoles) { - // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, - // not into its own GLVolume. - // There shall always be such a GLVolume allocated. - ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); - auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); - assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); - assert(!it->new_geometry()); - GLVolume &volume = *m_volumes.volumes[it->volume_idx]; - if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { - // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. -#if ENABLE_LEGACY_OPENGL_REMOVAL - volume.model.reset(); -#else - volume.indexed_vertex_array.release_geometry(); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - if (state.step[istep].state == PrintStateBase::DONE) { - TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); - assert(! mesh.empty()); +// size_t idx = 0; +// const SLAPrint *sla_print = this->sla_print(); +// std::vector shift_zs(m_model->objects.size(), 0); +// double relative_correction_z = sla_print->relative_correction().z(); +// if (relative_correction_z <= EPSILON) +// relative_correction_z = 1.; +// for (const SLAPrintObject *print_object : sla_print->objects()) { +// SLASupportState &state = sla_support_state[idx ++]; +// const ModelObject *model_object = print_object->model_object(); +// // Find an index of the ModelObject +// int object_idx; +// // There may be new SLA volumes added to the scene for this print_object. +// // Find the object index of this print_object in the Model::objects list. +// auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object); +// assert(it != sla_print->model().objects.end()); +// object_idx = it - sla_print->model().objects.begin(); +// // Cache the Z offset to be applied to all volumes with this object_idx. +// shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z; +// // Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene. +// // pairs of +// std::vector> instances[std::tuple_size::value]; +// for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) { +// const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx]; +// // Find index of ModelInstance corresponding to this SLAPrintObject::Instance. +// auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), +// [&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; }); +// assert(it != model_object->instances.end()); +// int instance_idx = it - model_object->instances.begin(); +// for (size_t istep = 0; istep < sla_steps.size(); ++ istep) +// if (sla_steps[istep] == slaposDrillHoles) { +// // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, +// // not into its own GLVolume. +// // There shall always be such a GLVolume allocated. +// ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); +// auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); +// assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); +// assert(!it->new_geometry()); +// GLVolume &volume = *m_volumes.volumes[it->volume_idx]; +// if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { +// // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. +//#if ENABLE_LEGACY_OPENGL_REMOVAL +// volume.model.reset(); +//#else +// volume.indexed_vertex_array.release_geometry(); +//#endif // ENABLE_LEGACY_OPENGL_REMOVAL +// if (state.step[istep].state == PrintStateBase::DONE) { +// TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); +// assert(! mesh.empty()); - // sla_trafo does not contain volume trafo. To get a mesh to create - // a new volume from, we have to apply vol trafo inverse separately. - const ModelObject& mo = *m_model->objects[volume.object_idx()]; - Transform3d trafo = sla_print->sla_trafo(mo) - * mo.volumes.front()->get_transformation().get_matrix(); - mesh.transform(trafo.inverse()); -#if ENABLE_SMOOTH_NORMALS -#if ENABLE_LEGACY_OPENGL_REMOVAL - volume.model.init_from(mesh, true); -#else - volume.indexed_vertex_array.load_mesh(mesh, true); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL -#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 -#endif // ENABLE_SMOOTH_NORMALS - } - else { - // Reload the original volume. -#if ENABLE_SMOOTH_NORMALS -#if ENABLE_LEGACY_OPENGL_REMOVAL - volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); -#else - volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); -#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 -#endif // ENABLE_SMOOTH_NORMALS - } -#if !ENABLE_LEGACY_OPENGL_REMOVAL - volume.finalize_geometry(true); -#endif // !ENABLE_LEGACY_OPENGL_REMOVAL - } - //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable - // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables - // of various concenrs (model vs. 3D print path). - volume.offsets = { state.step[istep].timestamp }; - } - else if (state.step[istep].state == PrintStateBase::DONE) { - // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. - ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); - auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); - assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); - if (it->new_geometry()) { - // This can be an SLA support structure that should not be rendered (in case someone used undo - // to revert to before it was generated). If that's the case, we should not generate anything. - if (model_object->sla_points_status != sla::PointsStatus::NoPoints) - instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); - else - shift_zs[object_idx] = 0.; - } - else { - // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. - m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); - m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); - } - } +// // sla_trafo does not contain volume trafo. To get a mesh to create +// // a new volume from, we have to apply vol trafo inverse separately. +// const ModelObject& mo = *m_model->objects[volume.object_idx()]; +// Transform3d trafo = sla_print->sla_trafo(mo) +// * mo.volumes.front()->get_transformation().get_matrix(); +// mesh.transform(trafo.inverse()); +//#if ENABLE_SMOOTH_NORMALS +//#if ENABLE_LEGACY_OPENGL_REMOVAL +// volume.model.init_from(mesh, true); +//#else +// volume.indexed_vertex_array.load_mesh(mesh, true); +//#endif // ENABLE_LEGACY_OPENGL_REMOVAL +//#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 +//#endif // ENABLE_SMOOTH_NORMALS +// } +// else { +// // Reload the original volume. +//#if ENABLE_SMOOTH_NORMALS +//#if ENABLE_LEGACY_OPENGL_REMOVAL +// volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); +//#else +// volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); +//#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 +//#endif // ENABLE_SMOOTH_NORMALS +// } +//#if !ENABLE_LEGACY_OPENGL_REMOVAL +// volume.finalize_geometry(true); +//#endif // !ENABLE_LEGACY_OPENGL_REMOVAL +// } +// //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable +// // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables +// // of various concenrs (model vs. 3D print path). +// volume.offsets = { state.step[istep].timestamp }; +// } +// else if (state.step[istep].state == PrintStateBase::DONE) { +// // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. +// ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); +// auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); +// assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); +// if (it->new_geometry()) { +// // This can be an SLA support structure that should not be rendered (in case someone used undo +// // to revert to before it was generated). If that's the case, we should not generate anything. +// if (model_object->sla_points_status != sla::PointsStatus::NoPoints) +// instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); +// else +// shift_zs[object_idx] = 0.; +// } +// else { +// // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. +// m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); +// m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); +// } +// } +// } + +// for (size_t istep = 0; istep < sla_steps.size(); ++istep) +// if (!instances[istep].empty()) +//#if ENABLE_LEGACY_OPENGL_REMOVAL +// m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); +//#else +// m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); +//#endif // ENABLE_LEGACY_OPENGL_REMOVAL +// } + + // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed + for (GLVolume* volume : m_volumes.volumes) + if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) { + const SLAPrintObject *po = sla_print()->objects()[volume->object_idx()]; + float zoffs = po->get_current_elevation() / sla_print()->relative_correction().z(); + volume->set_sla_shift_z(zoffs); } - - for (size_t istep = 0; istep < sla_steps.size(); ++istep) - if (!instances[istep].empty()) -#if ENABLE_LEGACY_OPENGL_REMOVAL - m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); -#else - m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); -#endif // ENABLE_LEGACY_OPENGL_REMOVAL - } - - // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed - for (GLVolume* volume : m_volumes.volumes) - if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) - volume->set_sla_shift_z(shift_zs[volume->object_idx()]); } if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) { @@ -7635,7 +7638,7 @@ void GLCanvas3D::_load_sla_shells() // adds objects' volumes for (const SLAPrintObject* obj : print->objects()) - if (obj->is_step_done(slaposSliceSupports)) { + /*if (obj->is_step_done(slaposSliceSupports))*/ { unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); for (const SLAPrintObject::Instance& instance : obj->instances()) { add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 394e879b7c..52ae9b25b4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -281,10 +281,10 @@ void HollowedMesh::on_update() // If there is a valid SLAPrintObject, check state of Hollowing step. if (print_object) { - if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) { + if (print_object->is_step_done(slaposDrillHoles) && !print_object->get_mesh_to_print().empty()) { size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp; if (timestamp > m_old_hollowing_timestamp) { - const TriangleMesh& backend_mesh = print_object->get_mesh_to_slice(); + const TriangleMesh& backend_mesh = print_object->get_mesh_to_print(); if (! backend_mesh.empty()) { m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh)); Transform3d trafo_inv = (canvas->sla_print()->sla_trafo(*mo) * print_object->model_object()->volumes.front()->get_transformation().get_matrix()).inverse(); @@ -292,10 +292,10 @@ void HollowedMesh::on_update() m_drainholes = print_object->model_object()->sla_drain_holes; m_old_hollowing_timestamp = timestamp; - indexed_triangle_set interior = print_object->hollowed_interior_mesh(); - its_flip_triangles(interior); - m_hollowed_interior_transformed = std::make_unique(std::move(interior)); - m_hollowed_interior_transformed->transform(trafo_inv); +// indexed_triangle_set interior = print_object->hollowed_interior_mesh(); +// its_flip_triangles(interior); +// m_hollowed_interior_transformed = std::make_unique(std::move(interior)); +// m_hollowed_interior_transformed->transform(trafo_inv); } else { m_hollowed_mesh_transformed.reset(nullptr); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 5764b283c6..b0f06541c1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -944,7 +944,7 @@ bool MainFrame::can_export_supports() const const PrintObjects& objects = m_plater->sla_print().objects(); for (const SLAPrintObject* object : objects) { - if (object->has_mesh(slaposPad) || object->has_mesh(slaposSupportTree)) + if (!object->support_mesh().empty()) { can_export = true; break; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e11e08d043..d4b279f606 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6155,19 +6155,13 @@ void Plater::export_stl_obj(bool extended, bool selection_only) const Transform3d mesh_trafo_inv = object->trafo().inverse(); const bool is_left_handed = object->is_left_handed(); - TriangleMesh pad_mesh; - const bool has_pad_mesh = extended && object->has_mesh(slaposPad); - if (has_pad_mesh) { - pad_mesh = object->get_mesh(slaposPad); - pad_mesh.transform(mesh_trafo_inv); - } + auto pad_mesh = extended? object->pad_mesh() : TriangleMesh{}; + pad_mesh = object->pad_mesh(); + pad_mesh.transform(mesh_trafo_inv); + + auto supports_mesh = extended ? object->support_mesh() : TriangleMesh{}; + supports_mesh.transform(mesh_trafo_inv); - TriangleMesh supports_mesh; - const bool has_supports_mesh = extended && object->has_mesh(slaposSupportTree); - if (has_supports_mesh) { - supports_mesh = object->get_mesh(slaposSupportTree); - supports_mesh.transform(mesh_trafo_inv); - } const std::vector& obj_instances = object->instances(); for (const SLAPrintObject::Instance& obj_instance : obj_instances) { auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), @@ -6184,19 +6178,19 @@ void Plater::export_stl_obj(bool extended, bool selection_only) TriangleMesh inst_mesh; - if (has_pad_mesh) { + if (!pad_mesh.empty()) { TriangleMesh inst_pad_mesh = pad_mesh; inst_pad_mesh.transform(inst_transform, is_left_handed); inst_mesh.merge(inst_pad_mesh); } - if (has_supports_mesh) { + if (!supports_mesh.empty()) { TriangleMesh inst_supports_mesh = supports_mesh; inst_supports_mesh.transform(inst_transform, is_left_handed); inst_mesh.merge(inst_supports_mesh); } - TriangleMesh inst_object_mesh = object->get_mesh_to_slice(); + TriangleMesh inst_object_mesh = object->get_mesh_to_print(); inst_object_mesh.transform(mesh_trafo_inv); inst_object_mesh.transform(inst_transform, is_left_handed);