From f913be2d93ff69c0fdf2f6db36cb735ed7f48fb3 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 5 Nov 2019 17:00:11 +0100 Subject: [PATCH 1/6] Streamlined hollowing method. --- tests/libslic3r/test_hollowing.cpp | 43 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index 4b7465a3da..8f57828a10 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -22,39 +22,46 @@ static Slic3r::TriangleMesh load_model(const std::string &obj_filename) return mesh; } -TEST_CASE("Negative 3D offset should produce smaller object.", "[Hollowing]") +static Slic3r::TriangleMesh hollowed_interior(const Slic3r::TriangleMesh &mesh, + double min_thickness) { - Slic3r::TriangleMesh in_mesh = load_model("20mm_cube.obj"); - in_mesh.scale(3.); - Slic3r::sla::Contour3D imesh = Slic3r::sla::Contour3D{in_mesh}; + Slic3r::sla::Contour3D imesh = Slic3r::sla::Contour3D{mesh}; - Benchmark bench; - bench.start(); + double scale = std::max(1.0, 3. / min_thickness); + double offset = scale * min_thickness; + float range = float(std::max(2 * offset, scale)); - openvdb::math::Transform tr; - auto ptr = Slic3r::meshToVolume(imesh, {}, 0.0f, 10.0f); + for (auto &p : imesh.points) p *= scale; + auto ptr = Slic3r::meshToVolume(imesh, {}, 0.1f * float(offset), range); REQUIRE(ptr); - openvdb::tools::Filter{*ptr}.gaussian(1, 3); + openvdb::tools::Filter{*ptr}.gaussian(int(scale), 1); - - double iso_surface = -3.0; - double adaptivity = 0.5; + double iso_surface = -offset; + double adaptivity = 0.; Slic3r::sla::Contour3D omesh = Slic3r::volumeToMesh(*ptr, iso_surface, adaptivity); REQUIRE(!omesh.empty()); - imesh.merge(omesh); + for (auto &p : omesh.points) p /= scale; - for (auto &p : imesh.points) p /= 3.; + return to_triangle_mesh(omesh); +} + +TEST_CASE("Negative 3D offset should produce smaller object.", "[Hollowing]") +{ + Slic3r::TriangleMesh in_mesh = load_model("20mm_cube.obj"); + Benchmark bench; + bench.start(); + + Slic3r::TriangleMesh out_mesh = hollowed_interior(in_mesh, 2); bench.stop(); std::cout << "Elapsed processing time: " << bench.getElapsedSec() << std::endl; - std::fstream merged_outfile("merged_out.obj", std::ios::out); - imesh.to_obj(merged_outfile); - std::fstream outfile("out.obj", std::ios::out); - omesh.to_obj(outfile); + in_mesh.merge(out_mesh); + in_mesh.require_shared_vertices(); + in_mesh.WriteOBJFile("merged_out.obj"); } From bdf6f7342ef539a3f198aa0446311b3add9bd820 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 6 Nov 2019 13:38:43 +0100 Subject: [PATCH 2/6] Hollowing step in SLAPrint process, PrintConfig params added. --- resources/icons/hollowing.svg | 25 +++++ resources/icons/white/hollowing.svg | 25 +++++ src/libslic3r/Model.cpp | 7 +- src/libslic3r/OpenVDBUtils.cpp | 122 ++++++++++++++++++++---- src/libslic3r/OpenVDBUtils.hpp | 23 +++-- src/libslic3r/PrintConfig.cpp | 16 ++++ src/libslic3r/PrintConfig.hpp | 22 ++++- src/libslic3r/SLAPrint.cpp | 56 ++++++++++- src/libslic3r/SLAPrint.hpp | 10 +- src/slic3r/GUI/GUI_ObjectList.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 22 +++-- src/slic3r/GUI/Preset.cpp | 2 + src/slic3r/GUI/Tab.cpp | 5 + tests/libslic3r/test_hollowing.cpp | 40 ++++---- 14 files changed, 311 insertions(+), 65 deletions(-) create mode 100644 resources/icons/hollowing.svg create mode 100644 resources/icons/white/hollowing.svg diff --git a/resources/icons/hollowing.svg b/resources/icons/hollowing.svg new file mode 100644 index 0000000000..65c7592c83 --- /dev/null +++ b/resources/icons/hollowing.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/white/hollowing.svg b/resources/icons/white/hollowing.svg new file mode 100644 index 0000000000..65c7592c83 --- /dev/null +++ b/resources/icons/white/hollowing.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 061c5bd50a..607f11bc65 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1142,7 +1142,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_upper) { upper->add_volume(*volume); } if (keep_lower) { lower->add_volume(*volume); } } - else { + else if (! volume->mesh().empty()) { + TriangleMesh upper_mesh, lower_mesh; // Transform the mesh by the combined transformation matrix. @@ -1150,7 +1151,9 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b TriangleMesh mesh(volume->mesh()); mesh.transform(instance_matrix * volume_matrix, true); volume->reset_mesh(); - + + mesh.require_shared_vertices(); + // Perform cut TriangleMeshSlicer tms(&mesh); tms.cut(float(z), &upper_mesh, &lower_mesh); diff --git a/src/libslic3r/OpenVDBUtils.cpp b/src/libslic3r/OpenVDBUtils.cpp index 97a57315b6..08c69bdb5d 100644 --- a/src/libslic3r/OpenVDBUtils.cpp +++ b/src/libslic3r/OpenVDBUtils.cpp @@ -2,6 +2,9 @@ #include "OpenVDBUtils.hpp" #include #include +#include +#include +#include "MTUtils.hpp" namespace Slic3r { @@ -50,6 +53,11 @@ void Contour3DDataAdapter::getIndexSpacePoint(size_t n, pos = {p.x(), p.y(), p.z()}; } + +// TODO: Do I need to call initialize? Seems to work without it as well but the +// docs say it should be called ones. It does a mutex lock-unlock sequence all +// even if was called previously. + openvdb::FloatGrid::Ptr meshToVolume(const TriangleMesh &mesh, const openvdb::math::Transform &tr, float exteriorBandWidth, @@ -62,11 +70,7 @@ openvdb::FloatGrid::Ptr meshToVolume(const TriangleMesh &mesh, interiorBandWidth, flags); } -// TODO: Do I need to call initialize? Seems to work without it as well but the -// docs say it should be called ones. It does a mutex lock-unlock sequence all -// even if was called previously. - -openvdb::FloatGrid::Ptr meshToVolume(const sla::Contour3D & mesh, +static openvdb::FloatGrid::Ptr meshToVolume(const sla::Contour3D &mesh, const openvdb::math::Transform &tr, float exteriorBandWidth, float interiorBandWidth, @@ -84,10 +88,10 @@ inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[0]), int(v[1 inline Vec4i to_vec4i(const openvdb::Vec4I &v) { return Vec4i{int(v[0]), int(v[1]), int(v[2]), int(v[3])}; } template -sla::Contour3D _volumeToMesh(const Grid &grid, - double isovalue, - double adaptivity, - bool relaxDisorientedTriangles) +sla::Contour3D __volumeToMesh(const Grid &grid, + double isovalue, + double adaptivity, + bool relaxDisorientedTriangles) { openvdb::initialize(); @@ -102,20 +106,106 @@ sla::Contour3D _volumeToMesh(const Grid &grid, ret.points.reserve(points.size()); ret.faces3.reserve(triangles.size()); ret.faces4.reserve(quads.size()); - + for (auto &v : points) ret.points.emplace_back(to_vec3d(v)); for (auto &v : triangles) ret.faces3.emplace_back(to_vec3i(v)); for (auto &v : quads) ret.faces4.emplace_back(to_vec4i(v)); - + return ret; } -sla::Contour3D volumeToMesh(const openvdb::FloatGrid &grid, - double isovalue, - double adaptivity, - bool relaxDisorientedTriangles) +template inline +Mesh _volumeToMesh(const openvdb::FloatGrid &grid, + double isovalue = 0.0, + double adaptivity = 0.0, + bool relaxDisorientedTriangles = true); + +template<> inline +TriangleMesh _volumeToMesh(const openvdb::FloatGrid &grid, + double isovalue, + double adaptivity, + bool relaxDisorientedTriangles) { - return _volumeToMesh(grid, isovalue, adaptivity, relaxDisorientedTriangles); + return to_triangle_mesh(__volumeToMesh(grid, isovalue, adaptivity, + relaxDisorientedTriangles)); +} + +template<> inline +sla::Contour3D _volumeToMesh(const openvdb::FloatGrid &grid, + double isovalue, + double adaptivity, + bool relaxDisorientedTriangles) +{ + return __volumeToMesh(grid, isovalue, adaptivity, + relaxDisorientedTriangles); +} + +TriangleMesh volumeToMesh(const openvdb::FloatGrid &grid, + double isovalue, + double adaptivity, + bool relaxDisorientedTriangles) +{ + return _volumeToMesh(grid, isovalue, adaptivity, + relaxDisorientedTriangles); +} + +template> +inline void _scale(S s, TriangleMesh &m) { m.scale(float(s)); } + +template> +inline void _scale(S s, sla::Contour3D &m) +{ + for (auto &p : m.points) p *= s; +} + +template +remove_cvref_t _hollowed_interior(Mesh &&mesh, + double min_thickness, + int oversampling, + double smoothing) +{ + using MMesh = remove_cvref_t; + MMesh imesh{std::forward(mesh)}; + + // I can't figure out how to increase the grid resolution through openvdb API + // so the model will be scaled up before conversion and the result scaled + // down. Voxels have a unit size. If I set voxelSize smaller, it scales + // the whole geometry down, and doesn't increase the number of voxels. + auto scale = double(oversampling); + + _scale(scale, imesh); + + double offset = scale * min_thickness; + float range = float(std::max(2 * offset, scale)); + auto gridptr = meshToVolume(imesh, {}, 0.1f * float(offset), range); + + assert(gridptr); + + if (!gridptr) { + BOOST_LOG_TRIVIAL(error) << "Returned OpenVDB grid is NULL"; + return MMesh{}; + } + + // Filtering: + int width = int(smoothing * scale); + int count = 1; + openvdb::tools::Filter{*gridptr}.gaussian(width, count); + + double iso_surface = -offset; + double adaptivity = 0.; + auto omesh = _volumeToMesh(*gridptr, iso_surface, adaptivity); + + _scale(1. / scale, omesh); + + return omesh; +} + +TriangleMesh hollowed_interior(const TriangleMesh &mesh, + double min_thickness, + int oversampling, + double smoothing) +{ + return _hollowed_interior(mesh, min_thickness, oversampling, smoothing); } } // namespace Slic3r diff --git a/src/libslic3r/OpenVDBUtils.hpp b/src/libslic3r/OpenVDBUtils.hpp index eae1e051dc..8e55300bd2 100644 --- a/src/libslic3r/OpenVDBUtils.hpp +++ b/src/libslic3r/OpenVDBUtils.hpp @@ -13,16 +13,21 @@ openvdb::FloatGrid::Ptr meshToVolume(const TriangleMesh & mesh, float interiorBandWidth = 3.0f, int flags = 0); -openvdb::FloatGrid::Ptr meshToVolume(const sla::Contour3D & mesh, - const openvdb::math::Transform &tr = {}, - float exteriorBandWidth = 3.0f, - float interiorBandWidth = 3.0f, - int flags = 0); +TriangleMesh volumeToMesh(const openvdb::FloatGrid &grid, + double isovalue = 0.0, + double adaptivity = 0.0, + bool relaxDisorientedTriangles = true); -sla::Contour3D volumeToMesh(const openvdb::FloatGrid &grid, - double isovalue = 0.0, - double adaptivity = 0.0, - bool relaxDisorientedTriangles = true); +sla::Contour3D hollowed_interior(sla::Contour3D&& mesh, double min_thickness); +sla::Contour3D hollowed_interior(sla::Contour3D& mesh, double min_thickness); + +// Generate an interior for any solid geometry maintaining a given minimum +// wall thickness. The returned mesh has triangles with normals facing inside +// the mesh so the result can be directly merged with the input to finish the +// hollowing. +// TODO: The thicknes is not strictly maintained due to the used gaussian filter +TriangleMesh hollowed_interior(const TriangleMesh &mesh, double min_thickness, + int oversampling = 3, double smoothing = 0.5); } // namespace Slic3r diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e639a6734d..4cfd81bc55 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2830,6 +2830,22 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.3)); + + def = this->add("hollowing_enable", coBool); + def->label = L("Enable hollowing"); + def->category = L("Hollowing"); + def->tooltip = L("Hollow out a model to have an empty interior"); + def->mode = comSimple; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("hollowing_min_thickness", coFloat); + def->label = L("Hollowing thickness"); + def->category = L("Hollowing"); + def->tooltip = L("Minimum wall thickness of a hollowed model."); + def->sidetext = L("mm"); + def->min = 1; + def->mode = comSimple; + def->set_default_value(new ConfigOptionFloat(4)); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 4b007fc51c..6bcc3f9ad2 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1014,7 +1014,7 @@ public: ConfigOptionFloat support_base_height /*= 1.0*/; // The minimum distance of the pillar base from the model in mm. - ConfigOptionFloat support_base_safety_distance; /*= 1.0*/; + ConfigOptionFloat support_base_safety_distance; /*= 1.0*/ // The default angle for connecting support sticks and junctions. ConfigOptionFloat support_critical_angle /*= 45*/; @@ -1059,7 +1059,7 @@ public: // ///////////////////////////////////////////////////////////////////////// // Zero elevation mode parameters: - // - The object pad will be derived from the the model geometry. + // - The object pad will be derived from the model geometry. // - There will be a gap between the object pad and the generated pad // according to the support_base_safety_distance parameter. // - The two pads will be connected with tiny connector sticks @@ -1081,6 +1081,22 @@ public: // How much should the tiny connectors penetrate into the model body ConfigOptionFloat pad_object_connector_penetration; + + // ///////////////////////////////////////////////////////////////////////// + // Model hollowing parameters: + // - Models can be hollowed out as part of the SLA print process + // - Thickness of the hollowed model walls can be adjusted + // - + // - Additional holes will be drilled into the hollow model to allow for + // - resin removal. + // ///////////////////////////////////////////////////////////////////////// + + ConfigOptionBool hollowing_enable; + + // The minimum thickness of the model walls to maintain. Note that the + // resulting walls may be thicker due to smoothing out fine cavities where + // resin could stuck. + ConfigOptionFloat hollowing_min_thickness; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -1118,6 +1134,8 @@ protected: OPT_PTR(pad_object_connector_stride); OPT_PTR(pad_object_connector_width); OPT_PTR(pad_object_connector_penetration); + OPT_PTR(hollowing_enable); + OPT_PTR(hollowing_min_thickness); } }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 8c03853e3d..0f5cb20b8c 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -3,6 +3,7 @@ #include "SLA/SLAPad.hpp" #include "SLA/SLAAutoSupports.hpp" #include "ClipperUtils.hpp" +#include "OpenVDBUtils.hpp" #include "Geometry.hpp" #include "MTUtils.hpp" @@ -47,6 +48,14 @@ public: } }; +class SLAPrintObject::HollowingData +{ +public: + + TriangleMesh interior; + // std::vector +}; + namespace { // should add up to 100 (%) @@ -752,6 +761,28 @@ void SLAPrint::process() // the coefficient that multiplies the per object status values which // are set up for <0, 100>. They need to be scaled into the whole process const double ostepd = (max_objstatus - min_objstatus) / (objcount * 100.0); + + auto hollow_model = [](SLAPrintObject &po) { + + if (!po.m_config.hollowing_enable.getBool()) { + BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!"; + po.m_hollowing_data.reset(); + return; + } else { + BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!"; + } + + if (!po.m_hollowing_data) + po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); + + double thickness = po.m_config.hollowing_min_thickness.getFloat(); + + po.m_hollowing_data->interior = + hollowed_interior(po.transformed_mesh(), thickness, 4, 0.5); + + if (po.m_hollowing_data->interior.empty()) + BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!"; + }; // The slicing will be performed on an imaginary 1D grid which starts from // the bottom of the bounding box created around the supported model. So @@ -765,7 +796,20 @@ void SLAPrint::process() // Slicing the model object. This method is oversimplified and needs to // be compared with the fff slicing algorithm for verification auto slice_model = [this, ilhs, ilh](SLAPrintObject& po) { - const TriangleMesh& mesh = po.transformed_mesh(); + + TriangleMesh hollowed_mesh; + + bool is_hollowing = po.m_config.hollowing_enable.getBool() && + po.m_hollowing_data; + + if (is_hollowing) { + hollowed_mesh = po.transformed_mesh(); + hollowed_mesh.merge(po.m_hollowing_data->interior); + hollowed_mesh.require_shared_vertices(); + } + + const TriangleMesh &mesh = is_hollowing ? hollowed_mesh : + po.transformed_mesh(); // We need to prepare the slice index... @@ -1465,12 +1509,12 @@ void SLAPrint::process() slaposFn pobj_program[] = { - [](SLAPrintObject&){}, slice_model, [](SLAPrintObject&){}, support_points, support_tree, generate_pad, slice_supports + hollow_model, slice_model, [](SLAPrintObject&){}, support_points, support_tree, generate_pad, slice_supports }; // We want to first process all objects... std::vector level1_obj_steps = { - slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposPad + slaposHollowing, slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposPad }; // and then slice all supports to allow preview to be displayed ASAP @@ -1707,7 +1751,11 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector steps; bool invalidated = false; for (const t_config_option_key &opt_key : opt_keys) { - if ( opt_key == "layer_height" + if ( opt_key == "hollowing_enable" + || opt_key == "hollowing_min_thickness") { + steps.emplace_back(slaposHollowing); + } else if ( + opt_key == "layer_height" || opt_key == "faded_layers" || opt_key == "pad_enable" || opt_key == "pad_wall_thickness" diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 38e3737754..1b8b126e23 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -74,8 +74,11 @@ public: // Support mesh is only valid if this->is_step_done(slaposSupportTree) is true. const TriangleMesh& support_mesh() const; // Get a pad mesh centered around origin in XY, and with zero rotation around Z applied. - // Support mesh is only valid if this->is_step_done(slaposBasePool) is true. + // Support mesh is only valid if this->is_step_done(slaposPad) is true. const TriangleMesh& pad_mesh() const; + + // Ready after this->is_step_done(slaposHollowing) is true + const TriangleMesh& hollowed_interior_mesh() const; // This will return the transformed mesh which is cached const TriangleMesh& transformed_mesh() const; @@ -288,9 +291,12 @@ private: // Caching the transformed (m_trafo) raw mesh of the object mutable CachedObject m_transformed_rmesh; - + class SupportData; std::unique_ptr m_supportdata; + + class HollowingData; + std::unique_ptr m_hollowing_data; }; using PrintObjects = std::vector; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index a88980a8d4..45d55c0b94 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -98,6 +98,7 @@ ObjectList::ObjectList(wxWindow* parent) : // ptSLA CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(nullptr, "support"/*"sla_supports"*/); CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(nullptr, "pad"); + CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap(nullptr, "hollowing"); } // create control diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 5b6620ef68..34173366d2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -597,16 +597,20 @@ void GLGizmoHollow::on_update(const UpdateData& data) void GLGizmoHollow::hollow_mesh(float offset, float adaptibility) { - Slic3r::sla::Contour3D imesh{*m_mesh}; - auto ptr = meshToVolume(imesh, {}); - sla::Contour3D omesh = volumeToMesh(*ptr, -offset, adaptibility, true); +// Slic3r::sla::Contour3D imesh{*m_mesh}; +// auto ptr = meshToVolume(imesh, {}); +// sla::Contour3D omesh = volumeToMesh(*ptr, -offset, adaptibility, true); - if (omesh.empty()) +// if (omesh.empty()) +// return; + +// imesh.merge(omesh); + TriangleMesh cavity = hollowed_interior(*m_mesh, double(offset), int(adaptibility)); + if (cavity.empty()) return; - - imesh.merge(omesh); - m_cavity_mesh.reset(new TriangleMesh); - *m_cavity_mesh = sla::to_triangle_mesh(imesh); + + m_cavity_mesh.reset(new TriangleMesh(cavity)); + m_cavity_mesh->merge(*m_mesh); m_cavity_mesh.get()->require_shared_vertices(); m_mesh_raycaster.reset(new MeshRaycaster(*m_cavity_mesh.get())); m_object_clipper.reset(); @@ -616,7 +620,7 @@ void GLGizmoHollow::hollow_mesh(float offset, float adaptibility) m_volume_with_cavity->indexed_vertex_array.load_mesh(*m_cavity_mesh.get()); m_volume_with_cavity->finalize_geometry(true); m_volume_with_cavity->set_volume_transformation(m_model_object->volumes.front()->get_transformation()); - m_volume_with_cavity->set_instance_transformation(m_model_object->instances[m_active_instance]->get_transformation()); + m_volume_with_cavity->set_instance_transformation(m_model_object->instances[size_t(m_active_instance)]->get_transformation()); m_parent.toggle_model_objects_visibility(false, m_model_object, m_active_instance); } diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index a360aaf1a0..edbb5fb750 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -496,6 +496,8 @@ const std::vector& Preset::sla_print_options() "pad_object_connector_stride", "pad_object_connector_width", "pad_object_connector_penetration", + "hollowing_enable", + "hollowing_min_thickness", "output_filename_format", "default_sla_print_profile", "compatible_printers", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c2a258e69b..22c4bfb9bf 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3563,6 +3563,11 @@ void TabSLAPrint::build() optgroup->append_single_option_line("pad_object_connector_stride"); optgroup->append_single_option_line("pad_object_connector_width"); optgroup->append_single_option_line("pad_object_connector_penetration"); + + page = add_options_page(_(L("Hollowing")), "hollowing"); + optgroup = page->new_optgroup(_(L("Hollowing"))); + optgroup->append_single_option_line("hollowing_enable"); + optgroup->append_single_option_line("hollowing_min_thickness"); page = add_options_page(_(L("Advanced")), "wrench"); optgroup = page->new_optgroup(_(L("Slicing"))); diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index 8f57828a10..b463fd863e 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -22,40 +22,38 @@ static Slic3r::TriangleMesh load_model(const std::string &obj_filename) return mesh; } -static Slic3r::TriangleMesh hollowed_interior(const Slic3r::TriangleMesh &mesh, - double min_thickness) -{ - Slic3r::sla::Contour3D imesh = Slic3r::sla::Contour3D{mesh}; +//static Slic3r::TriangleMesh hollowed_interior(const Slic3r::TriangleMesh &mesh, +// double min_thickness) +//{ +// Slic3r::sla::Contour3D imesh = Slic3r::sla::Contour3D{mesh}; - double scale = std::max(1.0, 3. / min_thickness); - double offset = scale * min_thickness; - float range = float(std::max(2 * offset, scale)); +// double scale = std::max(1.0, 3. / min_thickness); +// double offset = scale * min_thickness; +// float range = float(std::max(2 * offset, scale)); - for (auto &p : imesh.points) p *= scale; - auto ptr = Slic3r::meshToVolume(imesh, {}, 0.1f * float(offset), range); +// for (auto &p : imesh.points) p *= scale; +// auto ptr = Slic3r::meshToVolume(imesh, {}, 0.1f * float(offset), range); - REQUIRE(ptr); +// REQUIRE(ptr); - openvdb::tools::Filter{*ptr}.gaussian(int(scale), 1); +// openvdb::tools::Filter{*ptr}.gaussian(int(scale), 1); - double iso_surface = -offset; - double adaptivity = 0.; - Slic3r::sla::Contour3D omesh = Slic3r::volumeToMesh(*ptr, iso_surface, adaptivity); +// double iso_surface = -offset; +// double adaptivity = 0.; +// Slic3r::sla::Contour3D omesh = Slic3r::volumeToMesh(*ptr, iso_surface, adaptivity); - REQUIRE(!omesh.empty()); +// for (auto &p : omesh.points) p /= scale; - for (auto &p : omesh.points) p /= scale; - - return to_triangle_mesh(omesh); -} +// return to_triangle_mesh(omesh); +//} TEST_CASE("Negative 3D offset should produce smaller object.", "[Hollowing]") { - Slic3r::TriangleMesh in_mesh = load_model("20mm_cube.obj"); + Slic3r::TriangleMesh in_mesh = load_model("zaba.obj"); Benchmark bench; bench.start(); - Slic3r::TriangleMesh out_mesh = hollowed_interior(in_mesh, 2); + Slic3r::TriangleMesh out_mesh = hollowed_interior(in_mesh, 0.5); bench.stop(); From a82f1268f328b3c38c049896cadde2a551dc2871 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 6 Nov 2019 14:25:03 +0100 Subject: [PATCH 3/6] Hollowed interior is now visible in preview --- src/libslic3r/SLAPrint.cpp | 8 ++++++++ src/slic3r/GUI/GLCanvas3D.cpp | 2 ++ src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 17 +++-------------- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 3 +-- tests/libslic3r/test_hollowing.cpp | 2 +- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 0f5cb20b8c..2e8a704005 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1975,6 +1975,14 @@ const TriangleMesh& SLAPrintObject::pad_mesh() const return EMPTY_MESH; } +const TriangleMesh &SLAPrintObject::hollowed_interior_mesh() const +{ + if (m_hollowing_data && m_config.hollowing_enable.getBool()) + return m_hollowing_data->interior; + + return EMPTY_MESH; +} + const TriangleMesh &SLAPrintObject::transformed_mesh() const { // we need to transform the raw mesh... // currently all the instances share the same x and y rotation and scaling diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 268b4dc30b..52d1df3179 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5362,6 +5362,8 @@ void GLCanvas3D::_load_sla_shells() unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); for (const SLAPrintObject::Instance& instance : obj->instances()) { add_volume(*obj, 0, instance, obj->transformed_mesh(), GLVolume::MODEL_COLOR[0], true); + if (! obj->hollowed_interior_mesh().empty()) + add_volume(*obj, -int(slaposHollowing), instance, obj->hollowed_interior_mesh(), GLVolume::MODEL_COLOR[0], false); // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when // through the update_volumes_colors_by_extruder() call. m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 34173366d2..2c3620dd7b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -595,17 +595,9 @@ void GLGizmoHollow::on_update(const UpdateData& data) } -void GLGizmoHollow::hollow_mesh(float offset, float adaptibility) +void GLGizmoHollow::hollow_mesh(float offset) { -// Slic3r::sla::Contour3D imesh{*m_mesh}; -// auto ptr = meshToVolume(imesh, {}); -// sla::Contour3D omesh = volumeToMesh(*ptr, -offset, adaptibility, true); - -// if (omesh.empty()) -// return; - -// imesh.merge(omesh); - TriangleMesh cavity = hollowed_interior(*m_mesh, double(offset), int(adaptibility)); + TriangleMesh cavity = hollowed_interior(*m_mesh, double(offset)); if (cavity.empty()) return; @@ -700,7 +692,7 @@ RENDER_AGAIN: if (m_editing_mode) { if (m_imgui->button(m_desc.at("hollow"))) { - hollow_mesh(m_offset, m_adaptibility); + hollow_mesh(m_offset); } float diameter_upper_cap = static_cast(wxGetApp().preset_bundle->sla_prints.get_edited_preset().config.option("support_pillar_diameter"))->value; @@ -762,9 +754,6 @@ RENDER_AGAIN: m_imgui->text("Offset: "); ImGui::SameLine(); ImGui::SliderFloat(" ", &m_offset, 0.f, 10.f, "%.1f"); - m_imgui->text("Adaptibility: "); - ImGui::SameLine(); - ImGui::SliderFloat(" ", &m_adaptibility, 0.f, 1.f, "%.1f"); } else { // not in editing mode: m_imgui->text(m_desc.at("minimal_distance")); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 82455a9f40..ba950594a2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -92,7 +92,7 @@ private: void render_clipping_plane(const Selection& selection) const; bool is_mesh_update_necessary() const; void update_mesh(); - void hollow_mesh(float offset = 2.f, float adaptability = 1.f); + void hollow_mesh(float offset = 2.f); bool unsaved_changes() const; const TriangleMesh* mesh() const; @@ -109,7 +109,6 @@ private: std::vector m_normal_cache; // to restore after discarding changes or undo/redo float m_offset = 2.f; - float m_adaptibility = 1.f; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index b463fd863e..9a2ea2e726 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -49,7 +49,7 @@ static Slic3r::TriangleMesh load_model(const std::string &obj_filename) TEST_CASE("Negative 3D offset should produce smaller object.", "[Hollowing]") { - Slic3r::TriangleMesh in_mesh = load_model("zaba.obj"); + Slic3r::TriangleMesh in_mesh = load_model("20mm_cube.obj"); Benchmark bench; bench.start(); From bc3d22348aa6ee03c86aeab93dbdd1d2da7694b9 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 7 Nov 2019 09:34:34 +0100 Subject: [PATCH 4/6] Hollowing params: accuracy and smoothness --- src/libslic3r/OpenVDBUtils.cpp | 28 ++++++++++++++++++------- src/libslic3r/OpenVDBUtils.hpp | 5 +---- src/libslic3r/PrintConfig.cpp | 19 +++++++++++++++++ src/libslic3r/PrintConfig.hpp | 9 ++++++++ src/libslic3r/SLAPrint.cpp | 10 ++++++--- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 24 +++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 9 ++++++-- src/slic3r/GUI/Preset.cpp | 2 ++ src/slic3r/GUI/Tab.cpp | 2 ++ 9 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/libslic3r/OpenVDBUtils.cpp b/src/libslic3r/OpenVDBUtils.cpp index 08c69bdb5d..53f9d5ae9f 100644 --- a/src/libslic3r/OpenVDBUtils.cpp +++ b/src/libslic3r/OpenVDBUtils.cpp @@ -158,20 +158,35 @@ inline void _scale(S s, sla::Contour3D &m) for (auto &p : m.points) p *= s; } +static void filter_grid(openvdb::FloatGrid &grid, double scale, double gain) +{ + static const double ROUNDNESS_COEFF = 1.; + + // Filtering: + if (gain > 0.) { + double rounding = ROUNDNESS_COEFF * gain; + int width = int(rounding * scale); + int count = 1; + openvdb::tools::Filter{grid}.gaussian(width, count); + } +} + template remove_cvref_t _hollowed_interior(Mesh &&mesh, double min_thickness, - int oversampling, + double accuracy, double smoothing) { using MMesh = remove_cvref_t; MMesh imesh{std::forward(mesh)}; + static const double ACCURACY_COEFF = 7.; + // I can't figure out how to increase the grid resolution through openvdb API // so the model will be scaled up before conversion and the result scaled // down. Voxels have a unit size. If I set voxelSize smaller, it scales // the whole geometry down, and doesn't increase the number of voxels. - auto scale = double(oversampling); + auto scale = (1.0 + ACCURACY_COEFF * accuracy); // max 8x upscale, min is native voxel size _scale(scale, imesh); @@ -186,10 +201,7 @@ remove_cvref_t _hollowed_interior(Mesh &&mesh, return MMesh{}; } - // Filtering: - int width = int(smoothing * scale); - int count = 1; - openvdb::tools::Filter{*gridptr}.gaussian(width, count); + filter_grid(*gridptr, scale, smoothing); double iso_surface = -offset; double adaptivity = 0.; @@ -202,10 +214,10 @@ remove_cvref_t _hollowed_interior(Mesh &&mesh, TriangleMesh hollowed_interior(const TriangleMesh &mesh, double min_thickness, - int oversampling, + double accuracy, double smoothing) { - return _hollowed_interior(mesh, min_thickness, oversampling, smoothing); + return _hollowed_interior(mesh, min_thickness, accuracy, smoothing); } } // namespace Slic3r diff --git a/src/libslic3r/OpenVDBUtils.hpp b/src/libslic3r/OpenVDBUtils.hpp index 8e55300bd2..95b95db7ce 100644 --- a/src/libslic3r/OpenVDBUtils.hpp +++ b/src/libslic3r/OpenVDBUtils.hpp @@ -18,16 +18,13 @@ TriangleMesh volumeToMesh(const openvdb::FloatGrid &grid, double adaptivity = 0.0, bool relaxDisorientedTriangles = true); -sla::Contour3D hollowed_interior(sla::Contour3D&& mesh, double min_thickness); -sla::Contour3D hollowed_interior(sla::Contour3D& mesh, double min_thickness); - // Generate an interior for any solid geometry maintaining a given minimum // wall thickness. The returned mesh has triangles with normals facing inside // the mesh so the result can be directly merged with the input to finish the // hollowing. // TODO: The thicknes is not strictly maintained due to the used gaussian filter TriangleMesh hollowed_interior(const TriangleMesh &mesh, double min_thickness, - int oversampling = 3, double smoothing = 0.5); + double accuracy = 0.5, double smoothing = 0.5); } // namespace Slic3r diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 4cfd81bc55..e621d4b340 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2846,6 +2846,25 @@ void PrintConfigDef::init_sla_params() def->min = 1; def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(4)); + + def = this->add("hollowing_accuracy", coFloat); + def->label = L("Hollowing accuracy"); + def->category = L("Hollowing"); + def->tooltip = L("Performance vs accuracy of calculation. Lower values may produce unwanted artifacts."); + def->min = 0; + def->max = 1; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.5)); + + def = this->add("hollowing_smoothness", coFloat); + def->label = L("Hollowing smoothness"); + def->category = L("Hollowing"); + def->tooltip = L("The cavity shape is a smoothed version of the outside original shape. " + "Possible values span from 0 to 1 and control the amount of surface smoothing."); + def->min = 0; + def->max = 1; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.5)); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6bcc3f9ad2..d07999c886 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1097,6 +1097,13 @@ public: // resulting walls may be thicker due to smoothing out fine cavities where // resin could stuck. ConfigOptionFloat hollowing_min_thickness; + + // Indirectly controls the voxel size (resolution) used by openvdb + ConfigOptionFloat hollowing_accuracy; + + // Indirectly controls the amount of filtering used to blur geometry + // features in the created cavity. + ConfigOptionFloat hollowing_smoothness; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -1136,6 +1143,8 @@ protected: OPT_PTR(pad_object_connector_penetration); OPT_PTR(hollowing_enable); OPT_PTR(hollowing_min_thickness); + OPT_PTR(hollowing_accuracy); + OPT_PTR(hollowing_smoothness); } }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 2e8a704005..d2200bcfb2 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -776,9 +776,10 @@ void SLAPrint::process() po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); double thickness = po.m_config.hollowing_min_thickness.getFloat(); - + double accuracy = po.m_config.hollowing_accuracy.getFloat(); + double blur = po.m_config.hollowing_smoothness.getFloat(); po.m_hollowing_data->interior = - hollowed_interior(po.transformed_mesh(), thickness, 4, 0.5); + hollowed_interior(po.transformed_mesh(), thickness, accuracy, blur); if (po.m_hollowing_data->interior.empty()) BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!"; @@ -1752,7 +1753,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vectormerge(*m_mesh); m_cavity_mesh.get()->require_shared_vertices(); @@ -692,7 +694,7 @@ RENDER_AGAIN: if (m_editing_mode) { if (m_imgui->button(m_desc.at("hollow"))) { - hollow_mesh(m_offset); + hollow_mesh(); } float diameter_upper_cap = static_cast(wxGetApp().preset_bundle->sla_prints.get_edited_preset().config.option("support_pillar_diameter"))->value; @@ -748,12 +750,22 @@ RENDER_AGAIN: remove_all = m_imgui->button(m_desc.at("remove_all")); m_imgui->disabled_end(); - m_imgui->text(" "); // vertical gap +// m_imgui->text(" "); // vertical gap m_imgui->text("Offset: "); ImGui::SameLine(); ImGui::SliderFloat(" ", &m_offset, 0.f, 10.f, "%.1f"); + + // TODO: only in expert mode: + m_imgui->text("Accuracy: "); + ImGui::SameLine(); + ImGui::SliderFloat(" ", &m_accuracy, 0.f, 1.f, "%.1f"); + + // TODO: only in expert mode: + m_imgui->text("Smoothness: "); + ImGui::SameLine(); + ImGui::SliderFloat(" ", &m_smoothness, 0.f, 1.f, "%.1f"); } else { // not in editing mode: m_imgui->text(m_desc.at("minimal_distance")); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index ba950594a2..0cf1e1ecb1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -92,7 +92,7 @@ private: void render_clipping_plane(const Selection& selection) const; bool is_mesh_update_necessary() const; void update_mesh(); - void hollow_mesh(float offset = 2.f); + void hollow_mesh(); bool unsaved_changes() const; const TriangleMesh* mesh() const; @@ -108,14 +108,19 @@ private: mutable std::vector m_editing_cache; // a support point and whether it is currently selected std::vector m_normal_cache; // to restore after discarding changes or undo/redo - float m_offset = 2.f; + float m_offset = 2.0f; float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; + + float m_accuracy = 0.5f; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; + + + float m_smoothness = 0.5f; GLSelectionRectangle m_selection_rectangle; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index edbb5fb750..483bff8e55 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -498,6 +498,8 @@ const std::vector& Preset::sla_print_options() "pad_object_connector_penetration", "hollowing_enable", "hollowing_min_thickness", + "hollowing_accuracy", + "hollowing_smoothness", "output_filename_format", "default_sla_print_profile", "compatible_printers", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 22c4bfb9bf..d20e0ee6c8 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3568,6 +3568,8 @@ void TabSLAPrint::build() optgroup = page->new_optgroup(_(L("Hollowing"))); optgroup->append_single_option_line("hollowing_enable"); optgroup->append_single_option_line("hollowing_min_thickness"); + optgroup->append_single_option_line("hollowing_accuracy"); + optgroup->append_single_option_line("hollowing_smoothness"); page = add_options_page(_(L("Advanced")), "wrench"); optgroup = page->new_optgroup(_(L("Slicing"))); From 4b088658096ad38937795a9153ffd8406ce827a3 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 8 Nov 2019 09:21:30 +0100 Subject: [PATCH 5/6] hollowing params renamed, filtering generalized --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/OpenVDBUtils.cpp | 31 ++++---------- src/libslic3r/OpenVDBUtils.hpp | 6 ++- src/libslic3r/PrintConfig.cpp | 4 +- src/libslic3r/PrintConfig.hpp | 8 ++-- src/libslic3r/SLA/Hollowing.cpp | 55 +++++++++++++++++++++++++ src/libslic3r/SLA/Hollowing.hpp | 17 ++++++++ src/libslic3r/SLAPrint.cpp | 12 +++--- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 11 ++--- src/slic3r/GUI/Preset.cpp | 4 +- src/slic3r/GUI/Tab.cpp | 4 +- tests/libslic3r/test_hollowing.cpp | 29 +------------ 12 files changed, 111 insertions(+), 72 deletions(-) create mode 100644 src/libslic3r/SLA/Hollowing.cpp create mode 100644 src/libslic3r/SLA/Hollowing.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index e4b6ccd100..e28917b5f3 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -204,6 +204,8 @@ add_library(libslic3r STATIC SLA/SLARasterWriter.cpp SLA/ConcaveHull.hpp SLA/ConcaveHull.cpp + SLA/Hollowing.hpp + SLA/Hollowing.cpp ) encoding_check(libslic3r) diff --git a/src/libslic3r/OpenVDBUtils.cpp b/src/libslic3r/OpenVDBUtils.cpp index 53f9d5ae9f..91ccdd5c4e 100644 --- a/src/libslic3r/OpenVDBUtils.cpp +++ b/src/libslic3r/OpenVDBUtils.cpp @@ -2,7 +2,7 @@ #include "OpenVDBUtils.hpp" #include #include -#include +#include #include #include "MTUtils.hpp" @@ -158,35 +158,22 @@ inline void _scale(S s, sla::Contour3D &m) for (auto &p : m.points) p *= s; } -static void filter_grid(openvdb::FloatGrid &grid, double scale, double gain) -{ - static const double ROUNDNESS_COEFF = 1.; - - // Filtering: - if (gain > 0.) { - double rounding = ROUNDNESS_COEFF * gain; - int width = int(rounding * scale); - int count = 1; - openvdb::tools::Filter{grid}.gaussian(width, count); - } -} - template remove_cvref_t _hollowed_interior(Mesh &&mesh, double min_thickness, - double accuracy, - double smoothing) + double quality, + HollowingFilter filt) { using MMesh = remove_cvref_t; MMesh imesh{std::forward(mesh)}; - static const double ACCURACY_COEFF = 7.; + static const double QUALITY_COEFF = 7.; // I can't figure out how to increase the grid resolution through openvdb API // so the model will be scaled up before conversion and the result scaled // down. Voxels have a unit size. If I set voxelSize smaller, it scales // the whole geometry down, and doesn't increase the number of voxels. - auto scale = (1.0 + ACCURACY_COEFF * accuracy); // max 8x upscale, min is native voxel size + auto scale = (1.0 + QUALITY_COEFF * quality); // max 8x upscale, min is native voxel size _scale(scale, imesh); @@ -201,7 +188,7 @@ remove_cvref_t _hollowed_interior(Mesh &&mesh, return MMesh{}; } - filter_grid(*gridptr, scale, smoothing); + if (filt) filt(*gridptr, min_thickness, scale); double iso_surface = -offset; double adaptivity = 0.; @@ -214,10 +201,10 @@ remove_cvref_t _hollowed_interior(Mesh &&mesh, TriangleMesh hollowed_interior(const TriangleMesh &mesh, double min_thickness, - double accuracy, - double smoothing) + double quality, + HollowingFilter filt) { - return _hollowed_interior(mesh, min_thickness, accuracy, smoothing); + return _hollowed_interior(mesh, min_thickness, quality, filt); } } // namespace Slic3r diff --git a/src/libslic3r/OpenVDBUtils.hpp b/src/libslic3r/OpenVDBUtils.hpp index 95b95db7ce..bd52e81eec 100644 --- a/src/libslic3r/OpenVDBUtils.hpp +++ b/src/libslic3r/OpenVDBUtils.hpp @@ -18,13 +18,15 @@ TriangleMesh volumeToMesh(const openvdb::FloatGrid &grid, double adaptivity = 0.0, bool relaxDisorientedTriangles = true); +using HollowingFilter = std::function; + // Generate an interior for any solid geometry maintaining a given minimum // wall thickness. The returned mesh has triangles with normals facing inside // the mesh so the result can be directly merged with the input to finish the // hollowing. -// TODO: The thicknes is not strictly maintained due to the used gaussian filter TriangleMesh hollowed_interior(const TriangleMesh &mesh, double min_thickness, - double accuracy = 0.5, double smoothing = 0.5); + double quality = 0.5, + HollowingFilter filt = nullptr); } // namespace Slic3r diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e621d4b340..96b84cf817 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2847,7 +2847,7 @@ void PrintConfigDef::init_sla_params() def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(4)); - def = this->add("hollowing_accuracy", coFloat); + def = this->add("hollowing_quality", coFloat); def->label = L("Hollowing accuracy"); def->category = L("Hollowing"); def->tooltip = L("Performance vs accuracy of calculation. Lower values may produce unwanted artifacts."); @@ -2856,7 +2856,7 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.5)); - def = this->add("hollowing_smoothness", coFloat); + def = this->add("hollowing_flatness", coFloat); def->label = L("Hollowing smoothness"); def->category = L("Hollowing"); def->tooltip = L("The cavity shape is a smoothed version of the outside original shape. " diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d07999c886..9ed63e5d4c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1099,11 +1099,11 @@ public: ConfigOptionFloat hollowing_min_thickness; // Indirectly controls the voxel size (resolution) used by openvdb - ConfigOptionFloat hollowing_accuracy; + ConfigOptionFloat hollowing_quality; // Indirectly controls the amount of filtering used to blur geometry // features in the created cavity. - ConfigOptionFloat hollowing_smoothness; + ConfigOptionFloat hollowing_flatness; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -1143,8 +1143,8 @@ protected: OPT_PTR(pad_object_connector_penetration); OPT_PTR(hollowing_enable); OPT_PTR(hollowing_min_thickness); - OPT_PTR(hollowing_accuracy); - OPT_PTR(hollowing_smoothness); + OPT_PTR(hollowing_quality); + OPT_PTR(hollowing_flatness); } }; diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp new file mode 100644 index 0000000000..4309003134 --- /dev/null +++ b/src/libslic3r/SLA/Hollowing.cpp @@ -0,0 +1,55 @@ +#include "Hollowing.hpp" +#include +#include +#include +#include + +namespace Slic3r { +namespace sla { + +namespace { + +void filter_grid_sla(openvdb::FloatGrid &grid, double scale, double /*thickness*/, double flatness) +{ + static const double ROUNDNESS_COEFF = 1.; + + // Filtering: + if (flatness > 0.) { + double rounding = ROUNDNESS_COEFF * flatness; + int width = int(rounding * scale); + int count = 1; + openvdb::tools::Filter{grid}.gaussian(width, count); + } +} +// openvdb::tools::levelSetRebuild(grid, -float(thickness * 2)); +// filter_grid_sla(grid, scale, thickness, flatness); + +// openvdb::tools::levelSetRebuild(grid, float(thickness)); + + +void redist_grid_sla(openvdb::FloatGrid &grid, double scale, double thickness, double flatness) +{ +// openvdb::tools::levelSetRebuild(grid, -float(scale * thickness)); + + + openvdb::tools::LevelSetFilter filt{grid}; + +// filt.gaussian(int(flatness * scale)); + +// openvdb::tools::levelSetRebuild(grid, float(scale * thickness)); + //grid = openvdb::tools::topologyToLevelSet(grid); +} + +} + +TriangleMesh generate_interior(const TriangleMesh &mesh, + double min_thickness, + double quality, + double flatness) +{ + namespace plc = std::placeholders; + auto filt = std::bind(filter_grid_sla, plc::_1, plc::_2, plc::_3, flatness); + return hollowed_interior(mesh, min_thickness, quality, filt); +} + +}} // namespace Slic3r::sla diff --git a/src/libslic3r/SLA/Hollowing.hpp b/src/libslic3r/SLA/Hollowing.hpp new file mode 100644 index 0000000000..6abbe9f994 --- /dev/null +++ b/src/libslic3r/SLA/Hollowing.hpp @@ -0,0 +1,17 @@ +#ifndef HOLLOWINGFILTER_HPP +#define HOLLOWINGFILTER_HPP + +#include + +namespace Slic3r { +namespace sla { + +TriangleMesh generate_interior(const TriangleMesh &mesh, + double min_thickness, + double quality = 0.5, + double flatness = 0.5); + +} +} + +#endif // HOLLOWINGFILTER_H diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index d2200bcfb2..b150a4f768 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -3,7 +3,7 @@ #include "SLA/SLAPad.hpp" #include "SLA/SLAAutoSupports.hpp" #include "ClipperUtils.hpp" -#include "OpenVDBUtils.hpp" +#include "SLA/Hollowing.hpp" #include "Geometry.hpp" #include "MTUtils.hpp" @@ -776,10 +776,10 @@ void SLAPrint::process() po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); double thickness = po.m_config.hollowing_min_thickness.getFloat(); - double accuracy = po.m_config.hollowing_accuracy.getFloat(); - double blur = po.m_config.hollowing_smoothness.getFloat(); + double accuracy = po.m_config.hollowing_quality.getFloat(); + double blur = po.m_config.hollowing_flatness.getFloat(); po.m_hollowing_data->interior = - hollowed_interior(po.transformed_mesh(), thickness, accuracy, blur); + generate_interior(po.transformed_mesh(), thickness, accuracy, blur); if (po.m_hollowing_data->interior.empty()) BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!"; @@ -1754,8 +1754,8 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector& Preset::sla_print_options() "pad_object_connector_penetration", "hollowing_enable", "hollowing_min_thickness", - "hollowing_accuracy", - "hollowing_smoothness", + "hollowing_quality", + "hollowing_flatness", "output_filename_format", "default_sla_print_profile", "compatible_printers", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d20e0ee6c8..333384802a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3568,8 +3568,8 @@ void TabSLAPrint::build() optgroup = page->new_optgroup(_(L("Hollowing"))); optgroup->append_single_option_line("hollowing_enable"); optgroup->append_single_option_line("hollowing_min_thickness"); - optgroup->append_single_option_line("hollowing_accuracy"); - optgroup->append_single_option_line("hollowing_smoothness"); + optgroup->append_single_option_line("hollowing_quality"); + optgroup->append_single_option_line("hollowing_flatness"); page = add_options_page(_(L("Advanced")), "wrench"); optgroup = page->new_optgroup(_(L("Slicing"))); diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index 9a2ea2e726..4264774a3e 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -2,7 +2,7 @@ #include #include -#include "libslic3r/OpenVDBUtils.hpp" +#include "libslic3r/SLA/Hollowing.hpp" #include #include "libslic3r/Format/OBJ.hpp" @@ -22,38 +22,13 @@ static Slic3r::TriangleMesh load_model(const std::string &obj_filename) return mesh; } -//static Slic3r::TriangleMesh hollowed_interior(const Slic3r::TriangleMesh &mesh, -// double min_thickness) -//{ -// Slic3r::sla::Contour3D imesh = Slic3r::sla::Contour3D{mesh}; - -// double scale = std::max(1.0, 3. / min_thickness); -// double offset = scale * min_thickness; -// float range = float(std::max(2 * offset, scale)); - -// for (auto &p : imesh.points) p *= scale; -// auto ptr = Slic3r::meshToVolume(imesh, {}, 0.1f * float(offset), range); - -// REQUIRE(ptr); - -// openvdb::tools::Filter{*ptr}.gaussian(int(scale), 1); - -// double iso_surface = -offset; -// double adaptivity = 0.; -// Slic3r::sla::Contour3D omesh = Slic3r::volumeToMesh(*ptr, iso_surface, adaptivity); - -// for (auto &p : omesh.points) p /= scale; - -// return to_triangle_mesh(omesh); -//} - TEST_CASE("Negative 3D offset should produce smaller object.", "[Hollowing]") { Slic3r::TriangleMesh in_mesh = load_model("20mm_cube.obj"); Benchmark bench; bench.start(); - Slic3r::TriangleMesh out_mesh = hollowed_interior(in_mesh, 0.5); + Slic3r::TriangleMesh out_mesh = Slic3r::sla::generate_interior(in_mesh, 0.5); bench.stop(); From ac8eab5fa8e6c38faf788349bcb4f0f707d6bbbe Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 8 Nov 2019 16:51:43 +0100 Subject: [PATCH 6/6] Enhanced hollowing scheme, closing distance working as expected. --- src/libslic3r/OpenVDBUtils.cpp | 109 +++---------------- src/libslic3r/OpenVDBUtils.hpp | 33 ++++-- src/libslic3r/PrintConfig.cpp | 10 +- src/libslic3r/PrintConfig.hpp | 9 +- src/libslic3r/SLA/Hollowing.cpp | 135 ++++++++++++++++++------ src/libslic3r/SLAPrint.cpp | 8 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 8 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 9 +- src/slic3r/GUI/Preset.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 2 +- 10 files changed, 160 insertions(+), 165 deletions(-) diff --git a/src/libslic3r/OpenVDBUtils.cpp b/src/libslic3r/OpenVDBUtils.cpp index 91ccdd5c4e..c76bad96c5 100644 --- a/src/libslic3r/OpenVDBUtils.cpp +++ b/src/libslic3r/OpenVDBUtils.cpp @@ -2,9 +2,9 @@ #include "OpenVDBUtils.hpp" #include #include -#include -#include -#include "MTUtils.hpp" +#include + +//#include "MTUtils.hpp" namespace Slic3r { @@ -58,7 +58,7 @@ void Contour3DDataAdapter::getIndexSpacePoint(size_t n, // docs say it should be called ones. It does a mutex lock-unlock sequence all // even if was called previously. -openvdb::FloatGrid::Ptr meshToVolume(const TriangleMesh &mesh, +openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh &mesh, const openvdb::math::Transform &tr, float exteriorBandWidth, float interiorBandWidth, @@ -70,7 +70,7 @@ openvdb::FloatGrid::Ptr meshToVolume(const TriangleMesh &mesh, interiorBandWidth, flags); } -static openvdb::FloatGrid::Ptr meshToVolume(const sla::Contour3D &mesh, +openvdb::FloatGrid::Ptr mesh_to_grid(const sla::Contour3D &mesh, const openvdb::math::Transform &tr, float exteriorBandWidth, float interiorBandWidth, @@ -82,13 +82,8 @@ static openvdb::FloatGrid::Ptr meshToVolume(const sla::Contour3D &mesh, flags); } -inline Vec3f to_vec3f(const openvdb::Vec3s &v) { return Vec3f{v.x(), v.y(), v.z()}; } -inline Vec3d to_vec3d(const openvdb::Vec3s &v) { return to_vec3f(v).cast(); } -inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[0]), int(v[1]), int(v[2])}; } -inline Vec4i to_vec4i(const openvdb::Vec4I &v) { return Vec4i{int(v[0]), int(v[1]), int(v[2]), int(v[3])}; } - template -sla::Contour3D __volumeToMesh(const Grid &grid, +sla::Contour3D _volumeToMesh(const Grid &grid, double isovalue, double adaptivity, bool relaxDisorientedTriangles) @@ -114,97 +109,27 @@ sla::Contour3D __volumeToMesh(const Grid &grid, return ret; } -template inline -Mesh _volumeToMesh(const openvdb::FloatGrid &grid, - double isovalue = 0.0, - double adaptivity = 0.0, - bool relaxDisorientedTriangles = true); - -template<> inline -TriangleMesh _volumeToMesh(const openvdb::FloatGrid &grid, +TriangleMesh grid_to_mesh(const openvdb::FloatGrid &grid, double isovalue, double adaptivity, bool relaxDisorientedTriangles) { - return to_triangle_mesh(__volumeToMesh(grid, isovalue, adaptivity, - relaxDisorientedTriangles)); + return to_triangle_mesh( + _volumeToMesh(grid, isovalue, adaptivity, relaxDisorientedTriangles)); } -template<> inline -sla::Contour3D _volumeToMesh(const openvdb::FloatGrid &grid, - double isovalue, - double adaptivity, - bool relaxDisorientedTriangles) +sla::Contour3D grid_to_contour3d(const openvdb::FloatGrid &grid, + double isovalue, + double adaptivity, + bool relaxDisorientedTriangles) { - return __volumeToMesh(grid, isovalue, adaptivity, - relaxDisorientedTriangles); + return _volumeToMesh(grid, isovalue, adaptivity, + relaxDisorientedTriangles); } -TriangleMesh volumeToMesh(const openvdb::FloatGrid &grid, - double isovalue, - double adaptivity, - bool relaxDisorientedTriangles) +openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid, double iso, double er, double ir) { - return _volumeToMesh(grid, isovalue, adaptivity, - relaxDisorientedTriangles); -} - -template> -inline void _scale(S s, TriangleMesh &m) { m.scale(float(s)); } - -template> -inline void _scale(S s, sla::Contour3D &m) -{ - for (auto &p : m.points) p *= s; -} - -template -remove_cvref_t _hollowed_interior(Mesh &&mesh, - double min_thickness, - double quality, - HollowingFilter filt) -{ - using MMesh = remove_cvref_t; - MMesh imesh{std::forward(mesh)}; - - static const double QUALITY_COEFF = 7.; - - // I can't figure out how to increase the grid resolution through openvdb API - // so the model will be scaled up before conversion and the result scaled - // down. Voxels have a unit size. If I set voxelSize smaller, it scales - // the whole geometry down, and doesn't increase the number of voxels. - auto scale = (1.0 + QUALITY_COEFF * quality); // max 8x upscale, min is native voxel size - - _scale(scale, imesh); - - double offset = scale * min_thickness; - float range = float(std::max(2 * offset, scale)); - auto gridptr = meshToVolume(imesh, {}, 0.1f * float(offset), range); - - assert(gridptr); - - if (!gridptr) { - BOOST_LOG_TRIVIAL(error) << "Returned OpenVDB grid is NULL"; - return MMesh{}; - } - - if (filt) filt(*gridptr, min_thickness, scale); - - double iso_surface = -offset; - double adaptivity = 0.; - auto omesh = _volumeToMesh(*gridptr, iso_surface, adaptivity); - - _scale(1. / scale, omesh); - - return omesh; -} - -TriangleMesh hollowed_interior(const TriangleMesh &mesh, - double min_thickness, - double quality, - HollowingFilter filt) -{ - return _hollowed_interior(mesh, min_thickness, quality, filt); + return openvdb::tools::levelSetRebuild(grid, float(iso), float(er), float(ir)); } } // namespace Slic3r diff --git a/src/libslic3r/OpenVDBUtils.hpp b/src/libslic3r/OpenVDBUtils.hpp index bd52e81eec..151647bfc4 100644 --- a/src/libslic3r/OpenVDBUtils.hpp +++ b/src/libslic3r/OpenVDBUtils.hpp @@ -7,26 +7,37 @@ namespace Slic3r { -openvdb::FloatGrid::Ptr meshToVolume(const TriangleMesh & mesh, +inline Vec3f to_vec3f(const openvdb::Vec3s &v) { return Vec3f{v.x(), v.y(), v.z()}; } +inline Vec3d to_vec3d(const openvdb::Vec3s &v) { return to_vec3f(v).cast(); } +inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[0]), int(v[1]), int(v[2])}; } +inline Vec4i to_vec4i(const openvdb::Vec4I &v) { return Vec4i{int(v[0]), int(v[1]), int(v[2]), int(v[3])}; } + +openvdb::FloatGrid::Ptr mesh_to_grid(const TriangleMesh & mesh, const openvdb::math::Transform &tr = {}, float exteriorBandWidth = 3.0f, float interiorBandWidth = 3.0f, int flags = 0); -TriangleMesh volumeToMesh(const openvdb::FloatGrid &grid, +openvdb::FloatGrid::Ptr mesh_to_grid(const sla::Contour3D & mesh, + const openvdb::math::Transform &tr = {}, + float exteriorBandWidth = 3.0f, + float interiorBandWidth = 3.0f, + int flags = 0); + +sla::Contour3D grid_to_contour3d(const openvdb::FloatGrid &grid, + double isovalue, + double adaptivity, + bool relaxDisorientedTriangles = true); + +TriangleMesh grid_to_mesh(const openvdb::FloatGrid &grid, double isovalue = 0.0, double adaptivity = 0.0, bool relaxDisorientedTriangles = true); -using HollowingFilter = std::function; - -// Generate an interior for any solid geometry maintaining a given minimum -// wall thickness. The returned mesh has triangles with normals facing inside -// the mesh so the result can be directly merged with the input to finish the -// hollowing. -TriangleMesh hollowed_interior(const TriangleMesh &mesh, double min_thickness, - double quality = 0.5, - HollowingFilter filt = nullptr); +openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid, + double iso, + double ext_range = 3., + double int_range = 3.); } // namespace Slic3r diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 96b84cf817..58212f1289 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2856,15 +2856,13 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.5)); - def = this->add("hollowing_flatness", coFloat); - def->label = L("Hollowing smoothness"); + def = this->add("hollowing_closing_distance", coFloat); + def->label = L("Hollowing closing distance"); def->category = L("Hollowing"); - def->tooltip = L("The cavity shape is a smoothed version of the outside original shape. " - "Possible values span from 0 to 1 and control the amount of surface smoothing."); + def->tooltip = L(""); def->min = 0; - def->max = 1; def->mode = comExpert; - def->set_default_value(new ConfigOptionFloat(0.5)); + def->set_default_value(new ConfigOptionFloat(2.0)); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 9ed63e5d4c..671a6ce8e1 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1100,10 +1100,9 @@ public: // Indirectly controls the voxel size (resolution) used by openvdb ConfigOptionFloat hollowing_quality; - - // Indirectly controls the amount of filtering used to blur geometry - // features in the created cavity. - ConfigOptionFloat hollowing_flatness; + + // Indirectly controls the minimum size of created cavities. + ConfigOptionFloat hollowing_closing_distance; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) @@ -1144,7 +1143,7 @@ protected: OPT_PTR(hollowing_enable); OPT_PTR(hollowing_min_thickness); OPT_PTR(hollowing_quality); - OPT_PTR(hollowing_flatness); + OPT_PTR(hollowing_closing_distance); } }; diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp index 4309003134..c3993f2c89 100644 --- a/src/libslic3r/SLA/Hollowing.cpp +++ b/src/libslic3r/SLA/Hollowing.cpp @@ -1,55 +1,122 @@ -#include "Hollowing.hpp" -#include -#include -#include #include +//#include +#include + +#include "Hollowing.hpp" +#include + namespace Slic3r { namespace sla { -namespace { +//namespace { -void filter_grid_sla(openvdb::FloatGrid &grid, double scale, double /*thickness*/, double flatness) -{ - static const double ROUNDNESS_COEFF = 1.; +//void filter_grid_sla(openvdb::FloatGrid::Ptr &grid, double scale, double /*thickness*/, double flatness, double closing_dist) +//{ +// static const double ROUNDNESS_COEFF = 1.; - // Filtering: - if (flatness > 0.) { - double rounding = ROUNDNESS_COEFF * flatness; - int width = int(rounding * scale); - int count = 1; - openvdb::tools::Filter{grid}.gaussian(width, count); +// // Filtering: +// if (flatness > 0.) { +// double rounding = ROUNDNESS_COEFF * flatness; +// int width = int(rounding * scale); +// int count = 1; +// openvdb::tools::Filter{*grid}.gaussian(width, count); +// } +//} + +//} + +template> +inline void _scale(S s, TriangleMesh &m) { m.scale(float(s)); } + +template> +inline void _scale(S s, sla::Contour3D &m) +{ + for (auto &p : m.points) p *= s; +} + +template +remove_cvref_t _grid_to_mesh(const openvdb::FloatGrid &grid, + double isosurf, + double adapt); + +template<> +TriangleMesh _grid_to_mesh(const openvdb::FloatGrid &grid, + double isosurf, + double adapt) +{ + return grid_to_mesh(grid, isosurf, adapt); +} + +template<> +sla::Contour3D _grid_to_mesh(const openvdb::FloatGrid &grid, + double isosurf, + double adapt) +{ + return grid_to_contour3d(grid, isosurf, adapt); +} + +template +remove_cvref_t _generate_interior(Mesh &&mesh, + double min_thickness, + double voxel_scale, + double closing_dist) +{ +// namespace plc = std::placeholders; +// auto filt = std::bind(redist_grid_sla, plc::_1, plc::_2, plc::_3, flatness, closing_dist); +// return hollowed_interior(mesh, min_thickness, quality, filt); + + using MMesh = remove_cvref_t; + MMesh imesh{std::forward(mesh)}; + + _scale(voxel_scale, imesh); + + double offset = voxel_scale * min_thickness; + double D = voxel_scale * closing_dist; + float out_range = 0.1f * float(offset); + float in_range = 1.1f * float(offset + D); + auto gridptr = mesh_to_grid(imesh, {}, out_range, in_range); + + assert(gridptr); + + if (!gridptr) { + BOOST_LOG_TRIVIAL(error) << "Returned OpenVDB grid is NULL"; + return MMesh{}; } -} -// openvdb::tools::levelSetRebuild(grid, -float(thickness * 2)); -// filter_grid_sla(grid, scale, thickness, flatness); - -// openvdb::tools::levelSetRebuild(grid, float(thickness)); - - -void redist_grid_sla(openvdb::FloatGrid &grid, double scale, double thickness, double flatness) -{ -// openvdb::tools::levelSetRebuild(grid, -float(scale * thickness)); + if (closing_dist > .0) { + gridptr = redistance_grid(*gridptr, -(offset + D), double(in_range)); + } else { + D = -offset; + } - openvdb::tools::LevelSetFilter filt{grid}; +// openvdb::tools::Filter filt{*gridptr}; +// filt.offset(float(offset + D)); -// filt.gaussian(int(flatness * scale)); + double iso_surface = D; + double adaptivity = 0.; + auto omesh = _grid_to_mesh(*gridptr, iso_surface, adaptivity); -// openvdb::tools::levelSetRebuild(grid, float(scale * thickness)); - //grid = openvdb::tools::topologyToLevelSet(grid); -} - + _scale(1. / voxel_scale, omesh); + + return omesh; } TriangleMesh generate_interior(const TriangleMesh &mesh, double min_thickness, double quality, - double flatness) + double closing_dist) { - namespace plc = std::placeholders; - auto filt = std::bind(filter_grid_sla, plc::_1, plc::_2, plc::_3, flatness); - return hollowed_interior(mesh, min_thickness, quality, filt); + static const double MAX_OVERSAMPL = 7.; + + // I can't figure out how to increase the grid resolution through openvdb API + // so the model will be scaled up before conversion and the result scaled + // down. Voxels have a unit size. If I set voxelSize smaller, it scales + // the whole geometry down, and doesn't increase the number of voxels. + // + // max 8x upscale, min is native voxel size + auto voxel_scale = (1.0 + MAX_OVERSAMPL * quality); + return _generate_interior(mesh, min_thickness, voxel_scale, closing_dist); } }} // namespace Slic3r::sla diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index b150a4f768..3273cbcfed 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -776,10 +776,10 @@ void SLAPrint::process() po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); double thickness = po.m_config.hollowing_min_thickness.getFloat(); - double accuracy = po.m_config.hollowing_quality.getFloat(); - double blur = po.m_config.hollowing_flatness.getFloat(); + double quality = po.m_config.hollowing_quality.getFloat(); + double closing_d = po.m_config.hollowing_closing_distance.getFloat(); po.m_hollowing_data->interior = - generate_interior(po.transformed_mesh(), thickness, accuracy, blur); + generate_interior(po.transformed_mesh(), thickness, quality, closing_d); if (po.m_hollowing_data->interior.empty()) BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!"; @@ -1755,7 +1755,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vectortext(" "); // vertical gap - m_imgui->text("Offset: "); ImGui::SameLine(); ImGui::SliderFloat(" ", &m_offset, 0.f, 10.f, "%.1f"); @@ -763,10 +762,9 @@ RENDER_AGAIN: ImGui::SameLine(); ImGui::SliderFloat(" ", &m_accuracy, 0.f, 1.f, "%.1f"); - // TODO: only in expert mode: - m_imgui->text("Smoothness: "); + m_imgui->text("Closing distance: "); ImGui::SameLine(); - ImGui::SliderFloat(" ", &m_smoothness, 0.f, 1.f, "%.1f"); + ImGui::SliderFloat(" ", &m_closing_d, 0.f, 20.f, "%.1f"); } else { // not in editing mode: m_imgui->text(m_desc.at("minimal_distance")); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 0cf1e1ecb1..642f7f5a28 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -109,18 +109,15 @@ private: std::vector m_normal_cache; // to restore after discarding changes or undo/redo float m_offset = 2.0f; - + float m_accuracy = 0.5f; + float m_closing_d = 2.f; + float m_clipping_plane_distance = 0.f; std::unique_ptr m_clipping_plane; - float m_accuracy = 0.5f; - // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; - - - float m_smoothness = 0.5f; GLSelectionRectangle m_selection_rectangle; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 6f511fdec4..3b5a2f9852 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -499,7 +499,7 @@ const std::vector& Preset::sla_print_options() "hollowing_enable", "hollowing_min_thickness", "hollowing_quality", - "hollowing_flatness", + "hollowing_closing_distance", "output_filename_format", "default_sla_print_profile", "compatible_printers", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 333384802a..6f17abea44 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3569,7 +3569,7 @@ void TabSLAPrint::build() optgroup->append_single_option_line("hollowing_enable"); optgroup->append_single_option_line("hollowing_min_thickness"); optgroup->append_single_option_line("hollowing_quality"); - optgroup->append_single_option_line("hollowing_flatness"); + optgroup->append_single_option_line("hollowing_closing_distance"); page = add_options_page(_(L("Advanced")), "wrench"); optgroup = page->new_optgroup(_(L("Slicing")));