Skip to content

Commit

Permalink
Implement new 'fuzzy skin' type: displacement mapping
Browse files Browse the repository at this point in the history
Add new fuzzy skin type: displacement map. This feature uses an 8-bit grayscale PNG to displace the object's surface based on pixel values.

The displacement map is applied by mapping the surface points of the 3D model to the corresponding points on the 2D displacement map.

The UV mapping in this implementation is simple: it treats the object's as a cube.
It determines which face of the cube the current line is on based on the direction of the bump (which is just perpendicular to the line).
The U coordinate is calculated based on the x, y coordinates of the point on the line relative to the bounding box and the determined face.
The V coordinate is based on the current layer's height.
This method works surpsingly well for many objects but may fail for more complex shapes like ramps.

This feature is based on work by the PrusaSlicer community member Poikilos, who initially implemented displacement and cube mapping.
  • Loading branch information
undingen committed Jan 26, 2025
1 parent 118e14d commit 897a6b5
Show file tree
Hide file tree
Showing 9 changed files with 285 additions and 27 deletions.
2 changes: 2 additions & 0 deletions src/libslic3r/LayerRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,12 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, const LayerRe
&slices,
&compatible_regions,
this->layer()->height,
this->layer()->slice_z,
this->flow(frPerimeter),
&region_config,
&this->layer()->object()->config(),
&print_config,
this->layer()->object(),
spiral_mode,

// output:
Expand Down
244 changes: 221 additions & 23 deletions src/libslic3r/PerimeterGenerator.cpp

Large diffs are not rendered by default.

23 changes: 20 additions & 3 deletions src/libslic3r/PerimeterGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ struct FuzzySkinConfig
coord_t thickness;
coord_t point_distance;
bool fuzzy_first_layer;
NoiseType noise_type;
std::string displacement_map_path;

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
&& displacement_map_path == r.displacement_map_path;
}

bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); }
Expand All @@ -35,6 +42,8 @@ template<> struct hash<Slic3r::FuzzySkinConfig>
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<bool>{}(c.fuzzy_first_layer));
boost::hash_combine(seed, std::hash<Slic3r::NoiseType>{}(c.noise_type));
boost::hash_combine(seed, std::hash<std::string>{}(c.displacement_map_path));
return seed;
}
};
Expand All @@ -51,13 +60,16 @@ class PerimeterGenerator {
const ExPolygons *lower_slices;
double layer_height;
int layer_id;
coordf_t slice_z;
Flow perimeter_flow;
Flow ext_perimeter_flow;
Flow overhang_flow;
Flow solid_infill_flow;
const PrintRegionConfig *config;
const PrintObjectConfig *object_config;
const PrintConfig *print_config;
const PrintObject *print_object;

// Outputs:
ExtrusionEntityCollection *loops;
ExtrusionEntityCollection *gap_fill;
Expand All @@ -77,16 +89,18 @@ class PerimeterGenerator {
bool has_fuzzy_skin = false;
bool has_fuzzy_hole = false;
std::unordered_map<FuzzySkinConfig, ExPolygons> regions_by_fuzzify;

PerimeterGenerator(
// Input:
const SurfaceCollection* slices,
const LayerRegionPtrs *compatible_regions,
double layer_height,
coordf_t slice_z,
Flow flow,
const PrintRegionConfig* config,
const PrintObjectConfig* object_config,
const PrintConfig* print_config,
const PrintObject* print_object,
const bool spiral_mode,
// Output:
// Loops with the external thin walls
Expand All @@ -98,9 +112,10 @@ class PerimeterGenerator {
//BBS
ExPolygons* fill_no_overlap)
: 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),
config(config), object_config(object_config), print_config(print_config),
print_object(print_object),
m_spiral_vase(spiral_mode),
m_scaled_resolution(scaled<double>(print_config->resolution.value > EPSILON ? print_config->resolution.value : EPSILON)),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), fill_no_overlap(fill_no_overlap),
Expand All @@ -119,6 +134,8 @@ class PerimeterGenerator {
double smaller_width_ext_mm3_per_mm() const { return m_ext_mm3_per_mm_smaller_width; }
Polygons lower_slices_polygons() const { return m_lower_slices_polygons; }

const PrintObject* object() const { return print_object; }

private:
std::vector<Polygons> generate_lower_polygons_series(float width);
void split_top_surfaces(const ExPolygons &orig_polygons, ExPolygons &top_fills, ExPolygons &non_top_polygons, ExPolygons &fill_clip) const;
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset",
"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_displacement_map",
"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",
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed",
Expand Down
27 changes: 27 additions & 0 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ static t_config_enum_values s_keys_map_FuzzySkinType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FuzzySkinType)

static t_config_enum_values s_keys_map_NoiseType {
{ "classic", int(NoiseType::Classic) },
{ "displacementmap",int(NoiseType::DisplacementMap) }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType)

static t_config_enum_values s_keys_map_InfillPattern {
{ "concentric", ipConcentric },
{ "zig-zag", ipRectilinear },
Expand Down Expand Up @@ -2632,6 +2638,27 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple;
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"
"Displacement Map: Deforms the perimeter with an image-based displacement map.");
def->enum_keys_map = &ConfigOptionEnum<NoiseType>::get_enum_values();
def->enum_values.push_back("classic");
def->enum_values.push_back("displacementmap");
def->enum_labels.push_back(L("Classic"));
def->enum_labels.push_back(L("Displacement Map"));
def->mode = comSimple;
def->set_default_value(new ConfigOptionEnum<NoiseType>(NoiseType::Classic));

def = this->add("fuzzy_skin_displacement_map", coString);
def->label = L("Fuzzy skin displacement map filepath");
def->tooltip = L("Specifies the path to an 8-bit grayscale PNG file used for displacement mapping.");
def->category = L("Others");
def->mode = comSimple;
def->set_default_value(new ConfigOptionString());

def = this->add("filter_out_gap_fill", coFloat);
def->label = L("Filter out tiny gaps");
def->category = L("Layers and Perimeters");
Expand Down
7 changes: 7 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ enum class FuzzySkinType {
AllWalls,
};

enum class NoiseType {
Classic,
DisplacementMap,
};

enum PrintHostType {
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htESP3D, htCrealityPrint, htObico, htFlashforge, htSimplyPrint
};
Expand Down Expand Up @@ -917,6 +922,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fuzzy_skin_thickness))
((ConfigOptionFloat, fuzzy_skin_point_distance))
((ConfigOptionBool, fuzzy_skin_first_layer))
((ConfigOptionEnum<NoiseType>, fuzzy_skin_noise_type))
((ConfigOptionString, fuzzy_skin_displacement_map))
((ConfigOptionFloat, gap_infill_speed))
((ConfigOptionInt, sparse_infill_filament))
((ConfigOptionFloatOrPercent, sparse_infill_line_width))
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,8 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "fuzzy_skin_thickness"
|| opt_key == "fuzzy_skin_point_distance"
|| opt_key == "fuzzy_skin_first_layer"
|| opt_key == "fuzzy_skin_noise_type"
|| opt_key == "fuzzy_skin_displacement_map"
|| opt_key == "detect_overhang_wall"
|| opt_key == "overhang_reverse"
|| opt_key == "overhang_reverse_internal_only"
Expand Down
3 changes: 3 additions & 0 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer"})
toggle_line(el, has_fuzzy_skin);

NoiseType fuzzy_skin_noise_type = config->opt_enum<NoiseType>("fuzzy_skin_noise_type");
toggle_line("fuzzy_skin_displacement", has_fuzzy_skin && fuzzy_skin_noise_type == NoiseType::DisplacementMap);

bool have_arachne = config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne;
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"})
Expand Down
2 changes: 2 additions & 0 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2352,6 +2352,8 @@ 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("fuzzy_skin");
optgroup->append_single_option_line("fuzzy_skin_noise_type");
optgroup->append_single_option_line("fuzzy_skin_displacement_map");
optgroup->append_single_option_line("fuzzy_skin_point_distance");
optgroup->append_single_option_line("fuzzy_skin_thickness");
optgroup->append_single_option_line("fuzzy_skin_first_layer");
Expand Down

0 comments on commit 897a6b5

Please sign in to comment.