Add support for structured noise (perlin) fuzzy skin (#7678)

* Add support for perlin noise fuzzy skin

* Support multiple types of coherent noise

* Updated tooltips for more clarity.

* Reorder options as suggested by @discip

* Fix accidental removal of &

* Move libnoise to deps

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
Nick Johnson 2025-01-27 14:45:16 +00:00 committed by GitHub
parent 118e14d788
commit fd0b2547f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 200 additions and 24 deletions

View file

@ -0,0 +1,15 @@
find_path(LIBNOISE_INCLUDE_DIR libnoise/noise.h)
find_library(LIBNOISE_LIBRARY NAMES libnoise libnoise_static)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libnoise DEFAULT_MSG
LIBNOISE_LIBRARY
LIBNOISE_INCLUDE_DIR
)
if(libnoise_FOUND)
add_library(noise::noise STATIC IMPORTED)
set_target_properties(noise::noise PROPERTIES
IMPORTED_LOCATION "${LIBNOISE_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBNOISE_INCLUDE_DIR}"
)
endif()

1
deps/CMakeLists.txt vendored
View file

@ -293,6 +293,7 @@ include(MPFR/MPFR.cmake)
include(CGAL/CGAL.cmake) include(CGAL/CGAL.cmake)
include(NLopt/NLopt.cmake) include(NLopt/NLopt.cmake)
include(libnoise/libnoise.cmake)
# I *think* 1.1 is used for *just* md5 hashing? # I *think* 1.1 is used for *just* md5 hashing?

4
deps/libnoise/libnoise.cmake vendored Normal file
View file

@ -0,0 +1,4 @@
orcaslicer_add_cmake_project(libnoise
URL https://github.com/SoftFever/Orca-deps-libnoise/archive/refs/tags/1.0.zip
URL_HASH SHA256=96ffd6cc47898dd8147aab53d7d1b1911b507d9dbaecd5613ca2649468afd8b6
)

View file

@ -550,7 +550,7 @@ set(OCCT_LIBS
TKernel TKernel
) )
find_package(libnoise REQUIRED)
target_link_libraries(libslic3r target_link_libraries(libslic3r
libnest2d libnest2d
admesh admesh
@ -576,6 +576,7 @@ target_link_libraries(libslic3r
JPEG::JPEG JPEG::JPEG
qoi qoi
opencv_world opencv_world
noise::noise
) )
if(NOT WIN32) if(NOT WIN32)

View file

@ -87,6 +87,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, const LayerRe
&slices, &slices,
&compatible_regions, &compatible_regions,
this->layer()->height, this->layer()->height,
this->layer()->slice_z,
this->flow(frPerimeter), this->flow(frPerimeter),
&region_config, &region_config,
&this->layer()->object()->config(), &this->layer()->object()->config(),

View file

@ -22,6 +22,7 @@
#include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/AABBTreeLines.hpp"
#include "Print.hpp" #include "Print.hpp"
#include "Algorithm/LineSplit.hpp" #include "Algorithm/LineSplit.hpp"
#include "libnoise/noise.h"
static const int overhang_sampling_number = 6; static const int overhang_sampling_number = 6;
static const double narrow_loop_length_threshold = 10; static const double narrow_loop_length_threshold = 10;
static const double min_degree_gap = 0.1; static const double min_degree_gap = 0.1;
@ -44,6 +45,14 @@ static double random_value() {
return dist(gen); return dist(gen);
} }
class UniformNoise: public noise::module::Module {
public:
UniformNoise(): Module (GetSourceModuleCount ()) {};
virtual int GetSourceModuleCount() const { return 0; }
virtual double GetValue(double x, double y, double z) const { return random_value() * 2 - 1; }
};
// Hierarchy of perimeters. // Hierarchy of perimeters.
class PerimeterGeneratorLoop { class PerimeterGeneratorLoop {
public: public:
@ -66,9 +75,39 @@ public:
bool is_internal_contour() const; bool is_internal_contour() const;
}; };
static std::unique_ptr<noise::module::Module> get_noise_module(const FuzzySkinConfig& cfg) {
if (cfg.noise_type == NoiseType::Perlin) {
auto perlin_noise = noise::module::Perlin();
perlin_noise.SetFrequency(1 / cfg.noise_scale);
perlin_noise.SetOctaveCount(cfg.noise_octaves);
perlin_noise.SetPersistence(cfg.noise_persistence);
return std::make_unique<noise::module::Perlin>(perlin_noise);
} else if (cfg.noise_type == NoiseType::Billow) {
auto billow_noise = noise::module::Billow();
billow_noise.SetFrequency(1 / cfg.noise_scale);
billow_noise.SetOctaveCount(cfg.noise_octaves);
billow_noise.SetPersistence(cfg.noise_persistence);
return std::make_unique<noise::module::Billow>(billow_noise);
} else if (cfg.noise_type == NoiseType::RidgedMulti) {
auto ridged_multi_noise = noise::module::RidgedMulti();
ridged_multi_noise.SetFrequency(1 / cfg.noise_scale);
ridged_multi_noise.SetOctaveCount(cfg.noise_octaves);
return std::make_unique<noise::module::RidgedMulti>(ridged_multi_noise);
} else if (cfg.noise_type == NoiseType::Voronoi) {
auto voronoi_noise = noise::module::Voronoi();
voronoi_noise.SetFrequency(1 / cfg.noise_scale);
voronoi_noise.SetDisplacement(1.0);
return std::make_unique<noise::module::Voronoi>(voronoi_noise);
} else {
return std::make_unique<UniformNoise>();
}
}
// Thanks Cura developers for this function. // Thanks Cura developers for this function.
static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg) static void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg)
{ {
std::unique_ptr<noise::module::Module> noise = get_noise_module(cfg);
const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
const double range_random_point_dist = cfg.point_distance / 2.; const double range_random_point_dist = cfg.point_distance / 2.;
double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
@ -90,8 +129,9 @@ static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg
for (; p0pa_dist < p0p1_size; for (; p0pa_dist < p0p1_size;
p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist)
{ {
double r = random_value() * (cfg.thickness * 2.) - cfg.thickness; Point pa = *p0 + (p0p1 * (p0pa_dist / p0p1_size)).cast<coord_t>();
out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast<double>().normalized() * r).cast<coord_t>()); double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness;
out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * r).cast<coord_t>());
} }
dist_left_over = p0pa_dist - p0p1_size; dist_left_over = p0pa_dist - p0p1_size;
p0 = &p1; p0 = &p1;
@ -108,8 +148,10 @@ static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg
} }
// Thanks Cura developers for this function. // Thanks Cura developers for this function.
static void fuzzy_extrusion_line(std::vector<Arachne::ExtrusionJunction>& ext_lines, const FuzzySkinConfig& cfg) static void fuzzy_extrusion_line(std::vector<Arachne::ExtrusionJunction>& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg)
{ {
std::unique_ptr<noise::module::Module> noise = get_noise_module(cfg);
const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
const double range_random_point_dist = cfg.point_distance / 2.; const double range_random_point_dist = cfg.point_distance / 2.;
double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
@ -128,8 +170,9 @@ static void fuzzy_extrusion_line(std::vector<Arachne::ExtrusionJunction>& ext_li
double p0p1_size = p0p1.norm(); double p0p1_size = p0p1.norm();
double p0pa_dist = dist_left_over; double p0pa_dist = dist_left_over;
for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) { for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) {
double r = random_value() * (cfg.thickness * 2.) - cfg.thickness; Point pa = p0->p + (p0p1 * (p0pa_dist / p0p1_size)).cast<coord_t>();
out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast<double>().normalized() * r).cast<coord_t>(), p1.w, p1.perimeter_index); double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness;
out.emplace_back(pa + (perp(p0p1).cast<double>().normalized() * r).cast<coord_t>(), p1.w, p1.perimeter_index);
} }
dist_left_over = p0pa_dist - p0p1_size; dist_left_over = p0pa_dist - p0p1_size;
p0 = &p1; p0 = &p1;
@ -544,7 +587,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
} }
fuzzified = loop.polygon; fuzzified = loop.polygon;
fuzzy_polyline(fuzzified.points, true, config); fuzzy_polyline(fuzzified.points, true, perimeter_generator.slice_z, config);
return &fuzzified; return &fuzzified;
} }
@ -589,16 +632,17 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// Fuzzy splitted polygon // Fuzzy splitted polygon
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
// The entire polygon is fuzzified // The entire polygon is fuzzified
fuzzy_polyline(fuzzified.points, true, r.first); fuzzy_polyline(fuzzified.points, true, perimeter_generator.slice_z, r.first);
} else { } else {
Points segment; Points segment;
segment.reserve(splitted.size()); segment.reserve(splitted.size());
fuzzified.points.clear(); fuzzified.points.clear();
const auto fuzzy_current_segment = [&segment, &fuzzified, &r]() { const auto slice_z = perimeter_generator.slice_z;
const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() {
fuzzified.points.push_back(segment.front()); fuzzified.points.push_back(segment.front());
const auto back = segment.back(); const auto back = segment.back();
fuzzy_polyline(segment, false, r.first); fuzzy_polyline(segment, false, slice_z, r.first);
fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end()); fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end());
fuzzified.points.push_back(back); fuzzified.points.push_back(back);
segment.clear(); segment.clear();
@ -970,6 +1014,8 @@ static void smooth_overhang_level(ExtrusionPaths &paths)
static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& perimeter_generator, std::vector<PerimeterGeneratorArachneExtrusion>& pg_extrusions, static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& perimeter_generator, std::vector<PerimeterGeneratorArachneExtrusion>& pg_extrusions,
bool &steep_overhang_contour, bool &steep_overhang_hole) bool &steep_overhang_contour, bool &steep_overhang_hole)
{ {
const auto slice_z = perimeter_generator.slice_z;
// Detect steep overhangs // Detect steep overhangs
bool overhangs_reverse = perimeter_generator.config->overhang_reverse && bool overhangs_reverse = perimeter_generator.config->overhang_reverse &&
perimeter_generator.layer_id % 2 == 1; // Only calculate overhang degree on even (from GUI POV) layers perimeter_generator.layer_id % 2 == 1; // Only calculate overhang degree on even (from GUI POV) layers
@ -989,7 +1035,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
const auto& config = regions.begin()->first; const auto& config = regions.begin()->first;
const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour); const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
if (fuzzify) if (fuzzify)
fuzzy_extrusion_line(extrusion->junctions, config); fuzzy_extrusion_line(extrusion.junctions, slice_z, config);
} else { } else {
// Find all affective regions // Find all affective regions
std::vector<std::pair<const FuzzySkinConfig&, const ExPolygons&>> fuzzified_regions; std::vector<std::pair<const FuzzySkinConfig&, const ExPolygons&>> fuzzified_regions;
@ -1011,19 +1057,19 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
// Fuzzy splitted extrusion // Fuzzy splitted extrusion
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
// The entire polygon is fuzzified // The entire polygon is fuzzified
fuzzy_extrusion_line(extrusion->junctions, r.first); fuzzy_extrusion_line(extrusion.junctions, slice_z, r.first);
} else { } else {
const auto current_ext = extrusion->junctions; const auto current_ext = extrusion->junctions;
std::vector<Arachne::ExtrusionJunction> segment; std::vector<Arachne::ExtrusionJunction> segment;
segment.reserve(current_ext.size()); segment.reserve(current_ext.size());
extrusion->junctions.clear(); extrusion->junctions.clear();
const auto fuzzy_current_segment = [&segment, extrusion, &r]() { const auto fuzzy_current_segment = [&segment, &extrusion, &r, slice_z]() {
extrusion->junctions.push_back(segment.front()); extrusion.junctions.push_back(segment.front());
const auto back = segment.back(); const auto back = segment.back();
fuzzy_extrusion_line(segment, r.first); fuzzy_extrusion_line(segment, slice_z, r.first);
extrusion->junctions.insert(extrusion->junctions.end(), segment.begin(), segment.end()); extrusion.junctions.insert(extrusion.junctions.end(), segment.begin(), segment.end());
extrusion->junctions.push_back(back); extrusion.junctions.push_back(back);
segment.clear(); segment.clear();
}; };
@ -1858,7 +1904,11 @@ static void group_region_by_fuzzify(PerimeterGenerator& g)
region_config.fuzzy_skin, region_config.fuzzy_skin,
scaled<coord_t>(region_config.fuzzy_skin_thickness.value), scaled<coord_t>(region_config.fuzzy_skin_thickness.value),
scaled<coord_t>(region_config.fuzzy_skin_point_distance.value), scaled<coord_t>(region_config.fuzzy_skin_point_distance.value),
region_config.fuzzy_skin_first_layer region_config.fuzzy_skin_first_layer,
region_config.fuzzy_skin_noise_type,
region_config.fuzzy_skin_scale,
region_config.fuzzy_skin_octaves,
region_config.fuzzy_skin_persistence
}; };
auto& surfaces = regions[cfg]; auto& surfaces = regions[cfg];
for (const auto& surface : region->slices.surfaces) { for (const auto& surface : region->slices.surfaces) {

View file

@ -16,10 +16,21 @@ struct FuzzySkinConfig
coord_t thickness; coord_t thickness;
coord_t point_distance; coord_t point_distance;
bool fuzzy_first_layer; bool fuzzy_first_layer;
NoiseType noise_type;
double noise_scale;
int noise_octaves;
double noise_persistence;
bool operator==(const FuzzySkinConfig& r) const bool operator==(const FuzzySkinConfig& r) const
{ {
return type == r.type && thickness == r.thickness && point_distance == r.point_distance && fuzzy_first_layer == r.fuzzy_first_layer; return type == r.type
&& thickness == r.thickness
&& point_distance == r.point_distance
&& fuzzy_first_layer == r.fuzzy_first_layer
&& noise_type == r.noise_type
&& noise_scale == r.noise_scale
&& noise_octaves == r.noise_octaves
&& noise_persistence == r.noise_persistence;
} }
bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); } bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); }
@ -35,6 +46,10 @@ template<> struct hash<Slic3r::FuzzySkinConfig>
boost::hash_combine(seed, std::hash<coord_t>{}(c.thickness)); boost::hash_combine(seed, std::hash<coord_t>{}(c.thickness));
boost::hash_combine(seed, std::hash<coord_t>{}(c.point_distance)); boost::hash_combine(seed, std::hash<coord_t>{}(c.point_distance));
boost::hash_combine(seed, std::hash<bool>{}(c.fuzzy_first_layer)); boost::hash_combine(seed, std::hash<bool>{}(c.fuzzy_first_layer));
boost::hash_combine(seed, std::hash<Slic3r::NoiseType>{}(c.noise_type));
boost::hash_combine(seed, std::hash<double>{}(c.noise_scale));
boost::hash_combine(seed, std::hash<int>{}(c.noise_octaves));
boost::hash_combine(seed, std::hash<double>{}(c.noise_persistence));
return seed; return seed;
} }
}; };
@ -51,6 +66,7 @@ public:
const ExPolygons *lower_slices; const ExPolygons *lower_slices;
double layer_height; double layer_height;
int layer_id; int layer_id;
coordf_t slice_z;
Flow perimeter_flow; Flow perimeter_flow;
Flow ext_perimeter_flow; Flow ext_perimeter_flow;
Flow overhang_flow; Flow overhang_flow;
@ -83,6 +99,7 @@ public:
const SurfaceCollection* slices, const SurfaceCollection* slices,
const LayerRegionPtrs *compatible_regions, const LayerRegionPtrs *compatible_regions,
double layer_height, double layer_height,
coordf_t slice_z,
Flow flow, Flow flow,
const PrintRegionConfig* config, const PrintRegionConfig* config,
const PrintObjectConfig* object_config, const PrintObjectConfig* object_config,
@ -98,7 +115,7 @@ public:
//BBS //BBS
ExPolygons* fill_no_overlap) ExPolygons* fill_no_overlap)
: slices(slices), compatible_regions(compatible_regions), upper_slices(nullptr), lower_slices(nullptr), layer_height(layer_height), : slices(slices), compatible_regions(compatible_regions), upper_slices(nullptr), lower_slices(nullptr), layer_height(layer_height),
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow), slice_z(slice_z), layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow), overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config), config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_mode), m_spiral_vase(spiral_mode),

View file

@ -789,7 +789,7 @@ static std::vector<std::string> s_Preset_print_options {
"minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target", "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset", "ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset",
"max_travel_detour_distance", "max_travel_detour_distance",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",
"max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only", "max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only",
"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed",
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed", "top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed",

View file

@ -123,6 +123,15 @@ static t_config_enum_values s_keys_map_FuzzySkinType {
}; };
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FuzzySkinType) CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FuzzySkinType)
static t_config_enum_values s_keys_map_NoiseType {
{ "classic", int(NoiseType::Classic) },
{ "perlin", int(NoiseType::Perlin) },
{ "billow", int(NoiseType::Billow) },
{ "ridgedmulti", int(NoiseType::RidgedMulti) },
{ "voronoi", int(NoiseType::Voronoi) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType)
static t_config_enum_values s_keys_map_InfillPattern { static t_config_enum_values s_keys_map_InfillPattern {
{ "concentric", ipConcentric }, { "concentric", ipConcentric },
{ "zig-zag", ipRectilinear }, { "zig-zag", ipRectilinear },
@ -2632,6 +2641,57 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple; def->mode = comSimple;
def->set_default_value(new ConfigOptionBool(0)); def->set_default_value(new ConfigOptionBool(0));
def = this->add("fuzzy_skin_noise_type", coEnum);
def->label = L("Fuzzy skin noise type");
def->category = L("Others");
def->tooltip = L("Noise type to use for fuzzy skin generation.\n"
"Classic: Classic uniform random noise.\n"
"Perlin: Perlin noise, which gives a more consistent texture.\n"
"Billow: Similar to perlin noise, but clumpier.\n"
"Ridged Multifractal: Ridged noise with sharp, jagged features. Creates marble-like textures.\n"
"Voronoi: Divides the surface into voronoi cells, and displaces each one by a random amount. Creates a patchwork texture.");
def->enum_keys_map = &ConfigOptionEnum<NoiseType>::get_enum_values();
def->enum_values.push_back("classic");
def->enum_values.push_back("perlin");
def->enum_values.push_back("billow");
def->enum_values.push_back("ridgedmulti");
def->enum_values.push_back("voronoi");
def->enum_labels.push_back(L("Classic"));
def->enum_labels.push_back(L("Perlin"));
def->enum_labels.push_back(L("Billow"));
def->enum_labels.push_back(L("Ridged Multifractal"));
def->enum_labels.push_back(L("Voronoi"));
def->mode = comSimple;
def->set_default_value(new ConfigOptionEnum<NoiseType>(NoiseType::Classic));
def = this->add("fuzzy_skin_scale", coFloat);
def->label = L("Fuzzy skin feature size");
def->category = L("Others");
def->tooltip = L("The base size of the coherent noise features, in mm. Higher values will result in larger features.");
def->sidetext = L("mm");
def->min = 0.1;
def->max = 500;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(1.0));
def = this->add("fuzzy_skin_octaves", coInt);
def->label = L("Fuzzy Skin Noise Octaves");
def->category = L("Others");
def->tooltip = L("The number of octaves of coherent noise to use. Higher values increase the detail of the noise, but also increase computation time.");
def->min = 1;
def->max = 10;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(4));
def = this->add("fuzzy_skin_persistence", coFloat);
def->label = L("Fuzzy skin noise persistence");
def->category = L("Others");
def->tooltip = L("The decay rate for higher octaves of the coherent noise. Lower values will result in smoother noise.");
def->min = 0.01;
def->max = 1;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.5));
def = this->add("filter_out_gap_fill", coFloat); def = this->add("filter_out_gap_fill", coFloat);
def->label = L("Filter out tiny gaps"); def->label = L("Filter out tiny gaps");
def->category = L("Layers and Perimeters"); def->category = L("Layers and Perimeters");

View file

@ -41,6 +41,14 @@ enum class FuzzySkinType {
AllWalls, AllWalls,
}; };
enum class NoiseType {
Classic,
Perlin,
Billow,
RidgedMulti,
Voronoi,
};
enum PrintHostType { enum PrintHostType {
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htESP3D, htCrealityPrint, htObico, htFlashforge, htSimplyPrint htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htESP3D, htCrealityPrint, htObico, htFlashforge, htSimplyPrint
}; };
@ -402,6 +410,7 @@ static std::string get_bed_temp_1st_layer_key(const BedType type)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrinterTechnology) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrinterTechnology)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeFlavor) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeFlavor)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NoiseType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode)
@ -917,6 +926,10 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fuzzy_skin_thickness)) ((ConfigOptionFloat, fuzzy_skin_thickness))
((ConfigOptionFloat, fuzzy_skin_point_distance)) ((ConfigOptionFloat, fuzzy_skin_point_distance))
((ConfigOptionBool, fuzzy_skin_first_layer)) ((ConfigOptionBool, fuzzy_skin_first_layer))
((ConfigOptionEnum<NoiseType>, fuzzy_skin_noise_type))
((ConfigOptionFloat, fuzzy_skin_scale))
((ConfigOptionInt, fuzzy_skin_octaves))
((ConfigOptionFloat, fuzzy_skin_persistence))
((ConfigOptionFloat, gap_infill_speed)) ((ConfigOptionFloat, gap_infill_speed))
((ConfigOptionInt, sparse_infill_filament)) ((ConfigOptionInt, sparse_infill_filament))
((ConfigOptionFloatOrPercent, sparse_infill_line_width)) ((ConfigOptionFloatOrPercent, sparse_infill_line_width))

View file

@ -1117,6 +1117,10 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "fuzzy_skin_thickness" || opt_key == "fuzzy_skin_thickness"
|| opt_key == "fuzzy_skin_point_distance" || opt_key == "fuzzy_skin_point_distance"
|| opt_key == "fuzzy_skin_first_layer" || opt_key == "fuzzy_skin_first_layer"
|| opt_key == "fuzzy_skin_noise_type"
|| opt_key == "fuzzy_skin_scale"
|| opt_key == "fuzzy_skin_octaves"
|| opt_key == "fuzzy_skin_persistence"
|| opt_key == "detect_overhang_wall" || opt_key == "detect_overhang_wall"
|| opt_key == "overhang_reverse" || opt_key == "overhang_reverse"
|| opt_key == "overhang_reverse_internal_only" || opt_key == "overhang_reverse_internal_only"

View file

@ -616,7 +616,8 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
encoding_check(libslic3r_gui) encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto) find_package(libnoise REQUIRED)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
if (MSVC) if (MSVC)
target_link_libraries(libslic3r_gui Setupapi.lib) target_link_libraries(libslic3r_gui Setupapi.lib)

View file

@ -708,9 +708,14 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament")); toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament"));
bool has_fuzzy_skin = (config->opt_enum<FuzzySkinType>("fuzzy_skin") != FuzzySkinType::None); bool has_fuzzy_skin = (config->opt_enum<FuzzySkinType>("fuzzy_skin") != FuzzySkinType::None);
for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer"}) for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type"})
toggle_line(el, has_fuzzy_skin); toggle_line(el, has_fuzzy_skin);
NoiseType fuzzy_skin_noise_type = config->opt_enum<NoiseType>("fuzzy_skin_noise_type");
toggle_line("fuzzy_skin_scale", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic);
toggle_line("fuzzy_skin_octaves", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi);
toggle_line("fuzzy_skin_persistence", has_fuzzy_skin && (fuzzy_skin_noise_type == NoiseType::Perlin || fuzzy_skin_noise_type == NoiseType::Billow));
bool have_arachne = config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne; bool have_arachne = config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne;
for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"min_feature_size", "min_length_factor", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"}) "min_feature_size", "min_length_factor", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"})

View file

@ -2352,8 +2352,12 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v
optgroup->append_single_option_line("timelapse_type", "Timelapse"); optgroup->append_single_option_line("timelapse_type", "Timelapse");
optgroup->append_single_option_line("fuzzy_skin"); optgroup->append_single_option_line("fuzzy_skin");
optgroup->append_single_option_line("fuzzy_skin_noise_type");
optgroup->append_single_option_line("fuzzy_skin_point_distance"); optgroup->append_single_option_line("fuzzy_skin_point_distance");
optgroup->append_single_option_line("fuzzy_skin_thickness"); optgroup->append_single_option_line("fuzzy_skin_thickness");
optgroup->append_single_option_line("fuzzy_skin_scale");
optgroup->append_single_option_line("fuzzy_skin_octaves");
optgroup->append_single_option_line("fuzzy_skin_persistence");
optgroup->append_single_option_line("fuzzy_skin_first_layer"); optgroup->append_single_option_line("fuzzy_skin_first_layer");
optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); optgroup = page->new_optgroup(L("G-code output"), L"param_gcode");